Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / os / bluestore / BitAllocator.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2
3 // vim: ts=8 sw=2 smarttab
4 /*
5  * Bitmap based in-memory allocator.
6  * Author: Ramesh Chander, Ramesh.Chander@sandisk.com
7  *
8  * BitMap Tree Design:
9  * Storage is divided into bitmap of blocks. Each bitmap has size of
10  * unsigned long. Group of bitmap creates a Zone. Zone is a unit where
11  * at a time single thread can be active as well as single biggest
12  * contiguous allocation that can be requested.
13  *
14  * Rest of the nodes are classified into three categories:
15  *   root node or Allocator
16  *   internal nodes or BitMapAreaIN
17  *   final nodes that contains Zones called BitMapAreaLeaf
18  * This classification is according to their own implmentation of some
19  * of the interfaces defined in BitMapArea.
20  */
21
22 #include "BitAllocator.h"
23 #include <assert.h>
24 #include "bluestore_types.h"
25 #include "common/debug.h"
26 #include <math.h>
27
28 #define dout_context cct
29 #define dout_subsys ceph_subsys_bluestore
30 #undef dout_prefix
31 #define dout_prefix *_dout << "bitalloc:"
32
33 MEMPOOL_DEFINE_OBJECT_FACTORY(BitMapArea, BitMapArea, bluestore_alloc);
34 MEMPOOL_DEFINE_OBJECT_FACTORY(BitMapAreaIN, BitMapAreaIN, bluestore_alloc);
35 MEMPOOL_DEFINE_OBJECT_FACTORY(BitMapAreaLeaf, BitMapAreaLeaf, bluestore_alloc);
36 MEMPOOL_DEFINE_OBJECT_FACTORY(BitMapZone, BitMapZone, bluestore_alloc);
37 MEMPOOL_DEFINE_OBJECT_FACTORY(BmapEntry, BmapEntry, bluestore_alloc);
38 MEMPOOL_DEFINE_OBJECT_FACTORY(BitAllocator, BitAllocator, bluestore_alloc);
39
40 int64_t BitMapAreaLeaf::count = 0;
41 int64_t BitMapZone::count = 0;
42 int64_t BitMapZone::total_blocks = 0;
43
44
45
46 int64_t BmapEntityListIter::index()
47 {
48   return m_cur_idx;
49 }
50
51 BmapEntry::BmapEntry(CephContext*, const bool full)
52 {
53   if (full) {
54     m_bits = BmapEntry::full_bmask();
55   } else {
56     m_bits = BmapEntry::empty_bmask();
57   }
58 }
59
60 BmapEntry::~BmapEntry()
61 {
62
63 }
64
65 bool BmapEntry::check_bit(int bit)
66 {
67   return (atomic_fetch() & bit_mask(bit));
68 }
69
70 bool BmapEntry::is_allocated(int64_t offset, int64_t num_bits)
71 {
72   bmap_t bmask = BmapEntry::align_mask(num_bits) >> offset;
73   return ((m_bits & bmask) == bmask);
74 }
75
76 void BmapEntry::clear_bit(int bit)
77 {
78   bmap_t bmask = bit_mask(bit);
79   m_bits &= ~(bmask);
80 }
81
82 void BmapEntry::clear_bits(int offset, int num_bits)
83 {
84   if (num_bits == 0) {
85     return;
86   }
87
88   bmap_t bmask = BmapEntry::align_mask(num_bits) >> offset;
89   m_bits &= ~(bmask);
90 }
91
92 void BmapEntry::set_bits(int offset, int num_bits)
93 {
94   if (num_bits == 0) {
95     return;
96   }
97
98   bmap_t bmask = BmapEntry::align_mask(num_bits) >> offset;
99   m_bits |= bmask;
100 }
101
102 /*
103  * Allocate a bit if it was free.
104  * Retruns true if it was free.
105  */
106 bool BmapEntry::check_n_set_bit(int bit)
107 {
108   bmap_t bmask = bit_mask(bit);
109   bool res = !(m_bits & bmask);
110   m_bits |= bmask;
111   return res;
112 }
113
114 /*
115  * Find N cont free bits in BitMap starting from an offset.
116  *
117  * Returns number of continuous bits found.
118  */
119 int BmapEntry::find_n_cont_bits(int start_offset, int64_t num_bits)
120 {
121   int count = 0;
122   int i = 0;
123
124   if (num_bits == 0) {
125     return 0;
126   }
127
128   if (start_offset >= BmapEntry::size()) {
129     return 0;
130   }
131
132   for (i = start_offset; i < BmapEntry::size() && count < num_bits; i++) {
133     if (!check_n_set_bit(i)) {
134       break;
135     }
136     count++;
137   }
138
139   return count;
140 }
141
142 /*
143  * Find N free bits starting search from a given offset.
144  *
145  * Returns number of bits found, start bit and end of
146  * index next to bit where our search ended + 1.
147  */
148 int BmapEntry::find_n_free_bits(int start_idx, int64_t max_bits,
149          int *free_bit, int *end_idx)
150 {
151   int i = 0;
152   int count = 0;
153
154   *free_bit = 0;
155   alloc_assert(max_bits > 0);
156
157   /*
158    * Find free bit aligned to bit_align return the bit_num in free_bit.
159    */
160   if (atomic_fetch() == BmapEntry::full_bmask()) {
161     /*
162      * All bits full, return fail.
163      */
164     *end_idx = BmapEntry::size();
165     return 0;
166   }
167
168   /*
169    * Do a serial scan on bitmap.
170    */
171   for (i = start_idx; i < BmapEntry::size(); i++) {
172     if (check_n_set_bit(i)) {
173       /*
174        * Found first free bit
175        */
176       *free_bit = i;
177       count++;
178       break;
179     }
180   }
181   count += find_n_cont_bits(i + 1, max_bits - 1);
182
183   (*end_idx) = i + count;
184   return count;
185 }
186
187 /*
188  * Find first series of contiguous bits free in bitmap starting
189  * from start offset that either
190  * satisfy our need or are touching right edge of bitmap.
191  *
192  * Returns allocated bits, start bit of allocated, number of bits
193  * scanned from start offset.
194  */
195 int
196 BmapEntry::find_first_set_bits(int64_t required_blocks,
197           int bit_offset, int *start_offset,
198           int64_t *scanned)
199 {
200   int allocated = 0;
201   int conti = 0;
202   int end_idx = 0;
203
204   *scanned = 0;
205
206   while (bit_offset < BmapEntry::size()) {
207     conti = find_n_free_bits(bit_offset, required_blocks,
208            start_offset, &end_idx);
209
210     *scanned += end_idx - bit_offset;
211     /*
212      * Either end of bitmap or got required.
213      */
214     if (conti == required_blocks ||
215         (conti + *start_offset == BmapEntry::size())) {
216       allocated += conti;
217       break;
218     }
219
220     /*
221      * Did not get expected, search from next index again.
222      */
223     clear_bits(*start_offset, conti);
224     allocated = 0;
225
226     bit_offset = end_idx;
227   }
228
229   return allocated;
230 }
231
232 void BmapEntry::dump_state(CephContext* const cct, const int& count)
233 {
234   dout(0) << count << ":: 0x" << std::hex << m_bits << std::dec << dendl;
235 }
236
237 /*
238  * Zone related functions.
239  */
240 void BitMapZone::init(CephContext* const cct,
241                       const int64_t zone_num,
242                       const int64_t total_blocks,
243                       const bool def)
244 {
245   m_area_index = zone_num;
246   BitMapZone::total_blocks = total_blocks;
247   alloc_assert(size() > 0);
248
249   m_used_blocks = def? total_blocks: 0;
250
251   int64_t num_bmaps = total_blocks / BmapEntry::size();
252   alloc_assert(num_bmaps < std::numeric_limits<int16_t>::max());
253   alloc_assert(total_blocks < std::numeric_limits<int32_t>::max());
254   alloc_assert(!(total_blocks % BmapEntry::size()));
255
256   m_bmap_vec.resize(num_bmaps, BmapEntry(cct, def));
257   incr_count();
258 }
259
260 int64_t BitMapZone::sub_used_blocks(int64_t num_blocks)
261 {
262   return std::atomic_fetch_sub(&m_used_blocks, (int32_t) num_blocks);
263 }
264
265 int64_t BitMapZone::add_used_blocks(int64_t num_blocks)
266 {
267   return std::atomic_fetch_add(&m_used_blocks, (int32_t)num_blocks) + num_blocks;
268 }
269
270 /* Intensionally hinted because BitMapAreaLeaf::child_check_n_lock. */
271 inline int64_t BitMapZone::get_used_blocks()
272 {
273   return std::atomic_load(&m_used_blocks);
274 }
275
276 bool BitMapZone::reserve_blocks(int64_t num_blocks)
277 {
278   ceph_abort();
279   return false;
280 }
281
282 void BitMapZone::unreserve(int64_t num_blocks, int64_t allocated)
283 {
284   ceph_abort();
285 }
286
287 int64_t BitMapZone::get_reserved_blocks()
288 {
289   ceph_abort();
290   return 0;
291 }
292
293 BitMapZone::BitMapZone(CephContext* cct, int64_t total_blocks,
294                        int64_t zone_num)
295   : BitMapArea(cct)
296 {
297   init(cct, zone_num, total_blocks, false);
298 }
299
300 BitMapZone::BitMapZone(CephContext* cct, int64_t total_blocks,
301                        int64_t zone_num, bool def)
302   : BitMapArea(cct)
303 {
304   init(cct, zone_num, total_blocks, def);
305 }
306
307 void BitMapZone::shutdown()
308 {
309 }
310
311 BitMapZone::~BitMapZone()
312 {
313 }
314
315 /*
316  * Check if some search took zone marker to end.
317  *
318  * The inline hint has been added intensionally because of importance of this
319  * method for BitMapAreaLeaf::child_check_n_lock, and thus for the overall
320  * allocator's performance. Examination of disassemblies coming from GCC 5.4.0
321  * showed that the compiler really needs that hint.
322  */
323 inline bool BitMapZone::is_exhausted()
324 {
325   /* BitMapZone::get_used_blocks operates atomically. No need for lock. */
326   return BitMapZone::get_used_blocks() == BitMapZone::size();
327 }
328
329 bool BitMapZone::is_allocated(int64_t start_block, int64_t num_blocks)
330 {
331   BmapEntry *bmap = NULL;
332   int bit = 0;
333   int64_t falling_in_bmap = 0;
334
335   while (num_blocks) {
336     bit = start_block % BmapEntry::size();
337     bmap = &m_bmap_vec[start_block / BmapEntry::size()];
338     falling_in_bmap = MIN(num_blocks, BmapEntry::size() - bit);
339
340     if (!bmap->is_allocated(bit, falling_in_bmap)) {
341       return false;
342     }
343
344     start_block += falling_in_bmap;
345     num_blocks -= falling_in_bmap;
346   }
347
348   return true;
349 }
350
351 void BitMapZone::set_blocks_used(int64_t start_block, int64_t num_blocks)
352 {
353   BmapEntry *bmap = NULL;
354   int bit = 0;
355   int64_t falling_in_bmap = 0;
356   int64_t blks = num_blocks;
357
358   while (blks) {
359     bit = start_block % BmapEntry::size();
360     bmap = &m_bmap_vec[start_block / BmapEntry::size()];
361     falling_in_bmap = MIN(blks, BmapEntry::size() - bit);
362
363     bmap->set_bits(bit, falling_in_bmap);
364
365     start_block += falling_in_bmap;
366     blks -= falling_in_bmap;
367   }
368   add_used_blocks(num_blocks);
369 }
370
371 void BitMapZone::free_blocks_int(int64_t start_block, int64_t num_blocks)
372 {
373   BmapEntry *bmap = NULL;
374   int bit = 0;
375   int64_t falling_in_bmap = 0;
376   int64_t count = num_blocks;
377   int64_t first_blk = start_block;
378   
379   if (num_blocks == 0) {
380     return; 
381   }
382   alloc_dbg_assert(is_allocated(start_block, num_blocks));
383
384   while (count) {
385     bit = first_blk % BmapEntry::size();
386     bmap = &m_bmap_vec[first_blk / BmapEntry::size()];
387     falling_in_bmap = MIN(count, BmapEntry::size() - bit);
388
389     bmap->clear_bits(bit, falling_in_bmap);
390
391     first_blk += falling_in_bmap;
392     count -= falling_in_bmap;
393   }
394   alloc_dbg_assert(!is_allocated(start_block, num_blocks));
395 }
396
397 void BitMapZone::lock_excl()
398 {
399   m_lock.lock();
400 }
401
402 bool BitMapZone::lock_excl_try()
403 {
404   return m_lock.try_lock();
405 }
406
407 void BitMapZone::unlock()
408 {
409   m_lock.unlock();
410 }
411
412 bool BitMapZone::check_locked()
413 {
414   return !lock_excl_try();
415 }
416
417 void BitMapZone::free_blocks(int64_t start_block, int64_t num_blocks)
418 {
419   free_blocks_int(start_block, num_blocks);
420   sub_used_blocks(num_blocks);
421   alloc_assert(get_used_blocks() >= 0);
422 }
423
424 int64_t BitMapZone::alloc_blocks_dis(int64_t num_blocks,
425            int64_t min_alloc,
426      int64_t hint,
427      int64_t zone_blk_off, 
428      ExtentList *alloc_blocks)
429 {
430   int64_t bmap_idx = hint / BmapEntry::size();
431   int bit = hint % BmapEntry::size();
432   BmapEntry *bmap = NULL;
433   int64_t allocated = 0;
434   int64_t blk_off = 0;
435   int64_t alloc_cont = 0;
436   int64_t last_cont = 0;
437   int64_t last_running_ext = 0;
438   int search_idx = bit;
439   int64_t scanned = 0;
440   int start_off = 0;
441   
442
443   alloc_assert(check_locked());
444
445   BitMapEntityIter <BmapEntry> iter = BitMapEntityIter<BmapEntry>(
446           &m_bmap_vec, bmap_idx);
447   bmap = iter.next();
448   if (!bmap) {
449     return 0;
450   }
451
452   while (allocated < num_blocks) {
453     blk_off = zone_blk_off + bmap_idx * bmap->size();
454     if (last_cont) {
455       /*
456        * We had bits free at end of last bitmap, try to complete required
457        * min alloc size using that.
458        */
459       alloc_cont = bmap->find_n_cont_bits(0, min_alloc - last_cont);
460       allocated += alloc_cont;
461       last_cont += alloc_cont;
462       
463       if (!alloc_cont) {
464         if (last_cont) {
465           this->free_blocks_int(last_running_ext - zone_blk_off, last_cont);
466         }
467         allocated -= last_cont;
468         last_cont = 0;
469       } else if (last_cont / min_alloc) {
470           /*
471            * Got contiguous min_alloc_size across bitmaps.
472            */
473           alloc_blocks->add_extents(last_running_ext, last_cont);
474           last_cont = 0;
475           last_running_ext = 0;
476       }
477       search_idx = alloc_cont;
478     } else {
479       /*
480        * Try to allocate  min_alloc_size bits from given bmap.
481        */
482       alloc_cont = bmap->find_first_set_bits(min_alloc, search_idx, &start_off, &scanned);
483       search_idx = search_idx + scanned;
484       allocated += alloc_cont;
485       if (alloc_cont / min_alloc) {
486         /*
487          * Got contiguous min_alloc_size within a bitmap.
488          */
489         alloc_blocks->add_extents(blk_off + start_off, min_alloc);
490       }
491       
492       if (alloc_cont % min_alloc) {
493         /*
494          * Got some bits at end of bitmap, carry them to try match with
495          * start bits from next bitmap.
496          */
497         if (!last_cont) {
498           last_running_ext = blk_off + start_off;
499         } 
500         last_cont += alloc_cont % min_alloc;
501       }
502     }
503   
504    
505     if (search_idx == BmapEntry::size()) {
506       search_idx = 0;
507       bmap_idx = iter.index();
508       if ((bmap = iter.next()) == NULL) {
509         if (last_cont) {
510           this->free_blocks_int(last_running_ext - zone_blk_off, last_cont);
511         }
512         allocated -= last_cont;
513         break;
514       }
515     }
516   }
517
518   add_used_blocks(allocated);
519   return allocated;
520 }
521
522
523
524 void BitMapZone::dump_state(CephContext* const cct, int& count)
525 {
526   BmapEntry *bmap = NULL;
527   int bmap_idx = 0;
528   BitMapEntityIter <BmapEntry> iter = BitMapEntityIter<BmapEntry>(
529           &m_bmap_vec, 0);
530   dout(0) << __func__ << " zone " << count << " dump start " << dendl;
531   while ((bmap = static_cast<BmapEntry *>(iter.next()))) {
532     bmap->dump_state(cct, bmap_idx);
533     bmap_idx++;
534   }
535   dout(0) << __func__ << " zone " << count << " dump end " << dendl;
536   count++;
537 }
538
539
540 /*
541  * BitMapArea Leaf and non-Leaf functions.
542  */
543 int64_t BitMapArea::get_zone_size(CephContext* cct)
544 {
545   return cct->_conf->bluestore_bitmapallocator_blocks_per_zone;
546 }
547
548 int64_t BitMapArea::get_span_size(CephContext* cct)
549 {
550   return cct->_conf->bluestore_bitmapallocator_span_size;
551 }
552
553 int BitMapArea::get_level(CephContext* cct, int64_t total_blocks)
554 {
555   int level = 1;
556   int64_t zone_size_block = get_zone_size(cct);
557   int64_t span_size = get_span_size(cct);
558   int64_t spans = zone_size_block * span_size;
559   while (spans < total_blocks) {
560     spans *= span_size;
561     level++;
562   }
563   return level;
564 }
565
566 int64_t BitMapArea::get_level_factor(CephContext* cct, int level)
567 {
568   alloc_assert(level > 0);
569
570   int64_t zone_size = get_zone_size(cct);
571   if (level == 1) {
572     return zone_size;
573   }
574
575   int64_t level_factor = zone_size;
576   int64_t span_size = get_span_size(cct);
577   while (--level) {
578     level_factor *= span_size;
579   }
580
581   return level_factor;
582 }
583
584 int64_t BitMapArea::get_index()
585 {
586   return m_area_index;
587 }
588
589 /*
590  * BitMapArea Leaf and Internal
591  */
592 BitMapAreaIN::BitMapAreaIN(CephContext* cct)
593   : BitMapArea(cct)
594 {
595   // nothing
596 }
597
598 void BitMapAreaIN::init_common(CephContext* const cct,
599                                const int64_t total_blocks,
600                                const int64_t area_idx,
601                                const bool def)
602 {
603   m_area_index = area_idx;
604   m_total_blocks = total_blocks;
605   m_level = BitMapArea::get_level(cct, total_blocks);
606   m_reserved_blocks = 0;
607
608   m_used_blocks = def? total_blocks: 0;
609 }
610
611 void BitMapAreaIN::init(CephContext* const cct,
612                         int64_t total_blocks,
613                         const int64_t area_idx,
614                         const bool def)
615 {
616   int64_t num_child = 0;
617   alloc_assert(!(total_blocks % BmapEntry::size()));
618
619   init_common(cct, total_blocks, area_idx, def);
620   int64_t level_factor = BitMapArea::get_level_factor(cct, m_level);
621
622   num_child = (total_blocks + level_factor - 1) / level_factor;
623   alloc_assert(num_child < std::numeric_limits<int16_t>::max());
624
625   m_child_size_blocks = level_factor;
626
627   std::vector<BitMapArea*> children;
628   children.reserve(num_child);
629   int i = 0;
630   for (i = 0; i < num_child - 1; i++) {
631     if (m_level <= 2) {
632       children.push_back(new BitMapAreaLeaf(cct, m_child_size_blocks, i, def));
633     } else {
634       children.push_back(new BitMapAreaIN(cct, m_child_size_blocks, i, def));
635     }
636     total_blocks -= m_child_size_blocks;
637   }
638
639   int last_level = BitMapArea::get_level(cct, total_blocks);
640   if (last_level == 1) {
641     children.push_back(new BitMapAreaLeaf(cct, total_blocks, i, def));
642   } else {
643     children.push_back(new BitMapAreaIN(cct, total_blocks, i, def));
644   }
645   m_child_list = BitMapAreaList(std::move(children));
646 }
647
648 BitMapAreaIN::BitMapAreaIN(CephContext* cct,int64_t total_blocks,
649                            int64_t area_idx)
650   : BitMapArea(cct)
651 {
652   init(cct, total_blocks, area_idx, false);
653 }
654
655 BitMapAreaIN::BitMapAreaIN(CephContext* cct, int64_t total_blocks,
656                            int64_t area_idx, bool def)
657   : BitMapArea(cct)
658 {
659   init(cct, total_blocks, area_idx, def);
660 }
661
662 BitMapAreaIN::~BitMapAreaIN()
663 {
664 }
665
666 void BitMapAreaIN::shutdown()
667 {
668   lock_excl();
669   m_total_blocks = -1;
670   m_area_index = -2;
671   unlock();
672 }
673
674 bool BitMapAreaIN::child_check_n_lock(BitMapArea *child, int64_t required)
675 {
676   child->lock_shared();
677
678   if (child->is_exhausted()) {
679     child->unlock();
680     return false;
681   }
682
683   int64_t child_used_blocks = child->get_used_blocks();
684   int64_t child_total_blocks = child->size();
685   if ((child_total_blocks - child_used_blocks) < required) {
686     child->unlock();
687     return false;
688   }
689
690   return true;
691 }
692
693 void BitMapAreaIN::child_unlock(BitMapArea *child)
694 {
695   child->unlock();
696 }
697
698 bool BitMapAreaIN::is_exhausted()
699 {
700   return get_used_blocks() == size();
701 }
702
703 int64_t BitMapAreaIN::add_used_blocks(int64_t blks)
704 {
705   std::lock_guard<std::mutex> l(m_blocks_lock);
706   m_used_blocks += blks;
707   return m_used_blocks;
708 }
709
710 int64_t BitMapAreaIN::sub_used_blocks(int64_t num_blocks)
711 {
712   std::lock_guard<std::mutex> l(m_blocks_lock);
713
714   int64_t used_blks = m_used_blocks;
715   m_used_blocks -= num_blocks;
716   alloc_assert(m_used_blocks >= 0);
717   return used_blks;
718 }
719
720 int64_t BitMapAreaIN::get_used_blocks()
721 {
722   std::lock_guard<std::mutex> l(m_blocks_lock);
723   return m_used_blocks;
724 }
725
726 int64_t BitMapAreaIN::get_used_blocks_adj()
727 {
728   std::lock_guard<std::mutex> l(m_blocks_lock);
729   return m_used_blocks - m_reserved_blocks;
730 }
731
732 bool BitMapAreaIN::reserve_blocks(int64_t num)
733 {
734   bool res = false;
735   std::lock_guard<std::mutex> u_l(m_blocks_lock);
736   if (m_used_blocks + num <= size()) {
737     m_used_blocks += num;
738     m_reserved_blocks += num;
739     res = true;
740   }
741   alloc_assert(m_used_blocks <= size());
742   return res;
743 }
744
745 void BitMapAreaIN::unreserve(int64_t needed, int64_t allocated)
746 {
747   std::lock_guard<std::mutex> l(m_blocks_lock);
748   m_used_blocks -= (needed - allocated);
749   m_reserved_blocks -= needed;
750   alloc_assert(m_used_blocks >= 0);
751   alloc_assert(m_reserved_blocks >= 0);
752 }
753 int64_t BitMapAreaIN::get_reserved_blocks()
754 {
755   std::lock_guard<std::mutex> l(m_blocks_lock); 
756   return m_reserved_blocks;
757 }
758
759 bool BitMapAreaIN::is_allocated(int64_t start_block, int64_t num_blocks)
760 {
761   BitMapArea *area = NULL;
762   int64_t area_block_offset = 0;
763   int64_t falling_in_area = 0;
764
765   alloc_assert(start_block >= 0 &&
766       (start_block + num_blocks <= size()));
767
768   if (num_blocks == 0) {
769     return true;
770   }
771
772   while (num_blocks) {
773     area = static_cast<BitMapArea *>(m_child_list.get_nth_item(
774                     start_block / m_child_size_blocks));
775
776     area_block_offset = start_block % m_child_size_blocks;
777     falling_in_area = MIN(m_child_size_blocks - area_block_offset,
778               num_blocks);
779     if (!area->is_allocated(area_block_offset, falling_in_area)) {
780       return false;
781     }
782     start_block += falling_in_area;
783     num_blocks -= falling_in_area;
784   }
785   return true;
786 }
787
788 int64_t BitMapAreaIN::alloc_blocks_dis_int_work(bool wrap, int64_t num_blocks, int64_t min_alloc, 
789            int64_t hint, int64_t area_blk_off, ExtentList *block_list)
790 {
791   BitMapArea *child = NULL;
792   int64_t allocated = 0;
793   int64_t blk_off = 0;
794
795   BmapEntityListIter iter = BmapEntityListIter(
796         &m_child_list, hint / m_child_size_blocks, wrap);
797
798   while ((child = static_cast<BitMapArea *>(iter.next()))) {
799     if (!child_check_n_lock(child, 1)) {
800       hint = 0;
801       continue;
802     }
803
804     blk_off = child->get_index() * m_child_size_blocks + area_blk_off;
805     allocated += child->alloc_blocks_dis(num_blocks - allocated, min_alloc,
806                             hint % m_child_size_blocks, blk_off, block_list);
807     hint = 0;
808     child_unlock(child);
809     if (allocated == num_blocks) {
810       break;
811     }
812   }
813
814   return allocated;
815 }
816
817 int64_t BitMapAreaIN::alloc_blocks_dis_int(int64_t num_blocks, int64_t min_alloc,
818                        int64_t hint, int64_t area_blk_off, ExtentList *block_list)
819 {
820   return alloc_blocks_dis_int_work(false, num_blocks, min_alloc, hint,
821                      area_blk_off, block_list);
822 }
823
824 int64_t BitMapAreaIN::alloc_blocks_dis(int64_t num_blocks, int64_t min_alloc,
825            int64_t hint, int64_t blk_off, ExtentList *block_list)
826 {
827   int64_t allocated = 0;
828
829   lock_shared();
830   allocated += alloc_blocks_dis_int(num_blocks, min_alloc, hint, blk_off, block_list);
831   add_used_blocks(allocated);
832
833   unlock();
834   return allocated;
835 }
836
837
838 void BitMapAreaIN::set_blocks_used_int(int64_t start_block, int64_t num_blocks)
839 {
840   BitMapArea *child = NULL;
841   int64_t child_block_offset = 0;
842   int64_t falling_in_child = 0;
843   int64_t blks = num_blocks;
844   int64_t start_blk = start_block;
845
846   alloc_assert(start_block >= 0);
847
848   while (blks) {
849     child = static_cast<BitMapArea *>(m_child_list.get_nth_item(
850                   start_blk / m_child_size_blocks));
851
852     child_block_offset = start_blk % child->size();
853     falling_in_child = MIN(m_child_size_blocks - child_block_offset,
854               blks);
855     child->set_blocks_used(child_block_offset, falling_in_child);
856     start_blk += falling_in_child;
857     blks -= falling_in_child;
858   }
859
860   add_used_blocks(num_blocks);
861   alloc_dbg_assert(is_allocated(start_block, num_blocks));
862 }
863
864 void BitMapAreaIN::set_blocks_used(int64_t start_block, int64_t num_blocks)
865 {
866   if (num_blocks == 0) {
867     return;
868   }
869
870   lock_shared();
871   set_blocks_used_int(start_block, num_blocks);
872   unlock();
873 }
874
875 void BitMapAreaIN::free_blocks_int(int64_t start_block, int64_t num_blocks)
876 {
877   BitMapArea *child = NULL;
878   int64_t child_block_offset = 0;
879   int64_t falling_in_child = 0;
880
881   alloc_assert(start_block >= 0 &&
882     (start_block + num_blocks) <= size());
883
884   if (num_blocks == 0) {
885     return;
886   }
887
888   while (num_blocks) {
889     child = static_cast<BitMapArea *>(m_child_list.get_nth_item(
890           start_block / m_child_size_blocks));
891
892     child_block_offset = start_block % m_child_size_blocks;
893
894     falling_in_child = MIN(m_child_size_blocks - child_block_offset,
895               num_blocks);
896     child->free_blocks(child_block_offset, falling_in_child);
897     start_block += falling_in_child;
898     num_blocks -= falling_in_child;
899   }
900
901 }
902 void BitMapAreaIN::free_blocks(int64_t start_block, int64_t num_blocks)
903 {
904   if (num_blocks == 0) {
905     return;
906   }
907   lock_shared();
908   alloc_dbg_assert(is_allocated(start_block, num_blocks));
909
910   free_blocks_int(start_block, num_blocks);
911   (void) sub_used_blocks(num_blocks);
912
913   unlock();
914 }
915
916 void BitMapAreaIN::dump_state(CephContext* const cct, int& count)
917 {
918   BitMapArea *child = NULL;
919
920   BmapEntityListIter iter = BmapEntityListIter(
921         &m_child_list, 0, false);
922
923   while ((child = static_cast<BitMapArea *>(iter.next()))) {
924     child->dump_state(cct, count);
925   }
926 }
927
928 /*
929  * BitMapArea Leaf
930  */
931 BitMapAreaLeaf::BitMapAreaLeaf(CephContext* cct, int64_t total_blocks,
932                                int64_t area_idx)
933   : BitMapAreaIN(cct)
934 {
935   init(cct, total_blocks, area_idx, false);
936 }
937
938 BitMapAreaLeaf::BitMapAreaLeaf(CephContext* cct, int64_t total_blocks,
939                                int64_t area_idx, bool def)
940   : BitMapAreaIN(cct)
941 {
942   init(cct, total_blocks, area_idx, def);
943 }
944
945 void BitMapAreaLeaf::init(CephContext* const cct,
946                           const int64_t total_blocks,
947                           const int64_t area_idx,
948                           const bool def)
949 {
950   int64_t num_child = 0;
951   alloc_assert(!(total_blocks % BmapEntry::size()));
952
953   init_common(cct, total_blocks, area_idx, def);
954   alloc_assert(m_level == 1);
955   int zone_size_block = get_zone_size(cct);
956   alloc_assert(zone_size_block > 0);
957   num_child = (total_blocks + zone_size_block - 1) / zone_size_block;
958   alloc_assert(num_child);
959   m_child_size_blocks = total_blocks / num_child;
960
961   std::vector<BitMapArea*> children;
962   children.reserve(num_child);
963   for (int i = 0; i < num_child; i++) {
964     children.emplace_back(new BitMapZone(cct, m_child_size_blocks, i, def));
965   }
966
967   m_child_list = BitMapAreaList(std::move(children));
968
969   BitMapAreaLeaf::incr_count();
970 }
971
972 BitMapAreaLeaf::~BitMapAreaLeaf()
973 {
974   lock_excl();
975
976   for (int64_t i = 0; i < m_child_list.size(); i++) {
977     auto child = static_cast<BitMapArea *>(m_child_list.get_nth_item(i));
978     delete child;
979   }
980
981   unlock();
982 }
983
984 /* Intensionally hinted because BitMapAreaLeaf::alloc_blocks_dis_int. */
985 inline bool BitMapAreaLeaf::child_check_n_lock(BitMapZone* const child,
986                                                const int64_t required,
987                                                const bool lock)
988 {
989   /* The exhausted check can be performed without acquiring the lock. This
990    * is because 1) BitMapZone::is_exhausted() actually operates atomically
991    * and 2) it's followed by the exclusive, required-aware re-verification. */
992   if (child->BitMapZone::is_exhausted()) {
993     return false;
994   }
995
996   if (lock) {
997     child->lock_excl();
998   } else if (!child->lock_excl_try()) {
999     return false;
1000   }
1001
1002   int64_t child_used_blocks = child->get_used_blocks();
1003   int64_t child_total_blocks = child->size();
1004   if ((child_total_blocks - child_used_blocks) < required) {
1005     child->unlock();
1006     return false;
1007   }
1008
1009   return true;
1010 }
1011
1012 int64_t BitMapAreaLeaf::alloc_blocks_dis_int(int64_t num_blocks, int64_t min_alloc, 
1013                                  int64_t hint, int64_t area_blk_off, ExtentList *block_list)
1014 {
1015   BitMapZone* child = nullptr;
1016   int64_t allocated = 0;
1017   int64_t blk_off = 0;
1018
1019   BmapEntityListIter iter = BmapEntityListIter(
1020         &m_child_list, hint / m_child_size_blocks, false);
1021
1022   /* We're sure the only element type we aggregate is BitMapZone,
1023    * so there is no business to go through vptr and thus prohibit
1024    * compiler to inline the stuff. Consult BitMapAreaLeaf::init. */
1025   while ((child = static_cast<BitMapZone*>(iter.next()))) {
1026     if (!child_check_n_lock(child, 1, false)) {
1027       hint = 0;
1028       continue;
1029     }
1030
1031     blk_off = child->get_index() * m_child_size_blocks + area_blk_off;
1032     allocated += child->alloc_blocks_dis(num_blocks - allocated, min_alloc,
1033                                          hint % m_child_size_blocks, blk_off, block_list);
1034     child->unlock();
1035     if (allocated == num_blocks) {
1036       break;
1037     }
1038     hint = 0;
1039   }
1040   return allocated;
1041 }
1042
1043 void BitMapAreaLeaf::free_blocks_int(int64_t start_block, int64_t num_blocks)
1044 {
1045   BitMapArea *child = NULL;
1046   int64_t child_block_offset = 0;
1047   int64_t falling_in_child = 0;
1048
1049   alloc_assert(start_block >= 0 &&
1050     (start_block + num_blocks) <= size());
1051
1052   if (num_blocks == 0) {
1053     return;
1054   }
1055
1056   while (num_blocks) {
1057     child = static_cast<BitMapArea *>(m_child_list.get_nth_item(
1058           start_block / m_child_size_blocks));
1059
1060     child_block_offset = start_block % m_child_size_blocks;
1061
1062     falling_in_child = MIN(m_child_size_blocks - child_block_offset,
1063               num_blocks);
1064
1065     child->lock_excl();
1066     child->free_blocks(child_block_offset, falling_in_child);
1067     child->unlock();
1068     start_block += falling_in_child;
1069     num_blocks -= falling_in_child;
1070   }
1071 }
1072
1073 /*
1074  * Main allocator functions.
1075  */
1076 BitAllocator::BitAllocator(CephContext* cct, int64_t total_blocks,
1077                            int64_t zone_size_block, bmap_alloc_mode_t mode)
1078   : BitMapAreaIN(cct),
1079     cct(cct)
1080 {
1081   init_check(total_blocks, zone_size_block, mode, false, false);
1082 }
1083
1084 BitAllocator::BitAllocator(CephContext* cct, int64_t total_blocks,
1085                            int64_t zone_size_block, bmap_alloc_mode_t mode,
1086                            bool def)
1087   : BitMapAreaIN(cct),
1088     cct(cct)
1089 {
1090   init_check(total_blocks, zone_size_block, mode, def, false);
1091 }
1092
1093 BitAllocator::BitAllocator(CephContext* cct, int64_t total_blocks,
1094                            int64_t zone_size_block, bmap_alloc_mode_t mode,
1095                            bool def, bool stats_on)
1096   : BitMapAreaIN(cct),
1097     cct(cct)
1098 {
1099   init_check(total_blocks, zone_size_block, mode, def, stats_on);
1100 }
1101
1102 void BitAllocator::init_check(int64_t total_blocks, int64_t zone_size_block,
1103        bmap_alloc_mode_t mode, bool def, bool stats_on)
1104 {
1105   int64_t unaligned_blocks = 0;
1106
1107   if (mode != SERIAL && mode != CONCURRENT) {
1108     ceph_abort();
1109   }
1110
1111   if (total_blocks <= 0) {
1112     ceph_abort();
1113   }
1114
1115   if (zone_size_block == 0 ||
1116     zone_size_block < BmapEntry::size()) {
1117     ceph_abort();
1118   }
1119
1120   zone_size_block = (zone_size_block / BmapEntry::size()) *
1121         BmapEntry::size();
1122
1123   unaligned_blocks = total_blocks % zone_size_block;
1124   m_extra_blocks = unaligned_blocks? zone_size_block - unaligned_blocks: 0;
1125   total_blocks = ROUND_UP_TO(total_blocks, zone_size_block);
1126
1127   m_alloc_mode = mode;
1128   m_is_stats_on = stats_on;
1129   if (m_is_stats_on) {
1130     m_stats = new BitAllocatorStats();
1131   }
1132
1133   pthread_rwlock_init(&m_rw_lock, NULL);
1134   init(cct, total_blocks, 0, def);
1135   if (!def && unaligned_blocks) {
1136     /*
1137      * Mark extra padded blocks used from beginning.
1138      */
1139     set_blocks_used(total_blocks - m_extra_blocks, m_extra_blocks);
1140   }
1141 }
1142
1143 void BitAllocator::lock_excl()
1144 {
1145   pthread_rwlock_wrlock(&m_rw_lock);
1146 }
1147
1148 void BitAllocator::lock_shared()
1149 {
1150   pthread_rwlock_rdlock(&m_rw_lock);
1151 }
1152
1153 bool BitAllocator::try_lock()
1154 {
1155   bool get_lock = false;
1156   if (pthread_rwlock_trywrlock(&m_rw_lock) == 0) {
1157     get_lock = true;
1158   }
1159
1160   return get_lock;
1161 }
1162
1163 void BitAllocator::unlock()
1164 {
1165   pthread_rwlock_unlock(&m_rw_lock);
1166 }
1167
1168 BitAllocator::~BitAllocator()
1169 {
1170   lock_excl();
1171
1172   for (int64_t i = 0; i < m_child_list.size(); i++) {
1173     auto child = static_cast<BitMapArea *>(m_child_list.get_nth_item(i));
1174     delete child;
1175   }
1176
1177   unlock();
1178   pthread_rwlock_destroy(&m_rw_lock);
1179 }
1180
1181 void
1182 BitAllocator::shutdown()
1183 {
1184   bool get_lock = try_lock();
1185   assert(get_lock);
1186   bool get_serial_lock = try_serial_lock();
1187   assert(get_serial_lock);
1188   serial_unlock();
1189   unlock();
1190 }
1191
1192 void BitAllocator::unreserve_blocks(int64_t unused)
1193 {
1194   unreserve(unused, 0);
1195 }
1196
1197 void BitAllocator::serial_lock()
1198 {
1199   if (m_alloc_mode == SERIAL) {
1200     m_serial_mutex.lock();
1201   }
1202 }
1203
1204 void BitAllocator::serial_unlock()
1205 {
1206   if (m_alloc_mode == SERIAL) {
1207     m_serial_mutex.unlock();
1208   }
1209 }
1210
1211 bool BitAllocator::try_serial_lock()
1212 {
1213   bool get_lock = false;
1214   if (m_alloc_mode == SERIAL) {
1215     if (m_serial_mutex.try_lock() == 0) {
1216       get_lock = true;
1217     }
1218   } else {
1219     get_lock = true;
1220   }
1221   return get_lock;
1222 }
1223
1224 bool BitAllocator::child_check_n_lock(BitMapArea *child, int64_t required)
1225 {
1226   child->lock_shared();
1227
1228   if (child->is_exhausted()) {
1229     child->unlock();
1230     return false;
1231   }
1232
1233   int64_t child_used_blocks = child->get_used_blocks();
1234   int64_t child_total_blocks = child->size();
1235   if ((child_total_blocks - child_used_blocks) < required) {
1236     child->unlock();
1237     return false;
1238   }
1239
1240   return true;
1241 }
1242
1243 void BitAllocator::child_unlock(BitMapArea *child)
1244 {
1245   child->unlock();
1246 }
1247
1248 bool BitAllocator::check_input_dis(int64_t num_blocks)
1249 {
1250   if (num_blocks == 0 || num_blocks > size()) {
1251     return false;
1252   }
1253   return true;
1254 }
1255
1256 bool BitAllocator::check_input(int64_t num_blocks)
1257 {
1258   if (num_blocks == 0 || num_blocks > get_zone_size(cct)) {
1259     return false;
1260   }
1261   return true;
1262 }
1263
1264 void BitAllocator::free_blocks(int64_t start_block, int64_t num_blocks)
1265 {
1266   if (num_blocks == 0) {
1267     return;
1268   }
1269
1270   alloc_assert(start_block + num_blocks <= size());
1271   if (is_stats_on()) {
1272     m_stats->add_free_calls(1);
1273     m_stats->add_freed(num_blocks);
1274   }
1275
1276   lock_shared();
1277   alloc_dbg_assert(is_allocated(start_block, num_blocks));
1278
1279   free_blocks_int(start_block, num_blocks);
1280   (void) sub_used_blocks(num_blocks);
1281
1282   unlock();
1283 }
1284
1285
1286 void BitAllocator::set_blocks_used(int64_t start_block, int64_t num_blocks)
1287 {
1288   if (num_blocks == 0) {
1289     return;
1290   }
1291
1292   alloc_assert(start_block + num_blocks <= size());
1293   lock_shared();
1294   serial_lock();
1295   set_blocks_used_int(start_block, num_blocks);
1296
1297   serial_unlock();
1298   unlock();
1299 }
1300
1301 /*
1302  * Allocate N dis-contiguous blocks.
1303  */
1304 int64_t BitAllocator::alloc_blocks_dis_int(int64_t num_blocks, int64_t min_alloc,
1305                        int64_t hint, int64_t area_blk_off, ExtentList *block_list)
1306 {
1307   return alloc_blocks_dis_int_work(true, num_blocks, min_alloc, hint,
1308                      area_blk_off, block_list);
1309 }
1310
1311 int64_t BitAllocator::alloc_blocks_dis_res(int64_t num_blocks, int64_t min_alloc,
1312                                            int64_t hint, ExtentList *block_list)
1313 {
1314   return alloc_blocks_dis_work(num_blocks, min_alloc, hint, block_list, true);
1315 }
1316
1317 int64_t BitAllocator::alloc_blocks_dis_work(int64_t num_blocks, int64_t min_alloc,
1318                                             int64_t hint, ExtentList *block_list, bool reserved)
1319 {
1320   int scans = 1;
1321   int64_t allocated = 0;
1322   /*
1323    * This is root so offset is 0 yet.
1324    */
1325   int64_t blk_off = 0;
1326
1327   if (!check_input_dis(num_blocks)) {
1328     return 0;
1329   }
1330
1331   if (is_stats_on()) {
1332     m_stats->add_alloc_calls(1);
1333     m_stats->add_allocated(num_blocks);
1334   }
1335
1336   lock_shared();
1337   serial_lock();
1338   if (!reserved && !reserve_blocks(num_blocks)) {
1339     goto exit;
1340   }
1341
1342   if (is_stats_on()) {
1343     m_stats->add_concurrent_scans(scans);
1344   }
1345
1346   while (scans && allocated < num_blocks) {
1347     allocated += alloc_blocks_dis_int(num_blocks - allocated, min_alloc, hint + allocated, blk_off, block_list);
1348     scans--;
1349   }
1350
1351   if (allocated < num_blocks) {
1352     /*
1353      * Could not find anything in concurrent scan.
1354      * Go in serial manner to get something for sure
1355      * if available.
1356      */
1357     serial_unlock();
1358     unlock();
1359     lock_excl();
1360     serial_lock();
1361     allocated += alloc_blocks_dis_int(num_blocks - allocated, min_alloc, hint + allocated,
1362                                       blk_off, block_list);
1363     if (is_stats_on()) {
1364       m_stats->add_serial_scans(1);
1365     }
1366   }
1367
1368   unreserve(num_blocks, allocated);
1369   alloc_dbg_assert(is_allocated_dis(block_list, allocated));
1370
1371 exit:
1372   serial_unlock();
1373   unlock();
1374
1375   return allocated;
1376 }
1377
1378 bool BitAllocator::is_allocated_dis(ExtentList *blocks, int64_t num_blocks)
1379 {
1380   int64_t count = 0;
1381   for (int64_t j = 0; j < blocks->get_extent_count(); j++) {
1382     auto p = blocks->get_nth_extent(j);
1383     count += p.second;
1384     if (!is_allocated(p.first, p.second)) {
1385       return false;
1386     }
1387   }
1388
1389   alloc_assert(count == num_blocks);
1390   return true;
1391 }
1392
1393 void BitAllocator::free_blocks_dis(int64_t num_blocks, ExtentList *block_list)
1394 {
1395   int64_t freed = 0;
1396   lock_shared();
1397   if (is_stats_on()) {
1398     m_stats->add_free_calls(1);
1399     m_stats->add_freed(num_blocks);
1400   }
1401
1402   for (int64_t i = 0; i < block_list->get_extent_count(); i++) {
1403     free_blocks_int(block_list->get_nth_extent(i).first,
1404                     block_list->get_nth_extent(i).second);
1405     freed += block_list->get_nth_extent(i).second;
1406   }
1407
1408   alloc_assert(num_blocks == freed);
1409   sub_used_blocks(num_blocks);
1410   alloc_assert(get_used_blocks() >= 0);
1411   unlock();
1412 }
1413
1414 void BitAllocator::dump()
1415 {
1416   int count = 0;
1417   serial_lock(); 
1418   dump_state(cct, count);
1419   serial_unlock(); 
1420 }