Motr  M0
balloc.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2012-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_BALLOC
24 #include "lib/trace.h"
25 
26 #include <stdio.h> /* sprintf */
27 #include <stdlib.h>
28 #include <memory.h>
29 #include <sys/stat.h>
30 #include <sys/time.h>
31 
32 #include "dtm/dtm.h" /* m0_dtx */
33 #include "be/tx_bulk.h" /* m0_be_tx_bulk */
34 #include "be/op.h" /* m0_be_op_active */
35 #include "lib/misc.h" /* M0_SET0 */
36 #include "lib/errno.h"
37 #include "lib/arith.h" /* min_check, m0_is_po2 */
38 #include "lib/memory.h"
39 #include "lib/locality.h" /* m0_locality0_get */
40 #include "balloc.h"
41 #include "motr/magic.h"
42 
54 };
55 
57  uint32_t bac_criteria;
58  uint32_t bac_order2; /* order of 2 */
59  uint32_t bac_scanned; /* groups scanned */
60  uint32_t bac_found; /* count of found */
61  uint32_t bac_status; /* allocation status */
62  uint64_t bac_flags;
64  struct m0_be_tx *bac_tx;
66  struct m0_ext bac_orig; /*< original */
67  struct m0_ext bac_goal; /*< after normalization */
68  struct m0_ext bac_best; /*< best available */
69  struct m0_ext bac_final;/*< final results */
70 };
71 
72 static inline int btree_lookup_sync(struct m0_be_btree *tree,
73  const struct m0_buf *key,
74  struct m0_buf *val)
75 {
76  return M0_BE_OP_SYNC_RET(op, m0_be_btree_lookup(tree, &op, key, val),
77  bo_u.u_btree.t_rc);
78 }
79 
80 static inline int btree_insert_sync(struct m0_be_btree *tree,
81  struct m0_be_tx *tx,
82  const struct m0_buf *key,
83  const struct m0_buf *val)
84 {
85  return M0_BE_OP_SYNC_RET(op,
86  m0_be_btree_insert(tree, tx, &op, key, val),
87  bo_u.u_btree.t_rc);
88 }
89 
90 static inline int btree_update_sync(struct m0_be_btree *tree,
91  struct m0_be_tx *tx,
92  const struct m0_buf *key,
93  const struct m0_buf *val)
94 {
95  return M0_BE_OP_SYNC_RET(op,
96  m0_be_btree_update(tree, tx, &op, key, val),
97  bo_u.u_btree.t_rc);
98 }
99 
100 static inline int btree_delete_sync(struct m0_be_btree *tree,
101  struct m0_be_tx *tx,
102  const struct m0_buf *key)
103 {
104  return M0_BE_OP_SYNC_RET(op, m0_be_btree_delete(tree, tx, &op, key),
105  bo_u.u_btree.t_rc);
106 }
107 
108 /* Conducts the basic sanity check on freeblocks and fragments. */
109 static int is_group_good_enough(struct balloc_allocation_context *bac,
110  m0_bcount_t maxchunk, m0_bcount_t free,
111  m0_bcount_t fragments);
113  enum m0_balloc_allocation_flag alloc_flag);
114 static int allocate_blocks(int cr, struct balloc_allocation_context *bac,
115  struct m0_balloc_group_info *grp, m0_bcount_t len,
116  enum m0_balloc_allocation_flag alloc_type);
118 {
119  return grp->bgi_spare.bzp_freeblocks;
120 }
122 {
123  return grp->bgi_normal.bzp_freeblocks;
124 }
126 {
127  return grp->bgi_normal.bzp_maxchunk;
128 }
130 {
131  return grp->bgi_spare.bzp_maxchunk;
132 }
134 {
135  return grp->bgi_normal.bzp_fragments;
136 }
138 {
139  return grp->bgi_spare.bzp_fragments;
140 }
142 {
143  return &grp->bgi_normal.bzp_extents;
144 }
146 {
147  return &grp->bgi_spare.bzp_extents;
148 }
149 static void balloc_zone_init(struct m0_balloc_zone_param *zone, uint64_t type,
151  m0_bcount_t freeblocks, m0_bcount_t fragments,
152  m0_bcount_t maxchunk);
153 static uint64_t ext_range_locate(struct m0_ext *ip_ext,
154  struct m0_balloc_group_info *grp);
155 static bool is_spare(uint64_t alloc_flags);
156 static bool is_normal(uint64_t alloc_flags);
157 static bool is_any(uint64_t alloc_flag);
158 
159 
160 static void balloc_debug_dump_extent(const char *tag, struct m0_ext *ex)
161 {
162 if (ENABLE_BALLOC_DUMP) {
163 
164  if (ex == NULL)
165  return;
166 
167  M0_LOG(M0_DEBUG, "ex@%p:%s "EXT_F, ex, (char*) tag, EXT_P(ex));
168 }
169 }
170 
171 M0_INTERNAL void m0_balloc_debug_dump_group(const char *tag,
172  struct m0_balloc_group_info *grp)
173 {
174 if (ENABLE_BALLOC_DUMP) {
175  if (grp == NULL)
176  return;
177 
178  M0_LOG(M0_DEBUG, "group_desc@%p:%s groupno=%08llx "
179  "normal: free=%08llx maxchunk=0x%08llx frags=0x%08llx"
180  " spare: free=%08llx maxchunk=0x%08llx frags=0x%08llx",
181  grp, (char*) tag,
182  (unsigned long long) grp->bgi_groupno,
183  (unsigned long long) grp->bgi_normal.bzp_freeblocks,
184  (unsigned long long) grp->bgi_normal.bzp_maxchunk,
185  (unsigned long long) grp->bgi_normal.bzp_fragments,
186  (unsigned long long) grp->bgi_spare.bzp_freeblocks,
187  (unsigned long long) grp->bgi_spare.bzp_maxchunk,
188  (unsigned long long) grp->bgi_spare.bzp_fragments);
189 }
190 }
191 
192 M0_INTERNAL void m0_balloc_debug_dump_group_extent(const char *tag,
193  struct m0_balloc_group_info *grp)
194 {
195 if (ENABLE_BALLOC_DUMP) {
196  struct m0_lext *ex;
197 
198  if (grp == NULL || grp->bgi_extents == NULL)
199  return;
200 
201  M0_LOG(M0_DEBUG, "free extents@%p:%s for grp=%04llx:",
202  grp, (char*) tag, (unsigned long long) grp->bgi_groupno);
203  m0_list_for_each_entry(&grp->bgi_normal.bzp_extents, ex,
204  struct m0_lext, le_link)
205  M0_LOG(M0_DEBUG, "normal: "EXT_F, EXT_P(&ex->le_ext));
206  m0_list_for_each_entry(&grp->bgi_spare.bzp_extents, ex,
207  struct m0_lext, le_link)
208  M0_LOG(M0_DEBUG, "spare: "EXT_F, EXT_P(&ex->le_ext));
209 }
210 }
211 
212 M0_INTERNAL void m0_balloc_debug_dump_sb(const char *tag,
213  struct m0_balloc_super_block *sb)
214 {
215 if (ENABLE_BALLOC_DUMP) {
216  if (sb == NULL)
217  return;
218 
219  M0_LOG(M0_DEBUG, "dumping sb@%p:%s\n"
220  "|-----magic=%llx state=%llu version=%llu\n"
221  "|-----total=%llu free=%llu bs=%llu(bits=%lu)",
222  sb, (char*) tag,
223  (unsigned long long) sb->bsb_magic,
224  (unsigned long long) sb->bsb_state,
225  (unsigned long long) sb->bsb_version,
226  (unsigned long long) sb->bsb_totalsize,
227  (unsigned long long) sb->bsb_freeblocks,
228  (unsigned long long) sb->bsb_blocksize,
229  (unsigned long ) sb->bsb_bsbits);
230 
231  M0_LOG(M0_DEBUG, "|-----gs=%llu(bits=%lu) gc=%llu "
232  " prealloc=%llu\n"
233  "|-----time format=%llu\n"
234  "|-----write=%llu\n"
235  "|-----mnt =%llu\n"
236  "|-----last =%llu",
237  (unsigned long long) sb->bsb_groupsize,
238  (unsigned long ) sb->bsb_gsbits,
239  (unsigned long long) sb->bsb_groupcount,
240  (unsigned long long) sb->bsb_prealloc_count,
241  (unsigned long long) sb->bsb_format_time,
242  (unsigned long long) sb->bsb_write_time,
243  (unsigned long long) sb->bsb_mnt_time,
244  (unsigned long long) sb->bsb_last_check_time);
245 
246  M0_LOG(M0_DEBUG, "|-----mount=%llu max_mnt=%llu stripe_size=%llu",
247  (unsigned long long) sb->bsb_mnt_count,
248  (unsigned long long) sb->bsb_max_mnt_count,
249  (unsigned long long) sb->bsb_stripe_size
250  );
251 }
252 }
253 
254 static inline m0_bindex_t
255 balloc_bn2gn(m0_bindex_t blockno, struct m0_balloc *cb)
256 {
257  return blockno >> cb->cb_sb.bsb_gsbits;
258 }
259 
260 M0_INTERNAL struct m0_balloc_group_info *m0_balloc_gn2info(struct m0_balloc *cb,
261  m0_bindex_t groupno)
262 {
263  return cb->cb_group_info == NULL ? NULL : &cb->cb_group_info[groupno];
264 }
265 
267 {
268  return &grp->bgi_mutex.bm_u.mutex;
269 }
270 
271 static void lext_del(struct m0_lext *le)
272 {
273  m0_list_del(&le->le_link);
274  if (le->le_is_alloc)
275  m0_free(le);
276 }
277 
278 static struct m0_lext* lext_create(struct m0_ext *ex)
279 {
280  struct m0_lext *le;
281 
282  le = m0_alloc(sizeof(*le));
283  if (le == NULL)
284  return NULL;
285 
286  le->le_is_alloc = true;
287  le->le_ext = *ex;
288 
289  return le;
290 }
291 
293  enum m0_balloc_allocation_flag zone_type)
294 {
295  struct m0_list_link *l;
296  struct m0_lext *le;
297  struct m0_balloc_zone_param *zp;
298  m0_bcount_t frags = 0;
299 
300  zp = is_spare(zone_type) ? &grp->bgi_spare : &grp->bgi_normal;
301  while ((l = m0_list_first(&zp->bzp_extents)) != NULL) {
302  le = m0_list_entry(l, struct m0_lext, le_link);
303  lext_del(le);
304  ++frags;
305  }
306  M0_LOG(M0_DEBUG, "zone_type = %d, grp=%p grpno=%" PRIu64 " list_frags=%d"
307  "bzp_frags=%d", (int)zone_type, grp, grp->bgi_groupno,
308  (int)frags, (int)zp->bzp_fragments);
309  M0_ASSERT(ergo(frags > 0, frags == zp->bzp_fragments));
310 }
311 
313 {
314 
315 
317 
320  m0_free0(&grp->bgi_extents);
321  return 0;
322 }
323 
325 {
327 }
328 
330 {
331  return m0_mutex_trylock(bgi_mutex(grp));
332 }
333 
335 {
337 }
338 
339 #define MAX_ALLOCATION_CHUNK 2048ULL
340 
341 M0_INTERNAL void m0_balloc_group_desc_init(struct m0_balloc_group_desc *desc)
342 {
344  .ot_version = M0_BALLOC_GROUP_DESC_FORMAT_VERSION,
345  .ot_type = M0_FORMAT_TYPE_BALLOC_GROUP_DESC,
346  .ot_footer_offset = offsetof(struct m0_balloc_group_desc, bgd_footer)
347  });
349 }
350 
351 static void balloc_format_init(struct m0_balloc *cb)
352 {
354  .ot_version = M0_BALLOC_FORMAT_VERSION,
355  .ot_type = M0_FORMAT_TYPE_BALLOC,
356  .ot_footer_offset = offsetof(struct m0_balloc, cb_footer)
357  });
359 }
360 
362  struct m0_balloc *cb)
363 {
364  struct m0_balloc_group_desc gd = {};
365  struct m0_balloc_super_block *sb = &cb->cb_sb;
366  struct m0_buf key = M0_BUF_INIT_PTR(&gi->bgi_groupno);
367  struct m0_buf val = M0_BUF_INIT_PTR(&gd);
368  m0_bcount_t normal_zone_size;
369  m0_bcount_t spare_zone_size;
370  int rc;
371 
373  if (rc == 0) {
375  gi->bgi_extents = NULL;
376 
377  spare_zone_size =
379  normal_zone_size = cb->cb_sb.bsb_groupsize - spare_zone_size;
380 
382  gd.bgd_groupno << sb->bsb_gsbits,
383  normal_zone_size,
385  gd.bgd_maxchunk);
386 #ifdef __SPARE__SPACE__
388  gd.bgd_sparestart, spare_zone_size,
389  gd.bgd_spare_freeblocks, gd.bgd_spare_frags,
390  gd.bgd_spare_maxchunk);
391 #else
393  ((gd.bgd_groupno) << sb->bsb_gsbits) +
394  normal_zone_size,
395  spare_zone_size, 0, 0, 0);
396 #endif
398  }
399  return rc;
400 }
401 
403 {
407 }
408 
409 static int balloc_group_info_load(struct m0_balloc *bal)
410 {
411  struct m0_balloc_group_info *gi;
412  m0_bcount_t i;
413  int rc = 0;
414 
415  M0_LOG(M0_INFO, "Loading group info...");
416  for (i = 0; i < bal->cb_sb.bsb_groupcount; ++i) {
417  gi = &bal->cb_group_info[i];
418  gi->bgi_groupno = i;
419  rc = balloc_group_info_init(gi, bal);
420  if (rc != 0)
421  break;
422 
423  /* TODO verify the super_block info based on the group info */
424  }
425  while (rc != 0 && i > 0) {
427  }
428  return M0_RC(rc);
429 }
430 
434 static void balloc_fini_internal(struct m0_balloc *bal)
435 {
436  struct m0_balloc_group_info *gi;
437  int i;
438 
439  M0_ENTRY();
440 
441  if (bal->cb_group_info != NULL) {
442  for (i = 0 ; i < bal->cb_sb.bsb_groupcount; i++) {
443  gi = &bal->cb_group_info[i];
448  }
449  m0_free0(&bal->cb_group_info);
450  }
451 
454 
455  M0_LEAVE();
456 }
457 
458 static m0_bcount_t ge_tree_kv_size(const void *kv)
459 {
460  return sizeof(m0_bindex_t);
461 }
462 
463 static int ge_tree_cmp(const void *k0, const void *k1)
464 {
465  const m0_bindex_t *bn0 = (m0_bindex_t*)k0;
466  const m0_bindex_t *bn1 = (m0_bindex_t*)k1;
467 
468  return M0_3WAY(*bn0, *bn1);
469 }
470 
471 static const struct m0_be_btree_kv_ops ge_btree_ops = {
473  .ko_ksize = ge_tree_kv_size,
474  .ko_vsize = ge_tree_kv_size,
475  .ko_compare = ge_tree_cmp
476 };
477 
478 static m0_bcount_t gd_tree_key_size(const void *k)
479 {
480  return sizeof ((struct m0_balloc_group_desc*)0)->bgd_groupno;
481 }
482 
483 static m0_bcount_t gd_tree_val_size(const void *v)
484 {
485  return sizeof(struct m0_balloc_group_desc);
486 }
487 
488 static int gd_tree_cmp(const void *k0, const void *k1)
489 {
490  return memcmp(k0, k1, gd_tree_key_size(NULL));
491 }
492 
493 static const struct m0_be_btree_kv_ops gd_btree_ops = {
495  .ko_ksize = gd_tree_key_size,
496  .ko_vsize = gd_tree_val_size,
497  .ko_compare = gd_tree_cmp
498 };
499 
500 static void balloc_sb_sync(struct m0_balloc *cb, struct m0_be_tx *tx)
501 {
502  struct m0_balloc_super_block *sb = &cb->cb_sb;
503  struct timeval now;
504 
505  M0_ENTRY();
506 
509 
510  gettimeofday(&now, NULL);
511  sb->bsb_write_time = ((uint64_t)now.tv_sec) << 32 | now.tv_usec;
512 
513  sb->bsb_magic = M0_BALLOC_SB_MAGIC;
514 
516 
518  M0_BE_TX_CAPTURE_PTR(cb->cb_be_seg, tx, cb);
519 
520  M0_LEAVE();
521 }
522 
523 static int sb_update(struct m0_balloc *bal, struct m0_sm_group *grp)
524 {
525  struct m0_be_tx tx = {};
526  struct m0_be_tx_credit cred;
527  int rc;
528 
530 
532 
533  m0_be_tx_init(&tx, 0, bal->cb_be_seg->bs_domain,
534  grp, NULL, NULL, NULL, NULL);
535  cred = M0_BE_TX_CREDIT_PTR(bal);
536  m0_be_tx_prep(&tx, &cred);
537  rc = m0_be_tx_open_sync(&tx);
538  if (rc == 0) {
539  balloc_sb_sync(bal, &tx);
540  m0_be_tx_close_sync(&tx);
541  /* XXX error handling is missing here */
542  }
543  m0_be_tx_fini(&tx);
544 
546 
547  return M0_RC(rc);
548 }
549 
550 static int balloc_sb_write(struct m0_balloc *bal,
551  struct m0_balloc_format_req *req,
552  struct m0_sm_group *grp)
553 {
554  int rc;
555  struct timeval now;
556  m0_bcount_t number_of_groups;
557  struct m0_balloc_super_block *sb = &bal->cb_sb;
558 
559  M0_ENTRY();
560 
561  M0_PRE(m0_is_po2(req->bfr_blocksize));
562  M0_PRE(m0_is_po2(req->bfr_groupsize));
563 
564  number_of_groups = req->bfr_totalsize / req->bfr_blocksize /
565  req->bfr_groupsize;
566  if (number_of_groups < 1)
567  number_of_groups = 1;
568 
569  M0_LOG(M0_DEBUG, "total=%llu bs=%llu groupsize=%llu groups=%llu "
570  "unused=%llu",
571  (unsigned long long)req->bfr_totalsize,
572  (unsigned long long)req->bfr_blocksize,
573  (unsigned long long)req->bfr_groupsize,
574  (unsigned long long)number_of_groups,
575  (unsigned long long)(req->bfr_totalsize - number_of_groups *
576  req->bfr_groupsize * req->bfr_blocksize));
577 
578  gettimeofday(&now, NULL);
579  /* TODO verification of these parameters */
580  sb->bsb_magic = M0_BALLOC_SB_MAGIC;
581  sb->bsb_state = 0;
582  sb->bsb_version = M0_BALLOC_SB_VERSION;
583 
584  /*
585  Total size is rounded by number of groups so that the rest
586  of space (little piece) at the end of device is not accounted
587  as used space.
588  */
589  sb->bsb_totalsize = number_of_groups * req->bfr_groupsize *
590  req->bfr_blocksize;
591  /* should be power of 2*/
592  sb->bsb_blocksize = req->bfr_blocksize;
593  /* should be power of 2*/
594  sb->bsb_groupsize = req->bfr_groupsize;
595  sb->bsb_bsbits = ffs(req->bfr_blocksize) - 1;
596  sb->bsb_gsbits = ffs(req->bfr_groupsize) - 1;
597  sb->bsb_groupcount = number_of_groups;
598 #ifdef __SPARE_SPACE__
599  /* should be power of 2*/
600  sb->bsb_sparesize = req->bfr_spare_reserved_blocks;
601  sb->bsb_freespare = number_of_groups *
602  req->bfr_spare_reserved_blocks;
603  sb->bsb_freeblocks = (number_of_groups << sb->bsb_gsbits) -
604  sb->bsb_freespare;
605 #else
606  sb->bsb_freeblocks = (number_of_groups << sb->bsb_gsbits);
607 #endif
608  sb->bsb_prealloc_count = 16;
609  sb->bsb_format_time = ((uint64_t)now.tv_sec) << 32 | now.tv_usec;
610  sb->bsb_write_time = sb->bsb_format_time;
611  sb->bsb_mnt_time = sb->bsb_format_time;
612  sb->bsb_last_check_time = sb->bsb_format_time;
613  sb->bsb_mnt_count = 0;
614  sb->bsb_max_mnt_count = 1024;
615  sb->bsb_stripe_size = 0;
616 
617  rc = sb_update(bal, grp);
618  if (rc != 0)
619  M0_LOG(M0_ERROR, "super_block update failed: rc=%d", rc);
620 
621  return M0_RC(rc);
622 }
623 
627 };
628 
633  int bgs_rc;
635 };
636 
637 static void
639  struct m0_be_tx_bulk *tb,
640  struct balloc_groups_write_cfg *bgs,
641  struct m0_be_tx_credit *credit)
642 {
644  M0_MEMBER_SIZE(struct m0_ext, e_start),
645  M0_MEMBER_SIZE(struct m0_ext, e_end), credit);
648  sizeof(struct m0_balloc_group_desc), credit);
649 }
650 
651 static void balloc_group_work_put(struct m0_balloc *bal,
652  struct m0_be_tx_bulk *tb,
653  struct balloc_groups_write_cfg *bgs)
654 {
655  struct balloc_group_write_cfg *bgc;
656  struct m0_be_tx_credit credit;
657  m0_bcount_t i;
658  bool put_successful;
659  int rc;
660 
661  for (i = 0; i < bgs->bgs_max; ++i) {
662  m0_mutex_lock(&bgs->bgs_lock);
663  rc = bgs->bgs_rc;
664  m0_mutex_unlock(&bgs->bgs_lock);
665  if (rc != 0)
666  break;
667  bgc = &bgs->bgs_bgc[i];
668  *bgc = (struct balloc_group_write_cfg){
669  .bgc_bal = bgs->bgs_bal,
670  .bgc_i = i,
671  };
672  credit = M0_BE_TX_CREDIT(0, 0);
673  balloc_group_write_credit(bal, tb, bgs, &credit);
674  M0_BE_OP_SYNC(op, put_successful =
675  m0_be_tx_bulk_put(tb, &op, &credit, 0, 0, bgc));
676  if (!put_successful)
677  break;
678  }
679  m0_be_tx_bulk_end(tb);
680 }
681 
682 static void balloc_group_write_do(struct m0_be_tx_bulk *tb,
683  struct m0_be_tx *tx,
684  struct m0_be_op *op,
685  void *datum,
686  void *user,
687  uint64_t worker_index,
688  uint64_t partition)
689 {
690  struct balloc_groups_write_cfg *bgs = datum;
691  struct balloc_group_write_cfg *bgc = user;
692  struct m0_balloc *bal = bgc->bgc_bal;
693  struct m0_balloc_group_desc gd;
694  struct m0_balloc_super_block *sb = &bal->cb_sb;
695  struct m0_ext ext;
696  struct m0_buf key;
697  struct m0_buf val;
698  m0_bcount_t i = bgc->bgc_i;
699  m0_bcount_t spare_size;
700  int rc;
701 
703 
704  M0_LOG(M0_DEBUG, "creating group_extents for group %llu",
705  (unsigned long long)i);
706  spare_size = m0_stob_ad_spares_calc(sb->bsb_groupsize);
707  /* Insert non-spare extents. */
708  ext.e_start = i << sb->bsb_gsbits;
709  ext.e_end = ext.e_start + sb->bsb_groupsize - spare_size;
710  m0_ext_init(&ext);
711  balloc_debug_dump_extent("create...", &ext);
712 
713  key = (struct m0_buf)M0_BUF_INIT_PTR(&ext.e_end);
714  val = (struct m0_buf)M0_BUF_INIT_PTR(&ext.e_start);
716  if (rc != 0) {
717  M0_LOG(M0_ERROR, "insert extent failed: group=%llu "
718  "rc=%d", (unsigned long long)i, rc);
719  goto out;
720  }
721 #ifdef __SPARE_SPACE__
722  /* Insert extents reserved for spare. */
723  ext.e_start = (i << sb->bsb_gsbits) + sb->bsb_groupsize -
724  spare_size;
725  ext.e_end = ext.e_start + spare_size;
726  key = (struct m0_buf)M0_BUF_INIT_PTR(&ext.e_end);
727  val = (struct m0_buf)M0_BUF_INIT_PTR(&ext.e_start);
729  if (rc != 0) {
730  M0_LOG(M0_ERROR, "insert extent failed for spares: group=%llu "
731  "rc=%d", (unsigned long long)i, rc);
732  goto out;
733  }
734 #endif
735  M0_LOG(M0_DEBUG, "creating group_desc for group %llu",
736  (unsigned long long)i);
737  gd.bgd_groupno = i;
738 #ifdef __SPARE_SPACE__
739  gd.bgd_spare_freeblocks = sb->bsb_sparesize;
740  gd.bgd_sparestart = (i << sb->bsb_gsbits) + sb->bsb_groupsize -
741  sb->bsb_sparesize;
742  gd.bgd_spare_frags = 1;
743  gd.bgd_spare_maxchunk = sb->bsb_sparesize;
744 #endif
745  gd.bgd_freeblocks = sb->bsb_groupsize - spare_size;
746  gd.bgd_maxchunk = sb->bsb_groupsize - spare_size;
747  gd.bgd_fragments = 1;
749  key = (struct m0_buf)M0_BUF_INIT_PTR(&gd.bgd_groupno);
750  val = (struct m0_buf)M0_BUF_INIT_PTR(&gd);
751 
752  rc = btree_insert_sync(&bal->cb_db_group_desc, tx, &key, &val);
753  if (rc != 0) {
754  M0_LOG(M0_ERROR, "insert gd failed: group=%llu rc=%d",
755  (unsigned long long)i, rc);
756  }
757 out:
758  if (rc != 0) {
759  m0_mutex_lock(&bgs->bgs_lock);
760  bgs->bgs_rc = rc;
761  m0_mutex_unlock(&bgs->bgs_lock);
762  }
763  m0_be_op_done(op);
764 }
765 
766 static void balloc_group_write_done(struct m0_be_tx_bulk *tb,
767  void *datum,
768  void *user,
769  uint64_t worker_index,
770  uint64_t partition)
771 {
772  M0_LOG(M0_DEBUG, "tb=%p datum=%p user=%p worker_index=%" PRIu64 " "
773  "partition=%"PRIu64, tb, datum, user, worker_index, partition);
774 }
775 
776 static void balloc_zone_init(struct m0_balloc_zone_param *zone, uint64_t type,
778  m0_bcount_t freeblocks, m0_bcount_t fragments,
779  m0_bcount_t maxchunk)
780 {
781  zone->bzp_type = type;
782  zone->bzp_range.e_start = start;
783  zone->bzp_range.e_end = start + size;
784  zone->bzp_freeblocks = freeblocks;
785  zone->bzp_fragments = fragments;
786  zone->bzp_maxchunk = maxchunk;
787  m0_list_init(&zone->bzp_extents);
788 }
789 
790 static int balloc_groups_write(struct m0_balloc *bal)
791 {
792  struct balloc_groups_write_cfg bgs;
793  struct m0_balloc_super_block *sb = &bal->cb_sb;
794  struct m0_be_tx_bulk_cfg tb_cfg;
795  struct m0_be_tx_bulk tb = {};
796  int rc;
797 
798  M0_ENTRY();
799 
800  M0_ALLOC_ARR(bal->cb_group_info, sb->bsb_groupcount);
801  if (bal->cb_group_info == NULL) {
802  return M0_ERR(-ENOMEM);
803  }
804  bgs = (struct balloc_groups_write_cfg) {
805  .bgs_bal = bal,
806  .bgs_max = sb->bsb_groupcount,
807  .bgs_rc = 0,
808  };
809  M0_ALLOC_ARR(bgs.bgs_bgc, bgs.bgs_max);
810  if (bgs.bgs_bgc == NULL) {
811  m0_free0(&bal->cb_group_info);
812  return M0_ERR(-ENOMEM);
813  }
814  m0_mutex_init(&bgs.bgs_lock);
815  tb_cfg = (struct m0_be_tx_bulk_cfg){
816  .tbc_q_cfg = {
817  .bqc_q_size_max = 0x100,
818  .bqc_producers_nr_max = 1,
819  },
820  .tbc_workers_nr = 0x40,
821  .tbc_partitions_nr = 1,
822  .tbc_work_items_per_tx_max = 1,
823  .tbc_dom = bal->cb_be_seg->bs_domain,
824  .tbc_datum = &bgs,
825  .tbc_do = &balloc_group_write_do,
826  .tbc_done = &balloc_group_write_done,
827  };
828 
829  rc = m0_be_tx_bulk_init(&tb, &tb_cfg);
830  if (rc == 0) {
831  M0_BE_OP_SYNC(op, ({
832  m0_be_tx_bulk_run(&tb, &op);
833  balloc_group_work_put(bal, &tb, &bgs);
834  }));
835  rc = m0_be_tx_bulk_status(&tb);
836  m0_be_tx_bulk_fini(&tb);
837  }
838  m0_mutex_fini(&bgs.bgs_lock);
839  m0_free(bgs.bgs_bgc);
840  if (bgs.bgs_rc != 0)
841  rc = bgs.bgs_rc;
842 
843  rc = rc ?: balloc_group_info_load(bal);
844  if (rc != 0) {
845  /* balloc_fini_internal() checks whether this pointer is NULL */
846  m0_free0(&bal->cb_group_info);
847  }
848  return M0_RC(rc);
849 }
850 
864 static int balloc_format(struct m0_balloc *bal,
865  struct m0_balloc_format_req *req,
866  struct m0_sm_group *grp)
867 {
868  int rc;
869 
870  M0_ENTRY();
871 
872  rc = balloc_sb_write(bal, req, grp);
873  if (rc != 0)
874  return M0_RC(rc);
875 
888  rc = balloc_groups_write(bal);
890 
891  return M0_RC(rc);
892 }
893 
894 static void balloc_gi_sync_credit(const struct m0_balloc *cb,
895  struct m0_be_tx_credit *accum)
896 {
898  sizeof(struct m0_balloc_group_desc), accum);
899 }
900 
901 static int balloc_gi_sync(struct m0_balloc *cb,
902  struct m0_be_tx *tx,
903  struct m0_balloc_group_info *gi)
904 {
905  struct m0_balloc_group_desc gd = {};
906  struct m0_buf key;
907  struct m0_buf val;
908  int rc;
909 
910  M0_ENTRY();
911 
913 
914  gd.bgd_groupno = gi->bgi_groupno;
918 #ifdef __SPARE_SPACE__
919  gd.bgd_spare_freeblocks = group_spare_freeblocks_get(gi);
920  gd.bgd_spare_frags = group_spare_fragments_get(gi);
921  gd.bgd_spare_maxchunk = group_spare_maxchunk_get(gi);
922  gd.bgd_sparestart = gi->bgi_spare.bzp_range.e_start;
923 #endif
925 
926  key = (struct m0_buf)M0_BUF_INIT_PTR(&gd.bgd_groupno);
927  val = (struct m0_buf)M0_BUF_INIT_PTR(&gd);
928  rc = btree_update_sync(&cb->cb_db_group_desc, tx, &key, &val);
929 
931 
932  return M0_RC(rc);
933 }
934 
935 static int sb_mount(struct m0_balloc *bal, struct m0_sm_group *grp)
936 {
937  struct timeval now;
938 
939  gettimeofday(&now, NULL);
940  bal->cb_sb.bsb_mnt_time = ((uint64_t)now.tv_sec) << 32 | now.tv_usec;
941  ++bal->cb_sb.bsb_mnt_count;
942 
943  return sb_update(bal, grp);
944 }
945 
946 /*
947  * start transaction for init() and format() respectively.
948  * One transaction maybe fail to include all update. Multiple transaction
949  * is used here.
950  * The same reason for format().
951  */
952 static int balloc_init_internal(struct m0_balloc *bal,
953  struct m0_be_seg *seg,
954  struct m0_sm_group *grp,
955  uint32_t bshift,
956  m0_bcount_t container_size,
957  m0_bcount_t blocks_per_group,
958  m0_bcount_t spare_blocks_per_group)
959 {
960  int rc;
961 
962  M0_ENTRY();
963 
964  bal->cb_be_seg = seg;
965  bal->cb_group_info = NULL;
967 
970 
971  if (bal->cb_sb.bsb_magic != M0_BALLOC_SB_MAGIC) {
972  struct m0_balloc_format_req req = { 0 };
973 
974  /* let's format this container */
975  req.bfr_totalsize = container_size;
976  req.bfr_blocksize = 1 << bshift;
977  req.bfr_groupsize = blocks_per_group;
978  req.bfr_spare_reserved_blocks = spare_blocks_per_group;
979 
980  rc = balloc_format(bal, &req, grp);
981  if (rc != 0)
983  return M0_RC(rc);
984  }
985 
986  if (bal->cb_sb.bsb_blocksize != 1 << bshift) {
987  rc = -EINVAL;
988  goto out;
989  }
990 
991  M0_LOG(M0_INFO, "Group Count = %"PRIu64, bal->cb_sb.bsb_groupcount);
992 
994  rc = bal->cb_group_info == NULL ? M0_ERR(-ENOMEM) : 0;
995  if (rc == 0) {
996  rc = balloc_group_info_load(bal);
997  if (rc != 0)
998  m0_free0(&bal->cb_group_info);
999  }
1000  rc = rc ?: sb_mount(bal, grp);
1001 out:
1002  if (rc != 0)
1003  balloc_fini_internal(bal);
1004  return M0_RC(rc);
1005 }
1006 
1008  struct m0_balloc *motr,
1009  struct m0_be_tx *tx,
1010  struct m0_balloc_allocate_req *req)
1011 {
1012  M0_ENTRY();
1013 
1014  M0_SET0(&req->bar_result);
1015  m0_ext_init(&req->bar_result);
1016 
1017  bac->bac_ctxt = motr;
1018  bac->bac_tx = tx;
1019  bac->bac_req = req;
1020  bac->bac_order2 = 0;
1021  bac->bac_scanned = 0;
1022  bac->bac_found = 0;
1023  bac->bac_flags = req->bar_flags;
1025  bac->bac_criteria = 0;
1026 
1027  if (req->bar_goal == 0)
1028  req->bar_goal = motr->cb_last;
1029 
1030  bac->bac_orig.e_start = req->bar_goal;
1031  bac->bac_orig.e_end = req->bar_goal + req->bar_len;
1032  m0_ext_init(&bac->bac_orig);
1033  bac->bac_goal = bac->bac_orig;
1034 
1035  M0_SET0(&bac->bac_best);
1036  M0_SET0(&bac->bac_final);
1037  m0_ext_init(&bac->bac_best);
1038  m0_ext_init(&bac->bac_final);
1039 
1040  return M0_RC(0);
1041 }
1042 
1043 
1045 {
1046  return 0;
1047 }
1048 
1049 static bool is_spare(uint64_t alloc_flags)
1050 {
1051  return alloc_flags & M0_BALLOC_SPARE_ZONE;
1052 }
1053 
1054 static bool is_normal(uint64_t alloc_flags)
1055 {
1056  return alloc_flags & M0_BALLOC_NORMAL_ZONE;
1057 }
1058 
1059 static bool is_any(uint64_t alloc_flag)
1060 {
1061  return is_spare(alloc_flag) && is_normal(alloc_flag);
1062 }
1063 
1073 static bool balloc_got_freespace(const struct m0_balloc *ctx,
1074  m0_bcount_t blocks, uint64_t alloc_flags)
1075 {
1076  int rc;
1077  M0_ENTRY();
1078 
1079  M0_LOG(M0_DEBUG, "bsb_freeblocks=%llu blocks=%llu",
1080  (unsigned long long)ctx->cb_sb.bsb_freeblocks,
1081  (unsigned long long)blocks);
1082  rc =
1083 #ifdef __SPARE_SPACE__
1084  is_any(alloc_flags) ? (ctx->cb_sb.bsb_freespare >= blocks ||
1085  ctx->cb_sb.bsb_freeblocks >= blocks) :
1086  is_spare(alloc_flags) ? ctx->cb_sb.bsb_freespare >= blocks :
1087 #endif
1088  (ctx->cb_sb.bsb_freeblocks >= blocks);
1089 
1090  M0_LEAVE();
1091  return M0_RC(rc);
1092 }
1093 
1094 /*
1095  * here we normalize request for locality group
1096  */
1097 static void
1099 {
1100 }
1101 
1102 /*
1103  * Normalization means making request better in terms of
1104  * size and alignment
1105  */
1106 static void
1108 {
1110  M0_ENTRY();
1111 
1112  /* do normalize only for data requests. metadata requests
1113  do not need preallocation */
1114  if (!(bac->bac_flags & M0_BALLOC_HINT_DATA))
1115  goto out;
1116 
1117  /* sometime caller may want exact blocks */
1119  goto out;
1120 
1121  /* caller may indicate that preallocation isn't
1122  * required (it's a tail, for example) */
1124  goto out;
1125 
1128  goto out;
1129  }
1130 
1131  /* @todo : removing normalisation for time. */
1132  if (size <= 4 ) {
1133  size = 4;
1134  } else if (size <= 8) {
1135  size = 8;
1136  } else if (size <= 16) {
1137  size = 16;
1138  } else if (size <= 32) {
1139  size = 32;
1140  } else if (size <= 64) {
1141  size = 64;
1142  } else if (size <= 128) {
1143  size = 128;
1144  } else if (size <= 256) {
1145  size = 256;
1146  } else if (size <= 512) {
1147  size = 512;
1148  } else if (size <= 1024) {
1149  size = 1024;
1150  } else if (size <= 2048) {
1151  size = 2048;
1152  } else {
1153  M0_LOG(M0_WARN, "length %llu is too large, truncate to %llu",
1154  (unsigned long long) size, MAX_ALLOCATION_CHUNK);
1156  }
1157 
1158  if (size > bac->bac_ctxt->cb_sb.bsb_groupsize)
1159  size = bac->bac_ctxt->cb_sb.bsb_groupsize;
1160 
1161  /*
1162  Now prepare new goal. Extra space we get will be consumed and
1163  reserved by preallocation.
1164  */
1165  bac->bac_goal.e_end = bac->bac_goal.e_start + size;
1166 
1167  M0_LOG(M0_DEBUG, "goal: start=%llu=(0x%08llx), size=%llu(was %llu)",
1168  (unsigned long long) bac->bac_goal.e_start,
1169  (unsigned long long) bac->bac_goal.e_start,
1170  (unsigned long long) m0_ext_length(&bac->bac_goal),
1171  (unsigned long long) m0_ext_length(&bac->bac_orig));
1172 out:
1173  M0_LEAVE();
1174 }
1175 
1176 /* called under group lock */
1177 #ifdef __SPARE_SPACE__
1178 M0_INTERNAL int m0_balloc_load_extents(struct m0_balloc *cb,
1179  struct m0_balloc_group_info *grp)
1180 {
1181  struct m0_be_btree *db_ext = &cb->cb_db_group_extents;
1182  struct m0_be_btree_cursor cursor;
1183  struct m0_buf key;
1184  struct m0_buf val;
1185  struct m0_lext *ex;
1186  struct m0_ext spare_range;
1187  struct m0_ext normal_range;
1188  m0_bindex_t next_key;
1189  m0_bcount_t i;
1190  int rc = 0;
1191 
1192  M0_ENTRY("grp=%d non-spare-frags=%d spare-frags=%d",
1193  (int)grp->bgi_groupno, (int)group_fragments_get(grp),
1196 
1197  if (grp->bgi_extents != NULL) {
1198  M0_LOG(M0_DEBUG, "Already loaded");
1199  return M0_RC(0);
1200  }
1201 
1202  M0_ALLOC_ARR(grp->bgi_extents, group_fragments_get(grp) +
1204  if (grp->bgi_extents == NULL)
1205  return M0_RC(-ENOMEM);
1206 
1207  if (group_fragments_get(grp) == 0 &&
1209  M0_LOG(M0_NOTICE, "zero fragments");
1210  return M0_RC(0);
1211  }
1212 
1213  m0_be_btree_cursor_init(&cursor, db_ext);
1214 
1215  spare_range.e_start = grp->bgi_spare.bzp_range.e_start;
1216  spare_range.e_end = (grp->bgi_groupno + 1) << cb->cb_sb.bsb_gsbits;
1217  m0_ext_init(&spare_range);
1218  normal_range.e_start = grp->bgi_groupno << cb->cb_sb.bsb_gsbits;
1219  normal_range.e_end = spare_range.e_start;
1220  m0_ext_init(&normal_range);
1221 
1222  ex = grp->bgi_extents;
1223  ex->le_ext.e_end = (grp->bgi_groupno << cb->cb_sb.bsb_gsbits) + 1;
1224  next_key = ex->le_ext.e_end;
1225  for (i = 0; i < group_fragments_get(grp) +
1226  group_spare_fragments_get(grp); i++, ex++) {
1227  key = (struct m0_buf)M0_BUF_INIT_PTR(&next_key);
1228  rc = m0_be_btree_cursor_get_sync(&cursor, &key, true);
1229  if (rc != 0)
1230  break;
1231  m0_be_btree_cursor_kv_get(&cursor, &key, &val);
1232  ex->le_ext.e_end = *(m0_bindex_t*)key.b_addr;
1233  ex->le_ext.e_start = *(m0_bindex_t*)val.b_addr;
1234  m0_ext_init(&ex->le_ext);
1235  if (m0_ext_is_partof(&normal_range, &ex->le_ext))
1237  &ex->le_link);
1238  else if (m0_ext_is_partof(&spare_range, &ex->le_ext)) {
1240  }
1241  else {
1242  M0_LOG(M0_ERROR, "Invalid extent");
1243  M0_ASSERT(false);
1244  }
1245  next_key = ex->le_ext.e_end + 1;
1246  /* balloc_debug_dump_extent("loading...", ex); */
1247  }
1248  m0_be_btree_cursor_fini(&cursor);
1249 
1251  M0_LOG(M0_ERROR, "fragments mismatch: i=%llu frags=%lld",
1252  (unsigned long long)i,
1253  (unsigned long long)(group_fragments_get(grp) +
1255  if (rc != 0)
1257 
1258  return M0_RC(rc);
1259 }
1260 #else
1262  struct m0_ext *ext, uint64_t balloc_zone)
1263 {
1264  struct m0_balloc_zone_param *zp;
1265 
1266  zp = balloc_zone == M0_BALLOC_NORMAL_ZONE ?
1267  &grp->bgi_normal : &grp->bgi_spare;
1269  m0_ext_length(ext));
1270  zp->bzp_freeblocks += m0_ext_length(ext);
1271 }
1272 
1273 M0_INTERNAL int m0_balloc_load_extents(struct m0_balloc *cb,
1274  struct m0_balloc_group_info *grp)
1275 {
1276  struct m0_be_btree *db_ext = &cb->cb_db_group_extents;
1277  struct m0_buf key;
1278  struct m0_buf val;
1279  struct m0_lext *ex;
1280  struct m0_ext spare_range;
1281  struct m0_ext normal_range;
1282  m0_bcount_t i;
1283  m0_bcount_t normal_frags;
1284  m0_bcount_t spare_frags;
1285  m0_bindex_t next_key;
1286  int rc = 0;
1287 
1288  M0_ENTRY("grp=%d non-spare-frags=%d spare-frags=%d",
1289  (int)grp->bgi_groupno, (int)group_fragments_get(grp),
1292 
1293  if (grp->bgi_extents != NULL) {
1294  M0_LOG(M0_DEBUG, "Already loaded");
1295  return M0_RC(0);
1296  }
1297 
1298  if (group_fragments_get(grp) +
1300  M0_LOG(M0_NOTICE, "zero fragments");
1301  return M0_RC(0);
1302  }
1303 
1304  M0_ALLOC_ARR(grp->bgi_extents, group_fragments_get(grp) +
1306  if (grp->bgi_extents == NULL)
1307  return M0_RC(-ENOMEM);
1308 
1309  spare_range.e_start = grp->bgi_spare.bzp_range.e_start;
1310  spare_range.e_end = (grp->bgi_groupno + 1) << cb->cb_sb.bsb_gsbits;
1311  m0_ext_init(&spare_range);
1312  normal_range.e_start = grp->bgi_groupno << cb->cb_sb.bsb_gsbits;
1313  normal_range.e_end = spare_range.e_start;
1314  m0_ext_init(&normal_range);
1315 
1316  ex = grp->bgi_extents;
1317  next_key = (grp->bgi_groupno << cb->cb_sb.bsb_gsbits) + 1;
1318  normal_frags = 0;
1319  spare_frags = 0;
1320  grp->bgi_normal.bzp_maxchunk = 0;
1321  grp->bgi_normal.bzp_freeblocks = 0;
1322  grp->bgi_spare.bzp_maxchunk = 0;
1323  grp->bgi_spare.bzp_freeblocks = 0;
1324  for (i = 0; i < group_fragments_get(grp) +
1325  group_spare_fragments_get(grp); i++, ex++) {
1326  ex->le_ext.e_end = next_key;
1327  key = M0_BUF_INIT_PTR(&ex->le_ext.e_end);
1330  &key, &val),
1331  bo_u.u_btree.t_rc);
1332  if (rc != 0)
1333  break;
1334  m0_ext_init(&ex->le_ext);
1335  if (m0_ext_is_partof(&normal_range, &ex->le_ext)) {
1337  ++normal_frags;
1340  } else if (m0_ext_is_partof(&spare_range, &ex->le_ext)) {
1342  ++spare_frags;
1345  } else {
1346  M0_LOG(M0_ERROR, "Invalid extent");
1347  M0_ASSERT(false);
1348  }
1349  next_key = ex->le_ext.e_end + 1;
1350  balloc_debug_dump_extent("loading...", &ex->le_ext);
1351  }
1352 
1354  M0_LOG(M0_ERROR, "fragments mismatch: i=%llu frags=%lld",
1355  (unsigned long long)i,
1356  (unsigned long long)(group_fragments_get(grp) +
1358  if (rc != 0)
1360  else {
1361  grp->bgi_normal.bzp_fragments = normal_frags;
1362  grp->bgi_spare.bzp_fragments = spare_frags;
1363  }
1364 
1365  return M0_RC(rc);
1366 }
1367 #endif
1368 
1369 #if 0
1370 /* called under group lock */
1371 static int balloc_find_extent_exact(struct m0_balloc_allocation_context *bac,
1372  struct m0_balloc_group_info *grp,
1373  struct m0_ext *goal,
1374  struct m0_ext *ex)
1375 {
1376  m0_bcount_t i;
1377  int found = 0;
1378  struct m0_ext *fragment;
1379 
1381 
1382  for (i = 0; i < grp->bgi_fragments; i++) {
1383  fragment = &grp->bgi_extents[i];
1384 
1385  if (m0_ext_is_partof(fragment, goal)) {
1386  found = 1;
1387  *ex = *fragment;
1388  balloc_debug_dump_extent(__func__, ex);
1389  break;
1390  }
1391  if (fragment->e_start > goal->e_start)
1392  break;
1393  }
1394 
1395  return found;
1396 }
1397 #endif
1398 
1399 /* called under group lock */
1401  struct m0_balloc_group_info *grp,
1402  m0_bcount_t len,
1403  enum m0_balloc_allocation_flag alloc_flag,
1404  struct m0_ext *ex)
1405 {
1406  int found = 0;
1407  m0_bcount_t flen;
1409  struct m0_ext *frag;
1410  struct m0_lext *le;
1411  struct m0_ext min = {
1412  .e_start = 0,
1413  .e_end = 0xffffffff,
1414  };
1415  struct m0_balloc_zone_param *zp;
1416 
1418 
1419  m0_ext_init(&min);
1420 
1421  zp = is_spare(alloc_flag) ? &grp->bgi_spare : &grp->bgi_normal;
1422 
1423  M0_LOG(M0_DEBUG, "start=%" PRIu64 " len=%"PRIu64,
1424  zp->bzp_range.e_start, len);
1425 
1426  start = zp->bzp_range.e_start;
1427  m0_list_for_each_entry(&zp->bzp_extents, le, struct m0_lext, le_link) {
1428  frag = &le->le_ext;
1429  flen = m0_ext_length(frag);
1430  M0_LOG(M0_DEBUG, "frag="EXT_F, EXT_P(frag));
1431 repeat:
1432  /*
1433  {
1434  char msg[128];
1435  sprintf(msg, "buddy[s=%llu:0x%08llx, l=%u:0x%08x]",
1436  (unsigned long long)start,
1437  (unsigned long long)start,
1438  (int)len, (int)len);
1439  (void)msg;
1440  balloc_debug_dump_extent(msg, frag);
1441  }
1442  */
1443  if (frag->e_start == start && flen >= len) {
1444  ++found;
1445  if (flen < m0_ext_length(&min))
1446  min = *frag;
1447  if (flen == len || found > M0_BALLOC_BUDDY_LOOKUP_MAX)
1448  break;
1449  }
1450  if (frag->e_start > start) {
1451  do {
1452  start += len;
1453  } while (frag->e_start > start);
1454  if (start >= zp->bzp_range.e_end)
1455  break;
1456  /* we changed the 'start'. let's restart searching. */
1457  goto repeat;
1458  }
1459  }
1460 
1461  if (found > 0)
1462  *ex = min;
1463 
1464  return found;
1465 }
1466 
1469 {
1470  m0_bcount_t len = m0_ext_length(&bac->bac_goal);
1471 
1472  while (start < bac->bac_best.e_start)
1473  start += len;
1474 
1475  M0_LOG(M0_DEBUG, "start=0x%"PRIx64, start);
1476 
1477  if (start < bac->bac_best.e_end && len <= bac->bac_best.e_end - start)
1478  bac->bac_final.e_start = start;
1479  else
1480  bac->bac_final.e_start = bac->bac_best.e_start;
1481 
1482  bac->bac_final.e_end = bac->bac_final.e_start +
1483  min_check(m0_ext_length(&bac->bac_best), len);
1484  M0_LOG(M0_DEBUG, "final="EXT_F, EXT_P(&bac->bac_final));
1486 
1487  return 0;
1488 }
1489 
1491 {
1492  /* XXX No Preallocation now. So, trim the result to the original length. */
1493 
1494  bac->bac_final.e_end = bac->bac_final.e_start +
1496  m0_ext_length(&bac->bac_final));
1497  return 0;
1498 }
1499 
1500 static void balloc_sb_sync_credit(const struct m0_balloc *bal,
1501  struct m0_be_tx_credit *accum)
1502 {
1503  struct m0_be_tx_credit cred = M0_BE_TX_CREDIT_PTR(bal);
1504 
1505  m0_be_tx_credit_add(accum, &cred);
1506 }
1507 
1508 static void balloc_db_update_credit(const struct m0_balloc *bal, int nr,
1509  struct m0_be_tx_credit *accum)
1510 {
1511  const struct m0_be_btree *tree = &bal->cb_db_group_extents;
1512  struct m0_be_tx_credit cred = {};
1513 
1514  m0_be_btree_delete_credit(tree, 1,
1515  M0_MEMBER_SIZE(struct m0_ext, e_start),
1516  M0_MEMBER_SIZE(struct m0_ext, e_end), &cred);
1517  m0_be_btree_insert_credit(tree, 1,
1518  M0_MEMBER_SIZE(struct m0_ext, e_start),
1519  M0_MEMBER_SIZE(struct m0_ext, e_end), &cred);
1520  m0_be_btree_update_credit(tree, 2,
1521  M0_MEMBER_SIZE(struct m0_ext, e_end), &cred);
1522  balloc_sb_sync_credit(bal, &cred);
1523  balloc_gi_sync_credit(bal, &cred);
1524  m0_be_tx_credit_mac(accum, &cred, nr);
1525 }
1526 
1538  const struct m0_ext *tgt, uint64_t alloc_type,
1539  struct m0_ext **current)
1540 {
1541  struct m0_lext *le;
1542  struct m0_balloc_zone_param *zp;
1543  m0_bcount_t frags = 0;
1544 
1545  M0_ENTRY();
1546 
1547  zp = is_spare(alloc_type) ? &grp->bgi_spare : &grp->bgi_normal;
1548 
1549  m0_list_for_each_entry(&zp->bzp_extents, le, struct m0_lext, le_link) {
1550  *current = &le->le_ext;
1551  if (m0_ext_is_partof(*current, tgt))
1552  break;
1553  ++frags;
1554  }
1555  return frags < zp->bzp_fragments;
1556 }
1557 
1558 static int balloc_alloc_db_update(struct m0_balloc *motr, struct m0_be_tx *tx,
1559  struct m0_balloc_group_info *grp,
1560  struct m0_ext *tgt, uint64_t alloc_type,
1561  struct m0_ext *cur)
1562 {
1563  struct m0_be_btree *db = &motr->cb_db_group_extents;
1564  struct m0_buf key;
1565  struct m0_buf val;
1566  struct m0_lext *le;
1567  struct m0_lext *lcur;
1568  struct m0_balloc_zone_param *zp;
1569  int rc = 0;
1570  m0_bcount_t maxchunk;
1571 
1572  M0_ENTRY();
1574  M0_PRE(!is_any(alloc_type));
1575  M0_PRE(M0_IN(alloc_type, (M0_BALLOC_SPARE_ZONE,
1577  M0_PRE(cur != NULL);
1578 
1579  balloc_debug_dump_extent("target=", tgt);
1580 
1581  zp = is_spare(alloc_type) ? &grp->bgi_spare : &grp->bgi_normal;
1582  maxchunk = zp->bzp_maxchunk;
1583 
1584  balloc_debug_dump_extent("current=", cur);
1585 
1586  if (m0_ext_length(cur) == zp->bzp_maxchunk) {
1587  /* find next to max sized chunk */
1588  maxchunk = 0;
1590  struct m0_lext, le_link) {
1591  if (&le->le_ext == cur)
1592  continue;
1593  maxchunk = max_check(maxchunk,
1594  m0_ext_length(&le->le_ext));
1595  }
1596  }
1597 
1598  M0_LOG(M0_DEBUG, "bzp_maxchunk=0x%" PRIx64 " next_maxchunk=0x%"PRIx64,
1599  zp->bzp_maxchunk, maxchunk);
1600 
1601  if (cur->e_end == tgt->e_end) {
1602  key = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_end);
1603 
1604  rc = btree_delete_sync(db, tx, &key);
1605  if (rc != 0)
1606  return M0_RC(rc);
1607 
1608  if (cur->e_start < tgt->e_start) {
1609  /* +--------------+--------------------+ */
1610  /* | cur free | allocated | */
1611  /* | | tgt | | */
1612  /* +------+-------+--------------------+ */
1613  cur->e_end = tgt->e_start;
1614  key = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_end);
1615  val = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_start);
1616  rc = btree_insert_sync(db, tx, &key, &val);
1617  if (rc != 0)
1618  return M0_RC(rc);
1619  maxchunk = max_check(maxchunk, m0_ext_length(cur));
1620  } else {
1621  /* +-------------+---------------------+ */
1622  /* | cur free | allocated | */
1623  /* | tgt | | */
1624  /* +-------------+---------------------+ */
1625  le = container_of(cur, struct m0_lext, le_ext);
1626  lext_del(le);
1627  zp->bzp_fragments--;
1628  }
1629  } else {
1630  struct m0_ext new = *cur;
1631 
1632  /* +-----------------------------------+ */
1633  /* | cur free | */
1634  /* | tgt | | */
1635  /* +------------+----------------------+ */
1636  cur->e_start = tgt->e_end;
1637 
1638  key = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_end);
1639  val = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_start);
1640  rc = btree_update_sync(db, tx, &key, &val);
1641  if (rc != 0)
1642  return M0_RC(rc);
1643 
1644  maxchunk = max_check(maxchunk, m0_ext_length(cur));
1645 
1646  if (new.e_start < tgt->e_start) {
1647  /* +-----------------------------------+ */
1648  /* | cur free | */
1649  /* | new | tgt | | */
1650  /* +-------+---------+-----------------+ */
1651  new.e_end = tgt->e_start;
1652  le = lext_create(&new);
1653  if (le == NULL)
1654  return M0_RC(-ENOMEM);
1655  key = (struct m0_buf)M0_BUF_INIT_PTR(&new.e_end);
1656  val = (struct m0_buf)M0_BUF_INIT_PTR(&new.e_start);
1657  rc = btree_insert_sync(db, tx, &key, &val);
1658  if (rc != 0) {
1659  m0_free(le);
1660  return M0_RC(rc);
1661  }
1662  lcur = container_of(cur, struct m0_lext, le_ext);
1663  m0_list_add_before(&lcur->le_link, &le->le_link);
1664  zp->bzp_fragments++;
1665  maxchunk = max_check(maxchunk, m0_ext_length(&new));
1666  }
1667  }
1668  zp->bzp_maxchunk = maxchunk;
1670 
1671  grp->bgi_state |= M0_BALLOC_GROUP_INFO_DIRTY;
1672 
1673  m0_mutex_lock(&motr->cb_sb_mutex.bm_u.mutex);
1674 #ifdef __SPARE_SPACE__
1675  if (is_spare(alloc_type))
1676  motr->cb_sb.bsb_freespare -= m0_ext_length(tgt);
1677  else
1678 #endif
1679  motr->cb_sb.bsb_freeblocks -= m0_ext_length(tgt);
1680  motr->cb_sb.bsb_state |= M0_BALLOC_SB_DIRTY;
1681  balloc_sb_sync(motr, tx);
1682  m0_mutex_unlock(&motr->cb_sb_mutex.bm_u.mutex);
1683 
1684  rc = balloc_gi_sync(motr, tx, grp);
1685 
1686  return M0_RC(rc);
1687 }
1688 
1690  struct m0_be_tx *tx,
1691  struct m0_balloc_group_info *grp,
1692  struct m0_ext *tgt, uint64_t alloc_flag)
1693 {
1694  struct m0_buf key;
1695  struct m0_buf val;
1696  struct m0_be_btree *db = &motr->cb_db_group_extents;
1697  struct m0_ext *cur = NULL;
1698  struct m0_ext *pre = NULL;
1699  struct m0_lext *le;
1700  struct m0_lext *lcur;
1701  struct m0_balloc_zone_param *zp;
1702  m0_bcount_t frags = 0;
1703  m0_bcount_t maxchunk;
1704  int rc = 0;
1705  int found = 0;
1706 
1707  M0_ENTRY();
1709 
1710  balloc_debug_dump_extent("target=", tgt);
1711 
1712  zp = is_spare(alloc_flag) ? &grp->bgi_spare : &grp->bgi_normal;
1713  maxchunk = zp->bzp_maxchunk;
1714  m0_list_for_each_entry(&zp->bzp_extents, le, struct m0_lext, le_link) {
1715  cur = &le->le_ext;
1716 
1717  if (cur->e_start >= tgt->e_start) {
1718  found = 1;
1719  break;
1720  }
1721  pre = cur;
1722  ++frags;
1723  }
1724  balloc_debug_dump_extent("prev=", pre);
1725  balloc_debug_dump_extent("current=", cur);
1726 
1727  if (found && cur && tgt->e_end > cur->e_start) {
1728  M0_LOG(M0_ERROR, "!!!!!!!!!!!!!double free: "
1729  "tgt_end=%llu cur_start=%llu",
1730  (unsigned long long)tgt->e_end,
1731  (unsigned long long)cur->e_start);
1733  "double free with cur", grp);
1734  return M0_RC(-EINVAL);
1735  }
1736  if (pre && pre->e_end > tgt->e_start) {
1737  M0_LOG(M0_ERROR, "!!!!!!!!!!!!!double free: "
1738  "pre_end=%llu tgt_start=%llu",
1739  (unsigned long long)pre->e_end,
1740  (unsigned long long)tgt->e_start);
1742  "double free with pre", grp);
1743  return M0_RC(-EINVAL);
1744  }
1745 
1746  lcur = container_of(cur, struct m0_lext, le_ext);
1747 
1748  if (!found) {
1749  if (frags == 0) {
1750  /* No free fragments at all: */
1751  /* +-----------------------------------+ */
1752  /* | allocated | */
1753  /* | | tgt free | | */
1754  /* +-------+------------------+--------+ */
1755  le = lext_create(tgt);
1756  if (le == NULL)
1757  return M0_RC(-ENOMEM);
1758  key = (struct m0_buf)M0_BUF_INIT_PTR(&tgt->e_end);
1759  val = (struct m0_buf)M0_BUF_INIT_PTR(&tgt->e_start);
1760  rc = btree_insert_sync(db, tx, &key, &val);
1761  if (rc != 0) {
1762  m0_free(le);
1763  return M0_RC(rc);
1764  }
1765  m0_list_add(&zp->bzp_extents, &le->le_link);
1766  ++zp->bzp_fragments;
1767  maxchunk = max_check(maxchunk, m0_ext_length(tgt));
1768  } else {
1769  /* at the tail */
1770  if (cur->e_end < tgt->e_start) {
1771  /* To be the last one, standalone: */
1772  /* +-----------+-----------------------+ */
1773  /* | cur | | */
1774  /* | | | tgt free | */
1775  /* +-----------+--+--------------------+ */
1776  le = lext_create(tgt);
1777  if (le == NULL)
1778  return M0_RC(-ENOMEM);
1779  key = (struct m0_buf)M0_BUF_INIT_PTR(&tgt->e_end);
1780  val = (struct m0_buf)M0_BUF_INIT_PTR(&tgt->e_start);
1781  rc = btree_insert_sync(db, tx, &key, &val);
1782  if (rc != 0) {
1783  m0_free(le);
1784  return M0_RC(rc);
1785  }
1786  m0_list_add_after(&lcur->le_link, &le->le_link);
1787  ++zp->bzp_fragments;
1788  maxchunk = max_check(maxchunk, m0_ext_length(tgt));
1789  } else {
1790  /* +-----------+-----------------------+ */
1791  /* | cur |--> | */
1792  /* | | tgt free | */
1793  /* +-----------+-----------------------+ */
1794  M0_ASSERT(cur->e_end == tgt->e_start);
1795  key = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_end);
1796  rc = btree_delete_sync(db, tx, &key);
1797  if (rc != 0)
1798  return M0_RC(rc);
1799  cur->e_end = tgt->e_end;
1800  val = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_start);
1801  rc = btree_insert_sync(db, tx, &key, &val);
1802  if (rc != 0)
1803  return M0_RC(rc);
1804  maxchunk = max_check(maxchunk, m0_ext_length(cur));
1805  }
1806  }
1807  } else if (found && pre == NULL) {
1808  /* on the head */
1809  if (tgt->e_end < cur->e_start) {
1810  /* To be the first one: */
1811  /* +---------------+-------------------+ */
1812  /* | | cur free | */
1813  /* | | tgt | | | */
1814  /* +-+---------+---+-------------------+ */
1815  le = lext_create(tgt);
1816  if (le == NULL)
1817  return M0_RC(-ENOMEM);
1818  key = (struct m0_buf)M0_BUF_INIT_PTR(&tgt->e_end);
1819  val = (struct m0_buf)M0_BUF_INIT_PTR(&tgt->e_start);
1820  rc = btree_insert_sync(db, tx, &key, &val);
1821  if (rc != 0) {
1822  m0_free(le);
1823  return M0_RC(rc);
1824  }
1825  m0_list_add_before(&lcur->le_link, &le->le_link);
1826  ++zp->bzp_fragments;
1827  maxchunk = max_check(maxchunk, m0_ext_length(tgt));
1828  } else {
1829  /* Join with the first one: */
1830  /* +---------------+-------------------+ */
1831  /* | <--| cur free | */
1832  /* | | tgt | | */
1833  /* +-----+---------+-------------------+ */
1834  M0_ASSERT(tgt->e_end == cur->e_start);
1835  cur->e_start = tgt->e_start;
1836  key = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_end);
1837  val = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_start);
1838  rc = btree_update_sync(db, tx, &key, &val);
1839  if (rc != 0)
1840  return M0_RC(rc);
1841  maxchunk = max_check(maxchunk, m0_ext_length(cur));
1842  }
1843  } else {
1844  /* in the middle */
1845  if (pre->e_end == tgt->e_start &&
1846  tgt->e_end == cur->e_start) {
1847  /* Joint with both: */
1848  /* +-------+-------+-------------------+ */
1849  /* | pre |--> <--| cur free | */
1850  /* | | tgt | | */
1851  /* +-------+-------+-------------------+ */
1852  key = (struct m0_buf)M0_BUF_INIT_PTR(&pre->e_end);
1853  rc = btree_delete_sync(db, tx, &key);
1854  if (rc != 0)
1855  return M0_RC(rc);
1856  cur->e_start = pre->e_start;
1857  key = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_end);
1858  val = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_start);
1859  rc = btree_update_sync(db, tx, &key, &val);
1860  if (rc != 0)
1861  return M0_RC(rc);
1862  le = container_of(pre, struct m0_lext, le_ext);
1863  lext_del(le);
1864  --zp->bzp_fragments;
1865  maxchunk = max_check(maxchunk, m0_ext_length(cur));
1866  } else if (pre->e_end == tgt->e_start) {
1867  /* Joint with prev: */
1868  /* +-------+----------+----------------+ */
1869  /* | pre |--> | cur free | */
1870  /* | | tgt | | */
1871  /* +-------+-------+-------------------+ */
1872  key = (struct m0_buf)M0_BUF_INIT_PTR(&pre->e_end);
1873  rc = btree_delete_sync(db, tx, &key);
1874  if (rc != 0)
1875  return M0_RC(rc);
1876  pre->e_end = tgt->e_end;
1877  val = (struct m0_buf)M0_BUF_INIT_PTR(&pre->e_start);
1878  rc = btree_insert_sync(db, tx, &key, &val);
1879  if (rc != 0)
1880  return M0_RC(rc);
1881  maxchunk = max_check(maxchunk, m0_ext_length(pre));
1882  } else if (tgt->e_end == cur->e_start) {
1883  /* Joint with current: */
1884  /* +-------+----------+----------------+ */
1885  /* | pre | <--| cur free | */
1886  /* | | tgt | | */
1887  /* +----------+-------+----------------+ */
1888  cur->e_start = tgt->e_start;
1889  key = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_end);
1890  val = (struct m0_buf)M0_BUF_INIT_PTR(&cur->e_start);
1891  rc = btree_update_sync(db, tx, &key, &val);
1892  if (rc != 0)
1893  return M0_RC(rc);
1894  maxchunk = max_check(maxchunk, m0_ext_length(cur));
1895  } else {
1896  /* Add a new one: */
1897  /* +-------+------------+--------------+ */
1898  /* | pre | | cur free | */
1899  /* | | tgt | | */
1900  /* +----------+-------+----------------+ */
1901  le = lext_create(tgt);
1902  if (le == NULL)
1903  return M0_RC(-ENOMEM);
1904  key = (struct m0_buf)M0_BUF_INIT_PTR(&tgt->e_end);
1905  val = (struct m0_buf)M0_BUF_INIT_PTR(&tgt->e_start);
1906  rc = btree_insert_sync(db, tx, &key, &val);
1907  if (rc != 0) {
1908  m0_free(le);
1909  return M0_RC(rc);
1910  }
1911  m0_list_add_before(&lcur->le_link, &le->le_link);
1912  ++zp->bzp_fragments;
1913  maxchunk = max_check(maxchunk, m0_ext_length(tgt));
1914  }
1915  }
1916  zp->bzp_maxchunk = maxchunk;
1918 
1919  grp->bgi_state |= M0_BALLOC_GROUP_INFO_DIRTY;
1920 
1921  m0_mutex_lock(&motr->cb_sb_mutex.bm_u.mutex);
1922  if (is_spare(alloc_flag))
1923 #ifdef __SPARE_SPACE__
1924  motr->cb_sb.bsb_freespare += m0_ext_length(tgt);
1925 #else
1926  motr->cb_sb.bsb_freeblocks += m0_ext_length(tgt);
1927 #endif
1928  else
1929  motr->cb_sb.bsb_freeblocks += m0_ext_length(tgt);
1930  motr->cb_sb.bsb_state |= M0_BALLOC_SB_DIRTY;
1931  balloc_sb_sync(motr, tx);
1932  m0_mutex_unlock(&motr->cb_sb_mutex.bm_u.mutex);
1933 
1934  rc = balloc_gi_sync(motr, tx, grp);
1935 
1936  return M0_RC(rc);
1937 }
1938 
1939 #if 0
1940 static int balloc_find_by_goal(struct m0_balloc_allocation_context *bac)
1941 {
1942  m0_bindex_t group = balloc_bn2gn(bac->bac_goal.e_start,
1943  bac->bac_ctxt);
1944  struct m0_balloc_group_info *grp = m0_balloc_gn2info(bac->bac_ctxt,
1945  group);
1946  struct m0_be_tx *tx = bac->bac_tx;
1947  struct m0_ext ex = { 0 };
1948  int found;
1949  int ret = 0;
1950  M0_ENTRY();
1951 
1952  if (!(bac->bac_flags & M0_BALLOC_HINT_TRY_GOAL))
1953  goto out;
1954 
1955  M0_LOG(M0_DEBUG, "groupno=%llu start=%llu len=%llu groupsize=%llu",
1956  (unsigned long long)group,
1957  (unsigned long long)bac->bac_goal.e_start,
1958  (unsigned long long)m0_ext_length(&bac->bac_goal),
1959  (unsigned long long)bac->bac_ctxt->cb_sb.bsb_groupsize
1960  );
1961 
1963  if (grp->bgi_maxchunk < m0_ext_length(&bac->bac_goal)) {
1964  M0_LEAVE();
1965  goto out_unlock;
1966  }
1967  if (grp->bgi_freeblocks < m0_ext_length(&bac->bac_goal)) {
1968  M0_LEAVE();
1969  goto out_unlock;
1970  }
1971 
1972  ret = m0_balloc_load_extents(bac->bac_ctxt, grp);
1973  if (ret) {
1974  M0_LEAVE();
1975  goto out_unlock;
1976  }
1977 
1978  found = balloc_find_extent_exact(bac, grp, &bac->bac_goal, &ex);
1979  M0_LOG(M0_DEBUG, "found?max len = %llu",
1980  (unsigned long long)m0_ext_length(&ex));
1981 
1982  if (found) {
1983  bac->bac_found++;
1984  bac->bac_best.e_start = bac->bac_goal.e_start;
1985  bac->bac_best.e_end = ex.e_end;
1986  ret = balloc_use_best_found(bac);
1987  }
1988 
1989  /* update db according to the allocation result */
1990  if (ret == 0 && bac->bac_status == M0_BALLOC_AC_FOUND) {
1991  if (bac->bac_goal.e_end < bac->bac_best.e_end)
1993 
1994  ret = balloc_alloc_db_update(bac->bac_ctxt, tx, grp,
1995  &bac->bac_final);
1996  }
1997 
1999 out_unlock:
2001 out:
2002  return M0_RC(ret);
2003 }
2004 #endif
2005 
2006 /* group is locked */
2008  struct m0_balloc_group_info *gi)
2009 {
2010  if (is_any(bac->bac_flags)) {
2016  group_fragments_get(gi));
2017  } else if (is_spare(bac->bac_flags)) {
2021  } else if (is_normal(bac->bac_flags)) {
2022  return is_group_good_enough(bac, group_maxchunk_get(gi),
2024  group_fragments_get(gi));
2025  } else
2026  M0_ASSERT(0);
2027  /* The case when asserts are disabled */
2028  return 0;
2029 }
2030 
2032  m0_bcount_t maxchunk, m0_bcount_t free,
2033  m0_bcount_t fragments)
2034 {
2035  if (free == 0) {
2036  M0_LOG(M0_DEBUG, "bac=%p: no free blocks", bac);
2037  return 0;
2038  }
2039 
2040  if (fragments == 0) {
2041  M0_LOG(M0_DEBUG, "bac=%p: no fragments", bac);
2042  return 0;
2043  }
2044 
2045  switch (bac->bac_criteria) {
2046  case 0:
2047  if (maxchunk >= m0_ext_length(&bac->bac_goal))
2048  return 1;
2049  break;
2050  case 1:
2051  if ((free / fragments) >= m0_ext_length(&bac->bac_goal))
2052  return 2;
2053  break;
2054  case 2:
2055  return 3;
2056  break;
2057  default:
2058  M0_ASSERT(0);
2059  }
2060 
2061  M0_LOG(M0_DEBUG, "bac=%p criteria=%d: no big enough chunk: "
2062  "goal=0x%08" PRIx64 " maxchunk=0x%08"PRIx64,
2063  bac, bac->bac_criteria, m0_ext_length(&bac->bac_goal), maxchunk);
2064 
2065  return 0;
2066 }
2067 
2068 /* group is locked */
2070  struct m0_balloc_group_info *grp,
2071  enum m0_balloc_allocation_flag alloc_flag)
2072 {
2073 /*
2074  struct m0_balloc_super_block *sb = &bac->bac_ctxt->cb_sb;
2075 */
2076  struct m0_ext ex;
2077  m0_bcount_t len;
2079  int found = 0;
2080 
2081  M0_ENTRY();
2082  M0_PRE(bac->bac_order2 > 0);
2083 
2084  m0_ext_init(&ex);
2085  len = 1 << bac->bac_order2;
2086 /* for (; len <= sb->bsb_groupsize; len = len << 1) {
2087  M0_LOG(M0_DEBUG, "searching at %d (gs = %d) for order = %d "
2088  "len=%d:%x",
2089  (int)grp->bgi_groupno,
2090  (int)sb->bsb_groupsize,
2091  (int)bac->bac_order2,
2092  (int)len,
2093  (int)len);
2094 
2095  found = balloc_find_extent_buddy(bac, grp, len, &ex);
2096  if (found)
2097  break;
2098  }
2099 */
2100 
2101  found = balloc_find_extent_buddy(bac, grp, len, alloc_flag, &ex);
2102  if (found) {
2103  balloc_debug_dump_extent("found at simple scan", &ex);
2104 
2105  bac->bac_found++;
2106  bac->bac_best = ex;
2107  start = zone_start_get(grp, alloc_flag);
2109  }
2110 
2111  M0_LEAVE();
2112  return 0;
2113 }
2114 
2116  enum m0_balloc_allocation_flag alloc_flag)
2117 {
2118  return is_spare(alloc_flag) ? grp->bgi_spare.bzp_range.e_start :
2119  grp->bgi_normal.bzp_range.e_start;
2120 }
2121 
2122 __attribute__((unused))
2123 static int balloc_aligned_scan_group(struct balloc_allocation_context *bac,
2124  struct m0_balloc_group_info *grp)
2125 {
2126  return 0;
2127 }
2128 
2129 /*
2130  * How long balloc can look for a best extent (in found extents)
2131  */
2132 #define M0_BALLOC_DEFAULT_MAX_TO_SCAN 200
2133 
2134 /*
2135  * How long balloc must look for a best extent
2136  */
2137 #define M0_BALLOC_DEFAULT_MIN_TO_SCAN 10
2138 
2139 /*
2140  * How many groups balloc will scan looking for the best chunk
2141  */
2142 #define M0_BALLOC_DEFAULT_MAX_GROUPS_TO_SCAN 5
2143 
2144 
2146  struct m0_balloc_group_info *grp,
2147  int end_of_group,
2148  enum m0_balloc_allocation_flag alloc_flag)
2149 {
2150  int max_to_scan = M0_BALLOC_DEFAULT_MAX_TO_SCAN;
2151  int max_groups = M0_BALLOC_DEFAULT_MAX_GROUPS_TO_SCAN;
2152  int min_to_scan = M0_BALLOC_DEFAULT_MIN_TO_SCAN;
2153  M0_ENTRY();
2154 
2155  M0_LOG(M0_DEBUG, "check limits for group %llu. end = %d",
2156  (unsigned long long)grp->bgi_groupno,
2157  end_of_group);
2158 
2159  if (bac->bac_status == M0_BALLOC_AC_FOUND)
2160  return 0;
2161 
2162  if ((bac->bac_found > max_to_scan || bac->bac_scanned > max_groups) &&
2163  !(bac->bac_flags & M0_BALLOC_HINT_FIRST)) {
2165  return 0;
2166  }
2167 
2168  if (m0_ext_length(&bac->bac_best) < m0_ext_length(&bac->bac_goal))
2169  return 0;
2170 
2171  if ((end_of_group || bac->bac_found >= min_to_scan)) {
2173  bac->bac_ctxt);
2174  if (group == grp->bgi_groupno) {
2176  alloc_flag));
2177  }
2178  }
2179 
2180  return 0;
2181 }
2182 
2184  struct m0_balloc_group_info *grp,
2185  enum m0_balloc_allocation_flag alloc_flag,
2186  struct m0_ext *ex, int end_of_group)
2187 {
2188  struct m0_ext *goal = &bac->bac_goal;
2189  struct m0_ext *best = &bac->bac_best;
2190  int rc = 0;
2191  M0_ENTRY();
2192 
2193  balloc_debug_dump_extent(__func__, ex);
2194  bac->bac_found++;
2195 
2196  if ((bac->bac_flags & M0_BALLOC_HINT_FIRST) ||
2197  m0_ext_length(ex) == m0_ext_length(goal)) {
2198  *best = *ex;
2200  alloc_flag));
2201  M0_LEAVE();
2202  return 0;
2203  }
2204 
2205  if (m0_ext_length(best) == 0) {
2206  *best = *ex;
2207  M0_LEAVE();
2208  return 0;
2209  }
2210 
2211  if (m0_ext_length(best) < m0_ext_length(goal)) {
2212  /* req is still not satisfied. use the larger one */
2213  if (m0_ext_length(ex) > m0_ext_length(best)) {
2214  *best = *ex;
2215  }
2216  } else if (m0_ext_length(ex) >= m0_ext_length(goal)) {
2217  /* req is satisfied. but it is satisfied again.
2218  use the smaller one */
2219  if (m0_ext_length(ex) < m0_ext_length(best)) {
2220  *best = *ex;
2221  }
2222  }
2223 
2224  if (m0_ext_length(best) >= m0_ext_length(goal))
2225  rc = balloc_check_limits(bac, grp, end_of_group, alloc_flag);
2226  M0_LEAVE();
2227  return M0_RC(rc);
2228 }
2229 
2235  struct m0_balloc_group_info *grp,
2236  enum m0_balloc_allocation_flag alloc_flag)
2237 {
2238  struct m0_list *list;
2239  m0_bcount_t free;
2240  struct m0_ext *ex;
2241  struct m0_lext *le;
2242  int rc;
2243  int end_of_group = 0;
2244  M0_ENTRY();
2245 
2246 #ifdef __SPARE_SPACE__
2249  list = is_spare(alloc_flag) ? &grp->bgi_spare.bzp_extents :
2250  &grp->bgi_normal.bzp_extents;
2251 #else
2252  free = group_freeblocks_get(grp);
2253  list = &grp->bgi_normal.bzp_extents;
2254 #endif
2255 
2270  if (bac->bac_found != 0) {
2272  bac->bac_ctxt);
2273  if (group == grp->bgi_groupno) {
2274  end_of_group = 1;
2275  M0_SET0(&bac->bac_best);
2276  m0_ext_init(&bac->bac_best);
2277  }
2278  }
2279 
2280  M0_LOG(M0_DEBUG, "Wild scanning at group %llu: freeblocks=%llu",
2281  (unsigned long long)grp->bgi_groupno,
2282  (unsigned long long)free);
2283 
2284  m0_list_for_each_entry(list, le, struct m0_lext, le_link) {
2285  ex = &le->le_ext;
2286  if (m0_ext_length(ex) > free) {
2287  M0_LOG(M0_WARN, "corrupt group=%llu "
2288  "ex=[0x%08llx:0x%08llx)",
2289  (unsigned long long)grp->bgi_groupno,
2290  (unsigned long long)ex->e_start,
2291  (unsigned long long)ex->e_end);
2292  return M0_RC(-EINVAL);
2293  }
2294  balloc_measure_extent(bac, grp, alloc_flag, ex, end_of_group);
2295 
2296  free -= m0_ext_length(ex);
2297  if (free == 0 || bac->bac_status != M0_BALLOC_AC_CONTINUE)
2298  return M0_RC(0);
2299  }
2300 
2301  rc = balloc_check_limits(bac, grp, 1, alloc_flag);
2302  return M0_RC(rc);
2303 }
2304 
2305 /*
2306  * TRY to use the best result found in previous iteration.
2307  * The best result may be already used by others who are more lucky.
2308  * Group lock should be taken again.
2309  */
2311  enum m0_balloc_allocation_flag alloc_flag)
2312 {
2313  struct m0_ext *best = &bac->bac_best;
2315  bac->bac_ctxt);
2317  group);
2318  struct m0_ext *ex;
2319  struct m0_ext *cur = NULL;
2320  struct m0_lext *le;
2321  struct m0_list *list;
2322  int rc = -ENOENT;
2323 
2324  M0_ENTRY();
2325 
2327 
2328  if (is_spare(alloc_flag) && group_spare_freeblocks_get(grp) <
2329  m0_ext_length(best))
2330  goto out;
2331  if (is_normal(alloc_flag) && group_freeblocks_get(grp) <
2332  m0_ext_length(best))
2333  goto out;
2334 
2336  if (rc != 0)
2337  goto out;
2338 
2339  rc = -ENOENT;
2340  list = is_spare(alloc_flag) ? group_spare_ext(grp) :
2342  m0_list_for_each_entry(list, le, struct m0_lext, le_link) {
2343  ex = &le->le_ext;
2344  if (m0_ext_equal(ex, best)) {
2345  rc = balloc_use_best_found(bac,
2347  alloc_flag));
2348  break;
2349  } else if (ex->e_start > best->e_start)
2350  goto out;
2351  }
2352 
2353  /* update db according to the allocation result */
2354  if (rc == 0 && bac->bac_status == M0_BALLOC_AC_FOUND) {
2355  if (m0_ext_length(&bac->bac_goal) < m0_ext_length(best))
2357 
2358  balloc_debug_dump_extent(__func__, &bac->bac_final);
2359  M0_ASSERT(is_extent_free(grp, &bac->bac_final, alloc_flag,
2360  &cur));
2362  &bac->bac_final, alloc_flag, cur);
2363  }
2364 out:
2366  M0_LEAVE();
2367  return M0_RC(rc);
2368 }
2369 
2370 static void
2371 balloc_alloc_credit(const struct m0_ad_balloc *balroom, int nr,
2372  struct m0_be_tx_credit *accum)
2373 {
2374  const struct m0_balloc *bal = b2m0(balroom);
2375 
2376  M0_ENTRY("cred=[%lu:%lu] nr=%d",
2377  (unsigned long)accum->tc_reg_nr,
2378  (unsigned long)accum->tc_reg_size, nr);
2379  balloc_db_update_credit(bal, nr, accum);
2380  M0_LEAVE("cred=[%lu:%lu]",
2381  (unsigned long)accum->tc_reg_nr,
2382  (unsigned long)accum->tc_reg_size);
2383 }
2384 
2386  uint64_t alloc_flags)
2387 {
2388  return
2389 #ifdef __SPARE_SPACE__
2390  is_any(alloc_flags) ? (group_freeblocks_get(grp) == 0 &&
2392  is_spare(alloc_flags) ? group_spare_freeblocks_get(grp) == 0 :
2393 #endif
2394  group_freeblocks_get(grp) == 0;
2395 }
2396 
2397 static int
2399 {
2400  m0_bcount_t ngroups;
2402  m0_bcount_t i;
2403  m0_bcount_t len;
2404  int cr;
2405  int rc = 0;
2406 
2407  ngroups = bac->bac_ctxt->cb_sb.bsb_groupcount;
2408  len = m0_ext_length(&bac->bac_goal);
2409 
2410  M0_ENTRY("goal=0x%lx len=%d",
2411  (unsigned long)bac->bac_goal.e_start, (int)len);
2412 
2413 #if 0
2414  /* first, try the goal */
2415  rc = balloc_find_by_goal(bac);
2416  if (rc != 0 || bac->bac_status == M0_BALLOC_AC_FOUND ||
2418  M0_LEAVE();
2419  return M0_RC(rc);
2420  }
2421 #endif
2422 
2423  bac->bac_order2 = 0;
2424  /*
2425  * We search using buddy data only if the order of the request
2426  * is greater than equal to the threshold.
2427  */
2428  if (m0_is_po2(len))
2429  bac->bac_order2 = ffs(len) - 1;
2430 
2431  cr = bac->bac_order2 ? 0 : 1;
2432  /*
2433  * cr == 0 try to get exact allocation,
2434  * cr == 1 striped allocation. Not implemented currently.
2435  * cr == 2 try to get anything
2436  */
2437 repeat:
2438  for (;cr < 3 && bac->bac_status == M0_BALLOC_AC_CONTINUE; cr++) {
2439  M0_LOG(M0_DEBUG, "cr=%d", cr);
2440  bac->bac_criteria = cr;
2441  /*
2442  * searching for the right group start
2443  * from the goal value specified
2444  */
2445  group = balloc_bn2gn(bac->bac_goal.e_start, bac->bac_ctxt);
2446 
2447  for (i = 0; i < ngroups; group++, i++) {
2448  struct m0_balloc_group_info *grp;
2449 
2450  if (group >= ngroups)
2451  group = 0;
2452 
2454  // m0_balloc_debug_dump_group("searching group ...",
2455  // grp);
2456 
2458  if (rc != 0) {
2459  M0_LOG(M0_DEBUG, "grp=%d is busy", (int)group);
2460  /* This group is under processing by others. */
2461  continue;
2462  }
2463 
2464  /* quick check to skip empty groups */
2466  M0_LOG(M0_DEBUG, "grp=%d is empty", (int)group);
2468  continue;
2469  }
2470 
2472  if (rc != 0) {
2474  goto out;
2475  }
2476  if (!balloc_is_good_group(bac, grp)) {
2478  continue;
2479  }
2480  bac->bac_scanned++;
2481 
2482  /* m0_balloc_debug_dump_group_extent("AAA", grp); */
2483  rc = 1;
2484 #ifdef __SPARE_SPACE__
2485  if (is_spare(bac->bac_flags))
2486  rc = allocate_blocks(cr, bac, grp, len,
2488 #endif
2489  if (rc != 0 && (is_any(bac->bac_flags) ||
2490  is_normal(bac->bac_flags)))
2491  rc = allocate_blocks(cr, bac, grp, len,
2494 
2495  if (bac->bac_status != M0_BALLOC_AC_CONTINUE)
2496  break;
2497  }
2498  }
2499 
2500  if (m0_ext_length(&bac->bac_best) > 0 &&
2501  (bac->bac_status != M0_BALLOC_AC_FOUND) &&
2502  !(bac->bac_flags & M0_BALLOC_HINT_FIRST)) {
2503  /*
2504  * We've been searching too long. Let's try to allocate
2505  * the best chunk we've found so far
2506  */
2507 
2508  rc = 1;
2509 #ifdef __SPARE_SPACE__
2510  if (is_spare(bac->bac_flags))
2512 #endif
2513  if (rc != 0 &&
2514  (is_any(bac->bac_flags) || is_normal(bac->bac_flags))) {
2515  rc = balloc_try_best_found(bac,
2517  }
2518  if (rc || bac->bac_status != M0_BALLOC_AC_FOUND) {
2519  /*
2520  * Someone more lucky has already allocated it.
2521  * Let's just take first found block(s).
2522  */
2524  M0_SET0(&bac->bac_best);
2526  cr = 2;
2527  M0_LOG(M0_DEBUG, "Let's repeat..........");
2528  goto repeat;
2529  }
2530  }
2531 out:
2532  M0_LEAVE();
2533  if (rc == 0 && bac->bac_status != M0_BALLOC_AC_FOUND) {
2534  rc = -ENOSPC;
2535  M0_LOG(M0_ERROR, "Balloc running out of space");
2536  }
2537  return M0_RC(rc);
2538 }
2539 
2540 static int allocate_blocks(int cr, struct balloc_allocation_context *bac,
2541  struct m0_balloc_group_info *grp, m0_bcount_t len,
2542  enum m0_balloc_allocation_flag alloc_type)
2543 {
2544  int rc;
2545  struct m0_ext *cur = NULL;
2546 
2547  M0_PRE(!is_any(alloc_type));
2548  M0_PRE(is_spare(alloc_type) || is_normal(alloc_type));
2549 
2550  if (cr == 0 ||
2551  (cr == 1 && len == bac->bac_ctxt->cb_sb.bsb_stripe_size))
2552  rc = balloc_simple_scan_group(bac, grp, alloc_type);
2553  else
2554  rc = balloc_wild_scan_group(bac, grp, alloc_type);
2555 
2556  /* update db according to the allocation result */
2557  if (rc == 0 && bac->bac_status == M0_BALLOC_AC_FOUND) {
2558  if (len < m0_ext_length(&bac->bac_best))
2560  M0_ASSERT(is_extent_free(grp, &bac->bac_final, alloc_type,
2561  &cur));
2563  &bac->bac_final, alloc_type, cur);
2564  }
2565  return rc;
2566 }
2567 
2599 static
2601  struct m0_be_tx *tx,
2602  struct m0_balloc_allocate_req *req)
2603 {
2604  struct balloc_allocation_context bac;
2605  int rc;
2606 
2607  M0_ENTRY();
2608 
2609  while (req->bar_len &&
2610  !balloc_got_freespace(ctx, req->bar_len, req->bar_flags)) {
2611  req->bar_len >>= 1;
2612  }
2613  rc = req->bar_len == 0 ? -ENOSPC : 0;
2614  if (rc != 0)
2615  goto out;
2616 
2617  balloc_init_ac(&bac, ctx, tx, req);
2618 
2619  /* Step 1. query the pre-allocation */
2620  if (!balloc_use_prealloc(&bac)) {
2621  /* we did not find suitable free space in prealloc. */
2622 
2624 
2625  /* Step 2. Iterate over groups */
2626  rc = balloc_regular_allocator(&bac);
2627  if (rc == 0 && bac.bac_status == M0_BALLOC_AC_FOUND) {
2628  /* store the result in req and they will be returned */
2629  req->bar_result = bac.bac_final;
2630  }
2631  }
2632 out:
2633  return M0_RC(rc);
2634 }
2635 
2636 static void balloc_free_credit(const struct m0_ad_balloc *balroom, int nr,
2637  struct m0_be_tx_credit *accum)
2638 {
2639  balloc_db_update_credit(b2m0(balroom), nr, accum);
2640 }
2641 
2650  struct m0_be_tx *tx,
2651  struct m0_balloc_free_req *req)
2652 {
2653  struct m0_ext fex;
2654  struct m0_balloc_group_info *grp;
2655  struct m0_balloc_super_block *sb = &ctx->cb_sb;
2658  m0_bindex_t off;
2659  m0_bcount_t len;
2660  m0_bcount_t step;
2661  int rc = 0;
2662  uint64_t alloc_flag;
2663 
2664  M0_ENTRY();
2665 
2666  start = req->bfr_physical;
2667  len = req->bfr_len;
2668 
2669  M0_LOG(M0_DEBUG, "bal=%p start=0x%llx len=0x%llx start_group=%llu "
2670  "end_group=%llu group_count=%llu", ctx,
2671  (unsigned long long)start,
2672  (unsigned long long)len,
2673  (unsigned long long)balloc_bn2gn(start, ctx),
2674  (unsigned long long)balloc_bn2gn(start + len, ctx),
2675  (unsigned long long)sb->bsb_groupcount);
2676  group = balloc_bn2gn(start + len, ctx);
2677  if (group > sb->bsb_groupcount)
2678  return M0_ERR(-EINVAL);
2679 
2680  while (rc == 0 && len > 0) {
2684 
2686  if (rc != 0) {
2688  goto out;
2689  }
2690 
2692  off = start & (sb->bsb_groupsize - 1);
2693  step = (off + len > sb->bsb_groupsize) ?
2694  sb->bsb_groupsize - off : len;
2695 
2696  fex.e_start = start;
2697  fex.e_end = start + step;
2698  m0_ext_init(&fex);
2699  alloc_flag = ext_range_locate(&fex, grp);
2700  /*
2701  * For an extent spanning both zones first release
2702  * non-spare part, and then release spare part.
2703  */
2704  if (is_any(alloc_flag)) {
2705  fex.e_end = grp->bgi_spare.bzp_range.e_start;
2706  rc = balloc_free_db_update(ctx, tx, grp, &fex,
2708  if (rc != 0)
2709  break;
2710  fex.e_start = zone_start_get(grp,
2712  fex.e_end = start + step;
2713  alloc_flag = M0_BALLOC_SPARE_ZONE;
2714  }
2715  if (rc == 0)
2716  rc = balloc_free_db_update(ctx, tx, grp, &fex,
2717  alloc_flag);
2719  start += step;
2720  len -= step;
2721  }
2722 
2723 out:
2724  M0_LEAVE();
2725  return M0_RC(rc);
2726 }
2727 
2728 static uint64_t ext_range_locate(struct m0_ext *ip_ext,
2729  struct m0_balloc_group_info *grp)
2730 {
2731  if (m0_ext_is_partof(&grp->bgi_spare.bzp_range, ip_ext))
2732  return M0_BALLOC_SPARE_ZONE;
2733  else if (m0_ext_is_partof(&grp->bgi_normal.bzp_range, ip_ext))
2734  return M0_BALLOC_NORMAL_ZONE;
2735  else
2737 }
2745 __attribute__((unused))
2746 static int balloc_discard_prealloc(struct m0_balloc *ctx,
2747  struct m0_balloc_discard_req *req)
2748 {
2749  return 0;
2750 }
2751 
2764 __attribute__((unused))
2765 static int balloc_enforce(struct m0_balloc *ctx, bool alloc,
2766  struct m0_ext *ext)
2767 {
2768  return 0;
2769 }
2770 
2771 
2779 __attribute__((unused))
2780 static bool balloc_query(struct m0_balloc *ctx, struct m0_ext *ext)
2781 {
2782 
2783  return false;
2784 }
2785 
2796 static int balloc_reserve_extent(struct m0_ad_balloc *ballroom,
2797  struct m0_be_tx *tx, struct m0_ext *ext,
2798  uint64_t alloc_zone)
2799 {
2800  struct m0_balloc *ctx = b2m0(ballroom);
2801  m0_bcount_t ext_len;
2803  struct m0_balloc_group_info *grp;
2804  struct balloc_allocation_context bac;
2805  struct m0_ext *cur = NULL;
2806  int rc;
2807 
2808  M0_ENTRY("bal=%p extent="EXT_F, ctx, EXT_P(ext));
2809 
2810  ext_len = m0_ext_length(ext);
2811  /* Check total free space. */
2812  if (!balloc_got_freespace(ctx, ext_len, alloc_zone)) {
2813  rc = M0_ERR(-ENOSPC);
2814  M0_LOG(M0_DEBUG, "Balloc out of free space");
2815  goto out;
2816  }
2817  /* Fetch the group for this extent. */
2818  group = balloc_bn2gn(ext->e_start, ctx);
2819 
2820  /* Get the group. */
2822 
2823  /* Take lock of the group. */
2825 
2826  /* Check if space is available in group. */
2827  if (is_free_space_unavailable(grp, alloc_zone)) {
2828  rc = M0_ERR(-ENOSPC);
2829  M0_LOG(M0_DEBUG, "grp=%" PRIu64 " is empty", group);
2830  goto out_unlock;
2831  }
2832 
2834  if (rc != 0)
2835  goto out_unlock;
2836 
2837  bac.bac_flags = alloc_zone;
2838  bac.bac_criteria = 0; /* Find exact extent. */
2839  bac.bac_goal = *ext;
2840  m0_ext_init(&bac.bac_goal);
2841 
2842  if (!balloc_is_good_group(&bac, grp)) {
2843  rc = M0_ERR(-ENOSPC);
2844  M0_LOG(M0_DEBUG, "grp=%" PRIu64 " is not good", group);
2845  goto out_unlock;
2846  }
2847 
2848  if (!is_extent_free(grp, ext, alloc_zone, &cur)) {
2849  rc = M0_ERR(-EEXIST);
2850  goto out_unlock;
2851  }
2852 
2853  rc = balloc_alloc_db_update(ctx, tx, grp, ext, alloc_zone, cur);
2854 
2855 out_unlock:
2857 out:
2858  return M0_RC(rc);
2859 }
2860 
2866 static int balloc_alloc(struct m0_ad_balloc *ballroom, struct m0_dtx *tx,
2867  m0_bcount_t count, struct m0_ext *out,
2868  uint64_t alloc_zone)
2869 {
2870  struct m0_balloc *motr = b2m0(ballroom);
2871  struct m0_balloc_allocate_req req;
2872  m0_bcount_t freeblocks;
2873  int rc;
2874 
2875  M0_ENTRY("bal=%p goal=0x%lx count=%lu", motr,
2876  (unsigned long)out->e_start,
2877  (unsigned long)count);
2878  M0_PRE(count > 0);
2879 
2880  req.bar_goal = out->e_start; /* this also plays as the goal */
2881  req.bar_len = count;
2882 #ifdef __SPARE_SPACE__
2883  req.bar_flags = alloc_zone /*M0_BALLOC_HINT_DATA | M0_BALLOC_HINT_TRY_GOAL*/;
2884 #else
2885  req.bar_flags = M0_BALLOC_NORMAL_ZONE;
2886 #endif
2887 
2888  M0_SET0(out);
2889 
2890  freeblocks = motr->cb_sb.bsb_freeblocks;
2892  if (rc == 0) {
2893  if (m0_ext_is_empty(&req.bar_result)) {
2894  rc = -ENOENT;
2895  } else {
2896  out->e_start = req.bar_result.e_start;
2897  out->e_end = req.bar_result.e_end;
2898  m0_ext_init(out);
2899  m0_mutex_lock(&motr->cb_sb_mutex.bm_u.mutex);
2900  motr->cb_last = out->e_end;
2901  m0_mutex_unlock(&motr->cb_sb_mutex.bm_u.mutex);
2902  }
2903  }
2904  M0_LOG(M0_DEBUG, "BAlloc=%p rc=%d freeblocks %llu -> %llu",
2905  motr, rc,
2906  (unsigned long long)freeblocks,
2907  (unsigned long long)motr->cb_sb.bsb_freeblocks);
2908 
2909 
2910  return M0_RC(rc);
2911 }
2912 
2917 static int balloc_free(struct m0_ad_balloc *ballroom, struct m0_dtx *tx,
2918  struct m0_ext *ext)
2919 {
2920  struct m0_balloc *motr = b2m0(ballroom);
2921  struct m0_balloc_free_req req;
2922  m0_bcount_t freeblocks;
2923  int rc;
2924 
2925  req.bfr_physical = ext->e_start;
2926  req.bfr_len = m0_ext_length(ext);
2927 
2928  freeblocks = motr->cb_sb.bsb_freeblocks;
2929  rc = balloc_free_internal(motr, &tx->tx_betx, &req);
2930  M0_LOG(M0_DEBUG, "BFree=%p rc=%d freeblocks %llu -> %llu",
2931  motr, rc,
2932  (unsigned long long)freeblocks,
2933  (unsigned long long)motr->cb_sb.bsb_freeblocks);
2934  if (rc == 0)
2935  motr->cb_last = ext->e_start;
2936 
2937  return M0_RC(rc);
2938 }
2939 
2940 static int balloc_init(struct m0_ad_balloc *ballroom, struct m0_be_seg *db,
2941  uint32_t bshift, m0_bcount_t container_size,
2942  m0_bcount_t blocks_per_group,
2943  m0_bcount_t spare_blocks_per_group)
2944 {
2945  struct m0_balloc *motr;
2946  struct m0_sm_group *grp = m0_locality0_get()->lo_grp; /* XXX */
2947  int rc;
2948  M0_ENTRY();
2949 
2950  motr = b2m0(ballroom);
2951 
2953  rc = balloc_init_internal(motr, db, grp, bshift, container_size,
2954  blocks_per_group, spare_blocks_per_group);
2956 
2957  return M0_RC(rc);
2958 }
2959 
2960 static void balloc_fini(struct m0_ad_balloc *ballroom)
2961 {
2962  struct m0_balloc *motr = b2m0(ballroom);
2963 
2964  M0_ENTRY();
2965 
2967 
2968  M0_LEAVE();
2969 }
2970 
2971 static const struct m0_ad_balloc_ops balloc_ops = {
2972  .bo_init = balloc_init,
2973  .bo_fini = balloc_fini,
2974  .bo_alloc = balloc_alloc,
2975  .bo_free = balloc_free,
2976  .bo_alloc_credit = balloc_alloc_credit,
2977  .bo_free_credit = balloc_free_credit,
2978  .bo_reserve_extent = balloc_reserve_extent,
2979 };
2980 
2981 static int balloc_trees_create(struct m0_balloc *bal,
2982  struct m0_be_tx *tx,
2983  const struct m0_fid *fid)
2984 {
2985  int rc;
2986 
2989  &M0_FID_TINIT('b',
2991  fid->f_key)),
2992  bo_u.u_btree.t_rc);
2993  if (rc != 0)
2994  return M0_ERR(rc);
2995 
2999  fid->f_key)),
3000  bo_u.u_btree.t_rc);
3001 
3002  if (rc != 0) {
3003  M0_BE_OP_SYNC(op,
3005  }
3006 
3007  return M0_RC(rc);
3008 }
3009 
3010 M0_INTERNAL void m0_balloc_init(struct m0_balloc *cb)
3011 {
3012  cb->cb_ballroom.ab_ops = &balloc_ops;
3013 }
3014 
3015 M0_INTERNAL int m0_balloc_create(uint64_t cid,
3016  struct m0_be_seg *seg,
3017  struct m0_sm_group *grp,
3018  struct m0_balloc **out,
3019  const struct m0_fid *fid)
3020 {
3021  struct m0_balloc *cb;
3022  struct m0_be_btree btree = {};
3023  struct m0_be_tx tx = {};
3024  struct m0_be_tx_credit cred = {};
3025  int rc;
3026 
3027  M0_PRE(seg != NULL);
3028  M0_PRE(out != NULL);
3029 
3030  m0_be_tx_init(&tx, 0, seg->bs_domain,
3031  grp, NULL, NULL, NULL, NULL);
3032  M0_BE_ALLOC_CREDIT_PTR(cb, seg, &cred);
3034  m0_be_btree_create_credit(&btree, 1, &cred);
3037  m0_be_btree_create_credit(&btree, 1, &cred);
3039  m0_be_tx_prep(&tx, &cred);
3040  rc = m0_be_tx_open_sync(&tx);
3041 
3042  if (rc == 0) {
3043  M0_BE_ALLOC_PTR_SYNC(cb, seg, &tx);
3044  if (cb == NULL) {
3045  rc = -ENOMEM;
3046  } else {
3047  cb->cb_container_id = cid;
3048 
3049  balloc_format_init(cb);
3051  &ge_btree_ops);
3053  &gd_btree_ops);
3054  rc = balloc_trees_create(cb, &tx, fid);
3055  if (rc == 0) {
3056  M0_BE_TX_CAPTURE_PTR(seg, &tx, cb);
3057  *out = cb;
3058  } else {
3061  }
3062  }
3063  m0_be_tx_close_sync(&tx);
3064  }
3065  m0_be_tx_fini(&tx);
3066 
3067  if (rc == 0)
3068  m0_balloc_init(*out);
3069 
3070  return M0_RC(rc);
3071 }
3072 
3073 #undef M0_TRACE_SUBSYSTEM
3074 
3075 /*
3076  * Local variables:
3077  * c-indentation-style: "K&R"
3078  * c-basic-offset: 8
3079  * tab-width: 8
3080  * fill-column: 80
3081  * scroll-step: 1
3082  * End:
3083  */
static m0_bcount_t group_fragments_get(struct m0_balloc_group_info *grp)
Definition: balloc.c:133
M0_INTERNAL int m0_mutex_trylock(struct m0_mutex *mutex)
Definition: mutex.c:84
#define M0_BE_TX_CREDIT_PTR(ptr)
Definition: tx_credit.h:98
#define M0_BE_ALLOC_CREDIT_PTR(ptr, seg, accum)
Definition: alloc.h:355
struct m0_be_btree cb_db_group_desc
Definition: balloc.h:241
static size_t nr
Definition: dump.c:1505
struct m0_be_domain * bs_domain
Definition: seg.h:82
static const struct m0_be_btree_kv_ops ge_btree_ops
Definition: balloc.c:471
#define M0_PRE(cond)
M0_INTERNAL void m0_list_add(struct m0_list *head, struct m0_list_link *new)
Definition: list.c:113
#define M0_BE_ALLOC_PTR_SYNC(ptr, seg, tx)
Definition: alloc.h:339
static void balloc_group_write_do(struct m0_be_tx_bulk *tb, struct m0_be_tx *tx, struct m0_be_op *op, void *datum, void *user, uint64_t worker_index, uint64_t partition)
Definition: balloc.c:682
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
Definition: dtm.h:554
M0_INTERNAL void m0_be_btree_delete_credit(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t ksize, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1740
M0_INTERNAL m0_bcount_t m0_ext_length(const struct m0_ext *ext)
Definition: ext.c:42
M0_INTERNAL void m0_be_tx_bulk_run(struct m0_be_tx_bulk *tb, struct m0_be_op *op)
Definition: tx_bulk.c:565
M0_INTERNAL int m0_be_tx_bulk_init(struct m0_be_tx_bulk *tb, struct m0_be_tx_bulk_cfg *tb_cfg)
Definition: tx_bulk.c:136
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
uint64_t cb_container_id
Definition: balloc.h:225
static struct m0_list list
Definition: list.c:144
uint64_t ko_type
Definition: btree.h:97
M0_INTERNAL void m0_format_header_pack(struct m0_format_header *dest, const struct m0_format_tag *src)
Definition: format.c:40
m0_bindex_t e_end
Definition: ext.h:40
struct m0_balloc * bgs_bal
Definition: balloc.c:631
static void balloc_debug_dump_extent(const char *tag, struct m0_ext *ex)
Definition: balloc.c:160
struct m0_ad_balloc cb_ballroom
Definition: balloc.h:231
static const uint64_t k1
Definition: hash_fnc.c:34
M0_INTERNAL int m0_balloc_load_extents(struct m0_balloc *cb, struct m0_balloc_group_info *grp)
Definition: balloc.c:1273
M0_INTERNAL void m0_be_tx_bulk_end(struct m0_be_tx_bulk *tb)
Definition: tx_bulk.c:619
static int balloc_free_db_update(struct m0_balloc *motr, struct m0_be_tx *tx, struct m0_balloc_group_info *grp, struct m0_ext *tgt, uint64_t alloc_flag)
Definition: balloc.c:1689
#define NULL
Definition: misc.h:38
M0_INTERNAL void m0_balloc_debug_dump_sb(const char *tag, struct m0_balloc_super_block *sb)
Definition: balloc.c:212
M0_INTERNAL void m0_list_add_before(struct m0_list_link *anchor, struct m0_list_link *new)
Definition: list.c:133
static struct buffer * cur(struct m0_addb2_mach *mach, m0_bcount_t space)
Definition: addb2.c:791
Definition: idx_mock.c:52
struct m0_ext le_ext
Definition: balloc.h:145
#define ergo(a, b)
Definition: misc.h:293
static int balloc_use_best_found(struct balloc_allocation_context *bac, m0_bindex_t start)
Definition: balloc.c:1467
static int balloc_free(struct m0_ad_balloc *ballroom, struct m0_dtx *tx, struct m0_ext *ext)
Definition: balloc.c:2917
#define M0_3WAY(v0, v1)
Definition: arith.h:199
M0_INTERNAL void m0_list_init(struct m0_list *head)
Definition: list.c:29
#define M0_MEMBER_SIZE(type, member)
Definition: misc.h:62
M0_INTERNAL void m0_be_btree_lookup(struct m0_be_btree *tree, struct m0_be_op *op, const struct m0_buf *key, struct m0_buf *value)
Definition: btree.c:2033
static struct io_request req
Definition: file.c:100
static uint64_t tag(uint8_t code, uint64_t id)
Definition: addb2.c:1047
struct m0_balloc_allocate_req * bac_req
Definition: balloc.c:65
static struct m0_sm_group * grp
Definition: bytecount.c:38
static m0_bcount_t ge_tree_kv_size(const void *kv)
Definition: balloc.c:458
#define M0_LOG(level,...)
Definition: trace.h:167
M0_LEAVE()
m0_bindex_t e_start
Definition: ext.h:96
m0_bcount_t bzp_freeblocks
Definition: balloc.h:134
#define min_check(a, b)
Definition: arith.h:88
#define ENABLE_BALLOC_DUMP
Definition: config.h:18
static void balloc_group_work_put(struct m0_balloc *bal, struct m0_be_tx_bulk *tb, struct balloc_groups_write_cfg *bgs)
Definition: balloc.c:651
struct m0_balloc_group_info * cb_group_info
Definition: balloc.h:248
static int btree_insert_sync(struct m0_be_btree *tree, struct m0_be_tx *tx, const struct m0_buf *key, const struct m0_buf *val)
Definition: balloc.c:80
struct m0_be_btree cb_db_group_extents
Definition: balloc.h:239
M0_INTERNAL void m0_be_tx_fini(struct m0_be_tx *tx)
Definition: stubs.c:163
uint64_t bsb_mnt_time
Definition: balloc.h:195
static int balloc_init_ac(struct balloc_allocation_context *bac, struct m0_balloc *motr, struct m0_be_tx *tx, struct m0_balloc_allocate_req *req)
Definition: balloc.c:1007
#define max_check(a, b)
Definition: arith.h:95
#define M0_BE_OP_SYNC(op_obj, action)
Definition: op.h:190
static bool m0_is_po2(uint64_t val)
Definition: arith.h:153
#define M0_BALLOC_DEFAULT_MAX_TO_SCAN
Definition: balloc.c:2132
int(* bo_init)(struct m0_ad_balloc *ballroom, struct m0_be_seg *db, uint32_t bshift, m0_bcount_t container_size, m0_bcount_t blocks_per_group, m0_bcount_t spare_blocks_per_group)
Definition: ad.h:77
static int balloc_new_preallocation(struct balloc_allocation_context *bac)
Definition: balloc.c:1490
static const struct m0_ad_balloc_ops balloc_ops
Definition: balloc.c:2971
static void balloc_group_write_done(struct m0_be_tx_bulk *tb, void *datum, void *user, uint64_t worker_index, uint64_t partition)
Definition: balloc.c:766
static void zone_params_update(struct m0_balloc_group_info *grp, struct m0_ext *ext, uint64_t balloc_zone)
Definition: balloc.c:1261
static void balloc_free_credit(const struct m0_ad_balloc *balroom, int nr, struct m0_be_tx_credit *accum)
Definition: balloc.c:2636
M0_INTERNAL void m0_list_fini(struct m0_list *head)
Definition: list.c:36
static int balloc_is_good_group(struct balloc_allocation_context *bac, struct m0_balloc_group_info *gi)
Definition: balloc.c:2007
m0_bcount_t bgd_fragments
Definition: balloc.h:60
static int balloc_use_prealloc(struct balloc_allocation_context *bac)
Definition: balloc.c:1044
#define M0_BALLOC_DEFAULT_MIN_TO_SCAN
Definition: balloc.c:2137
#define MAX_ALLOCATION_CHUNK
Definition: balloc.c:339
M0_INTERNAL void m0_list_del(struct m0_list_link *old)
Definition: list.c:147
static int balloc_init_internal(struct m0_balloc *bal, struct m0_be_seg *seg, struct m0_sm_group *grp, uint32_t bshift, m0_bcount_t container_size, m0_bcount_t blocks_per_group, m0_bcount_t spare_blocks_per_group)
Definition: balloc.c:952
static const struct m0_be_btree_kv_ops gd_btree_ops
Definition: balloc.c:493
M0_INTERNAL void m0_be_tx_prep(struct m0_be_tx *tx, const struct m0_be_tx_credit *credit)
Definition: stubs.c:175
const struct m0_ad_balloc_ops * ab_ops
Definition: ad.h:65
#define M0_BE_TX_CAPTURE_PTR(seg, tx, ptr)
Definition: tx.h:505
uint64_t m0_bindex_t
Definition: types.h:80
static int balloc_format(struct m0_balloc *bal, struct m0_balloc_format_req *req, struct m0_sm_group *grp)
Definition: balloc.c:864
static int btree_lookup_sync(struct m0_be_btree *tree, const struct m0_buf *key, struct m0_buf *val)
Definition: balloc.c:72
static m0_bcount_t gd_tree_key_size(const void *k)
Definition: balloc.c:478
static bool is_spare(uint64_t alloc_flags)
Definition: balloc.c:1049
static int ge_tree_cmp(const void *k0, const void *k1)
Definition: balloc.c:463
uint64_t m0_bcount_t
Definition: types.h:77
m0_bcount_t bgd_maxchunk
Definition: balloc.h:62
static int balloc_regular_allocator(struct balloc_allocation_context *bac)
Definition: balloc.c:2398
M0_INTERNAL int m0_balloc_create(uint64_t cid, struct m0_be_seg *seg, struct m0_sm_group *grp, struct m0_balloc **out, const struct m0_fid *fid)
Definition: balloc.c:3015
static bool is_normal(uint64_t alloc_flags)
Definition: balloc.c:1054
M0_INTERNAL void m0_be_btree_create(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_fid *btree_fid)
Definition: btree.c:1512
#define container_of(ptr, type, member)
Definition: misc.h:33
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
struct m0_be_tx * bac_tx
Definition: balloc.c:64
static int balloc_groups_write(struct m0_balloc *bal)
Definition: balloc.c:790
static void balloc_normalize_group_request(struct balloc_allocation_context *bac)
Definition: balloc.c:1098
#define PRIx64
Definition: types.h:61
static m0_bcount_t count
Definition: xcode.c:167
struct m0_balloc * bgc_bal
Definition: balloc.c:625
M0_INTERNAL void m0_be_btree_delete(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key)
Definition: btree.c:1958
M0_INTERNAL void m0_be_btree_cursor_fini(struct m0_be_btree_cursor *cursor)
Definition: btree.c:2290
m0_bcount_t bsb_groupsize
Definition: balloc.h:187
struct m0_fid fid
Definition: di.c:46
return M0_RC(rc)
op
Definition: libdemo.c:64
struct m0_list bzp_extents
Definition: balloc.h:137
static bool is_extent_free(struct m0_balloc_group_info *grp, const struct m0_ext *tgt, uint64_t alloc_type, struct m0_ext **current)
Definition: balloc.c:1537
static int btree(struct scanner *s, struct rectype *r, char *buf)
Definition: beck.c:1270
#define M0_BE_TX_CREDIT(nr, size)
Definition: tx_credit.h:94
#define M0_ENTRY(...)
Definition: trace.h:170
static int balloc_free_internal(struct m0_balloc *ctx, struct m0_be_tx *tx, struct m0_balloc_free_req *req)
Definition: balloc.c:2649
static const uint64_t k0
Definition: hash_fnc.c:33
Definition: buf.h:37
M0_INTERNAL void m0_sm_group_unlock(struct m0_sm_group *grp)
Definition: sm.c:96
static m0_bindex_t zone_start_get(struct m0_balloc_group_info *grp, enum m0_balloc_allocation_flag alloc_flag)
Definition: balloc.c:2115
M0_INTERNAL bool m0_ext_equal(const struct m0_ext *a, const struct m0_ext *b)
Definition: ext.c:70
int i
Definition: dir.c:1033
union m0_be_mutex::@196 bm_u
m0_bcount_t bzp_maxchunk
Definition: balloc.h:136
#define PRIu64
Definition: types.h:58
M0_INTERNAL int m0_balloc_trylock_group(struct m0_balloc_group_info *grp)
Definition: balloc.c:329
struct m0_ext bac_goal
Definition: balloc.c:67
struct m0_ext bzp_range
Definition: balloc.h:133
static struct m0_list * group_spare_ext(struct m0_balloc_group_info *grp)
Definition: balloc.c:145
return M0_ERR(-EOPNOTSUPP)
static m0_bcount_t gd_tree_val_size(const void *v)
Definition: balloc.c:483
M0_INTERNAL void m0_be_btree_update_credit(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1750
#define M0_BE_OP_SYNC_RET(op_obj, action, member)
Definition: op.h:243
M0_INTERNAL void m0_balloc_lock_group(struct m0_balloc_group_info *grp)
Definition: balloc.c:324
Definition: trace.h:482
M0_INTERNAL int m0_be_tx_bulk_status(struct m0_be_tx_bulk *tb)
Definition: tx_bulk.c:630
M0_INTERNAL void m0_be_btree_create_credit(const struct m0_be_btree *tree, m0_bcount_t nr, struct m0_be_tx_credit *accum)
Definition: btree.c:1783
M0_INTERNAL void m0_be_btree_insert(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key, const struct m0_buf *val)
Definition: btree.c:1932
static m0_bcount_t group_spare_fragments_get(struct m0_balloc_group_info *grp)
Definition: balloc.c:137
#define M0_FID_TINIT(type, container, key)
Definition: fid.h:90
static int balloc_find_extent_buddy(struct balloc_allocation_context *bac, struct m0_balloc_group_info *grp, m0_bcount_t len, enum m0_balloc_allocation_flag alloc_flag, struct m0_ext *ex)
Definition: balloc.c:1400
static m0_bcount_t group_maxchunk_get(struct m0_balloc_group_info *grp)
Definition: balloc.c:125
m0_bcount_t bgc_i
Definition: balloc.c:626
static int allocate_blocks(int cr, struct balloc_allocation_context *bac, struct m0_balloc_group_info *grp, m0_bcount_t len, enum m0_balloc_allocation_flag alloc_type)
Definition: balloc.c:2540
static bool balloc_got_freespace(const struct m0_balloc *ctx, m0_bcount_t blocks, uint64_t alloc_flags)
Definition: balloc.c:1073
M0_INTERNAL void m0_be_btree_insert_credit(const struct m0_be_btree *tree, m0_bcount_t nr, m0_bcount_t ksize, m0_bcount_t vsize, struct m0_be_tx_credit *accum)
Definition: btree.c:1720
struct m0_ext bac_final
Definition: balloc.c:69
M0_INTERNAL void m0_be_tx_credit_mac(struct m0_be_tx_credit *c, const struct m0_be_tx_credit *c1, m0_bcount_t k)
Definition: tx_credit.c:88
#define m0_free0(pptr)
Definition: memory.h:77
#define m0_list_for_each_entry(head, pos, type, member)
Definition: list.h:235
static bool is_any(uint64_t alloc_flag)
Definition: balloc.c:1059
#define M0_ASSERT(cond)
M0_INTERNAL void m0_be_btree_destroy(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op)
Definition: btree.c:1538
static int gd_tree_cmp(const void *k0, const void *k1)
Definition: balloc.c:488
M0_INTERNAL bool m0_mutex_is_locked(const struct m0_mutex *mutex)
Definition: mutex.c:95
#define M0_BALLOC_DEFAULT_MAX_GROUPS_TO_SCAN
Definition: balloc.c:2142
M0_INTERNAL void m0_ext_init(struct m0_ext *ext)
Definition: ext.c:32
static int balloc_simple_scan_group(struct balloc_allocation_context *bac, struct m0_balloc_group_info *grp, enum m0_balloc_allocation_flag alloc_flag)
Definition: balloc.c:2069
static struct m0_balloc * b2m0(const struct m0_ad_balloc *ballroom)
Definition: balloc.h:265
struct m0_balloc_zone_param bgi_normal
Definition: balloc.h:156
struct m0_be_mutex cb_sb_mutex
Definition: balloc.h:250
struct m0_balloc_zone_param bgi_spare
Definition: balloc.h:157
struct m0_mutex bgs_lock
Definition: balloc.c:634
M0_INTERNAL void m0_be_tx_credit_add(struct m0_be_tx_credit *c0, const struct m0_be_tx_credit *c1)
Definition: tx_credit.c:44
M0_INTERNAL void m0_balloc_unlock_group(struct m0_balloc_group_info *grp)
Definition: balloc.c:334
M0_INTERNAL int m0_be_tx_open_sync(struct m0_be_tx *tx)
Definition: stubs.c:199
static int btree_update_sync(struct m0_be_btree *tree, struct m0_be_tx *tx, const struct m0_buf *key, const struct m0_buf *val)
Definition: balloc.c:90
M0_INTERNAL void m0_balloc_init(struct m0_balloc *cb)
Definition: balloc.c:3010
static void balloc_fini(struct m0_ad_balloc *ballroom)
Definition: balloc.c:2960
static int balloc_alloc(struct m0_ad_balloc *ballroom, struct m0_dtx *tx, m0_bcount_t count, struct m0_ext *out, uint64_t alloc_zone)
Definition: balloc.c:2866
static struct ff2c_term * alloc(void)
Definition: parser.c:37
M0_INTERNAL bool m0_ext_is_partof(const struct m0_ext *super, const struct m0_ext *sub)
Definition: ext.c:62
M0_INTERNAL void m0_balloc_debug_dump_group_extent(const char *tag, struct m0_balloc_group_info *grp)
Definition: balloc.c:192
void * m0_alloc(size_t size)
Definition: memory.c:126
m0_bcount_t tc_reg_nr
Definition: tx_credit.h:84
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
M0_INTERNAL void m0_balloc_debug_dump_group(const char *tag, struct m0_balloc_group_info *grp)
Definition: balloc.c:171
static int balloc_check_limits(struct balloc_allocation_context *bac, struct m0_balloc_group_info *grp, int end_of_group, enum m0_balloc_allocation_flag alloc_flag)
Definition: balloc.c:2145
M0_INTERNAL void m0_be_btree_fini(struct m0_be_btree *tree)
Definition: btree.c:1503
static int balloc_init(struct m0_ad_balloc *ballroom, struct m0_be_seg *db, uint32_t bshift, m0_bcount_t container_size, m0_bcount_t blocks_per_group, m0_bcount_t spare_blocks_per_group)
Definition: balloc.c:2940
m0_bcount_t bsb_stripe_size
Definition: balloc.h:201
static void lext_del(struct m0_lext *le)
Definition: balloc.c:271
struct m0_balloc * bac_ctxt
Definition: balloc.c:63
struct m0_sm_group * lo_grp
Definition: locality.h:67
static int balloc_trees_create(struct m0_balloc *bal, struct m0_be_tx *tx, const struct m0_fid *fid)
Definition: balloc.c:2981
uint64_t bgi_state
Definition: balloc.h:153
M0_INTERNAL void m0_be_op_done(struct m0_be_op *op)
Definition: stubs.c:104
static void group(void)
Definition: sm.c:386
m0_bcount_t bzp_fragments
Definition: balloc.h:135
m0_bcount_t bsb_blocksize
Definition: balloc.h:186
uint32_t bsb_gsbits
Definition: balloc.h:189
static m0_bcount_t group_spare_maxchunk_get(struct m0_balloc_group_info *grp)
Definition: balloc.c:129
static int is_group_good_enough(struct balloc_allocation_context *bac, m0_bcount_t maxchunk, m0_bcount_t free, m0_bcount_t fragments)
Definition: balloc.c:2031
Definition: seg.h:66
static void balloc_group_write_credit(struct m0_balloc *bal, struct m0_be_tx_bulk *tb, struct balloc_groups_write_cfg *bgs, struct m0_be_tx_credit *credit)
Definition: balloc.c:638
static m0_bindex_t balloc_bn2gn(m0_bindex_t blockno, struct m0_balloc *cb)
Definition: balloc.c:255
static struct m0_clink l[NR]
Definition: chan.c:37
#define EXT_P(x)
Definition: ext.h:86
struct m0_lext * bgi_extents
Definition: balloc.h:159
M0_INTERNAL bool m0_ext_is_empty(const struct m0_ext *ext)
Definition: ext.c:76
static int balloc_try_best_found(struct balloc_allocation_context *bac, enum m0_balloc_allocation_flag alloc_flag)
Definition: balloc.c:2310
uint64_t bsb_magic
Definition: balloc.h:175
static void balloc_alloc_credit(const struct m0_ad_balloc *balroom, int nr, struct m0_be_tx_credit *accum)
Definition: balloc.c:2371
M0_INTERNAL void m0_be_btree_cursor_kv_get(struct m0_be_btree_cursor *cur, struct m0_buf *key, struct m0_buf *val)
Definition: btree.c:2485
bool le_is_alloc
Definition: balloc.h:143
Definition: list.h:72
static void balloc_format_init(struct m0_balloc *cb)
Definition: balloc.c:351
M0_INTERNAL void m0_be_tx_init(struct m0_be_tx *tx, uint64_t tid, struct m0_be_domain *dom, struct m0_sm_group *sm_group, m0_be_tx_cb_t persistent, m0_be_tx_cb_t discarded, void(*filler)(struct m0_be_tx *tx, void *payload), void *datum)
Definition: stubs.c:150
m0_bcount_t bsb_groupcount
Definition: balloc.h:190
M0_INTERNAL int m0_balloc_release_extents(struct m0_balloc_group_info *grp)
Definition: balloc.c:312
M0_INTERNAL void m0_be_btree_update(struct m0_be_btree *tree, struct m0_be_tx *tx, struct m0_be_op *op, const struct m0_buf *key, const struct m0_buf *val)
Definition: btree.c:1941
static void balloc_db_update_credit(const struct m0_balloc *bal, int nr, struct m0_be_tx_credit *accum)
Definition: balloc.c:1508
M0_INTERNAL void m0_be_btree_lookup_slant(struct m0_be_btree *tree, struct m0_be_op *op, struct m0_buf *key, struct m0_buf *value)
Definition: btree.c:2041
M0_INTERNAL bool m0_be_tx_bulk_put(struct m0_be_tx_bulk *tb, struct m0_be_op *op, struct m0_be_tx_credit *credit, m0_bcount_t payload_credit, uint64_t partition, void *user)
Definition: tx_bulk.c:583
struct m0_pdclust_tgt_addr tgt
Definition: fd.c:110
static uint64_t ext_range_locate(struct m0_ext *ip_ext, struct m0_balloc_group_info *grp)
Definition: balloc.c:2728
static struct super_block sb
Definition: file.c:85
static long long min(long long a, long long b)
Definition: crate.c:191
#define EXT_F
Definition: ext.h:85
M0_INTERNAL void m0_be_op_active(struct m0_be_op *op)
Definition: stubs.c:100
M0_INTERNAL void m0_be_tx_bulk_fini(struct m0_be_tx_bulk *tb)
Definition: tx_bulk.c:288
#define M0_BUF_INIT_PTR(p)
Definition: buf.h:69
M0_INTERNAL struct m0_locality * m0_locality0_get(void)
Definition: locality.c:169
struct m0_ext bac_orig
Definition: balloc.c:66
Definition: fid.h:38
Definition: ext.h:37
uint64_t f_key
Definition: fid.h:40
m0_bindex_t e_start
Definition: ext.h:39
M0_INTERNAL void m0_format_footer_update(const void *buffer)
Definition: format.c:95
static int balloc_group_info_init(struct m0_balloc_group_info *gi, struct m0_balloc *cb)
Definition: balloc.c:361
struct m0_be_tx tx_betx
Definition: dtm.h:559
M0_INTERNAL void m0_list_add_after(struct m0_list_link *anchor, struct m0_list_link *new)
Definition: list.c:126
static int balloc_sb_write(struct m0_balloc *bal, struct m0_balloc_format_req *req, struct m0_sm_group *grp)
Definition: balloc.c:550
static int sb_update(struct m0_balloc *bal, struct m0_sm_group *grp)
Definition: balloc.c:523
static void balloc_zone_init(struct m0_balloc_zone_param *zone, uint64_t type, m0_bcount_t start, m0_bcount_t size, m0_bcount_t freeblocks, m0_bcount_t fragments, m0_bcount_t maxchunk)
Definition: balloc.c:776
struct m0_motr motr
m0_bindex_t e_end
Definition: ext.h:97
struct m0_format_header bgd_header
Definition: balloc.h:54
m0_bcount_t size
Definition: di.c:39
static int start(struct m0_fom *fom)
Definition: trigger_fom.c:321
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
M0_INTERNAL m0_bcount_t m0_stob_ad_spares_calc(m0_bcount_t grp_blocks)
Definition: ad.c:313
static int balloc_allocate_internal(struct m0_balloc *ctx, struct m0_be_tx *tx, struct m0_balloc_allocate_req *req)
Definition: balloc.c:2600
M0_INTERNAL void m0_be_btree_init(struct m0_be_btree *tree, struct m0_be_seg *seg, const struct m0_be_btree_kv_ops *ops)
Definition: btree.c:1487
static m0_bcount_t group_spare_freeblocks_get(struct m0_balloc_group_info *grp)
Definition: balloc.c:117
M0_INTERNAL void m0_be_btree_cursor_init(struct m0_be_btree_cursor *cur, struct m0_be_btree *btree)
Definition: btree.c:2281
M0_INTERNAL void m0_sm_group_lock(struct m0_sm_group *grp)
Definition: sm.c:83
uint64_t bsb_mnt_count
Definition: balloc.h:198
struct m0_ext bac_best
Definition: balloc.c:68
static m0_bcount_t group_freeblocks_get(struct m0_balloc_group_info *grp)
Definition: balloc.c:121
static struct m0_be_seg * seg
Definition: btree.c:40
struct balloc_group_write_cfg * bgs_bgc
Definition: balloc.c:630
m0_bindex_t bgi_groupno
Definition: balloc.h:155
m0_balloc_allocation_flag
Definition: balloc.h:87
static int balloc_gi_sync(struct m0_balloc *cb, struct m0_be_tx *tx, struct m0_balloc_group_info *gi)
Definition: balloc.c:901
struct m0_balloc_super_block cb_sb
Definition: balloc.h:227
M0_INTERNAL int m0_be_btree_cursor_get_sync(struct m0_be_btree_cursor *cur, const struct m0_buf *key, bool slant)
Definition: btree.c:2331
static uint64_t found
Definition: base.c:376
static void extents_release(struct m0_balloc_group_info *grp, enum m0_balloc_allocation_flag zone_type)
Definition: balloc.c:292
m0_balloc_allocation_status
Definition: balloc.c:50
static int btree_delete_sync(struct m0_be_btree *tree, struct m0_be_tx *tx, const struct m0_buf *key)
Definition: balloc.c:100
static int balloc_group_info_load(struct m0_balloc *bal)
Definition: balloc.c:409
__attribute__((unused))
Definition: balloc.c:2122
Definition: nucleus.c:42
static void balloc_sb_sync(struct m0_balloc *cb, struct m0_be_tx *tx)
Definition: balloc.c:500
#define out(...)
Definition: gen.c:41
static int balloc_alloc_db_update(struct m0_balloc *motr, struct m0_be_tx *tx, struct m0_balloc_group_info *grp, struct m0_ext *tgt, uint64_t alloc_type, struct m0_ext *cur)
Definition: balloc.c:1558
int type
Definition: dir.c:1031
m0_bindex_t bgd_groupno
Definition: balloc.h:56
static int balloc_reserve_extent(struct m0_ad_balloc *ballroom, struct m0_be_tx *tx, struct m0_ext *ext, uint64_t alloc_zone)
Definition: balloc.c:2796
static struct m0_list_link * m0_list_first(const struct m0_list *head)
Definition: list.h:191
M0_INTERNAL void m0_list_add_tail(struct m0_list *head, struct m0_list_link *new)
Definition: list.c:119
m0_bindex_t bgd_groupno
Definition: balloc.h:636
static void balloc_fini_internal(struct m0_balloc *bal)
Definition: balloc.c:434
M0_INTERNAL struct m0_balloc_group_info * m0_balloc_gn2info(struct m0_balloc *cb, m0_bindex_t groupno)
Definition: balloc.c:260
Definition: op.h:74
static struct m0_list * group_normal_ext(struct m0_balloc_group_info *grp)
Definition: balloc.c:141
static void balloc_normalize_request(struct balloc_allocation_context *bac)
Definition: balloc.c:1107
static void balloc_gi_sync_credit(const struct m0_balloc *cb, struct m0_be_tx_credit *accum)
Definition: balloc.c:894
struct m0_be_seg * cb_be_seg
Definition: balloc.h:251
static int sb_mount(struct m0_balloc *bal, struct m0_sm_group *grp)
Definition: balloc.c:935
struct m0_list_link le_link
Definition: balloc.h:144
m0_bcount_t bgd_freeblocks
Definition: balloc.h:58
void m0_free(void *data)
Definition: memory.c:146
Definition: mutex.h:47
uint64_t bsb_state
Definition: balloc.h:176
static void balloc_group_info_fini(struct m0_balloc_group_info *gi)
Definition: balloc.c:402
static int balloc_wild_scan_group(struct balloc_allocation_context *bac, struct m0_balloc_group_info *grp, enum m0_balloc_allocation_flag alloc_flag)
Definition: balloc.c:2234
int32_t rc
Definition: trigger_fop.h:47
static struct m0_mutex * bgi_mutex(struct m0_balloc_group_info *grp)
Definition: balloc.c:266
static bool is_free_space_unavailable(struct m0_balloc_group_info *grp, uint64_t alloc_flags)
Definition: balloc.c:2385
#define m0_list_entry(link, type, member)
Definition: list.h:217
static void balloc_sb_sync_credit(const struct m0_balloc *bal, struct m0_be_tx_credit *accum)
Definition: balloc.c:1500
M0_INTERNAL void m0_balloc_group_desc_init(struct m0_balloc_group_desc *desc)
Definition: balloc.c:341
m0_bcount_t bgs_max
Definition: balloc.c:632
enum m0_balloc_allocation_flag bzp_type
Definition: balloc.h:132
struct m0_mutex mutex
Definition: format.h:199
static int balloc_measure_extent(struct balloc_allocation_context *bac, struct m0_balloc_group_info *grp, enum m0_balloc_allocation_flag alloc_flag, struct m0_ext *ex, int end_of_group)
Definition: balloc.c:2183
m0_bcount_t tc_reg_size
Definition: tx_credit.h:86
struct m0_format_header cb_header
Definition: balloc.h:222
Definition: trace.h:478
static struct m0_lext * lext_create(struct m0_ext *ex)
Definition: balloc.c:278
M0_INTERNAL void m0_be_tx_close_sync(struct m0_be_tx *tx)
Definition: stubs.c:205
Definition: tx.h:280
Definition: idx_mock.c:47