]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Bitmap based in-memory allocator. | |
5 | * Author: Ramesh Chander, Ramesh.Chander@sandisk.com | |
6 | * | |
7 | */ | |
8 | ||
9 | #include "BitAllocator.h" | |
10 | ||
11 | #include "BitMapAllocator.h" | |
12 | #include "bluestore_types.h" | |
13 | #include "common/debug.h" | |
14 | ||
15 | #define dout_context cct | |
16 | #define dout_subsys ceph_subsys_bluestore | |
17 | #undef dout_prefix | |
18 | #define dout_prefix *_dout << "bitmapalloc:" | |
19 | ||
20 | ||
21 | BitMapAllocator::BitMapAllocator(CephContext* cct, int64_t device_size, | |
22 | int64_t block_size) | |
23 | : cct(cct) | |
24 | { | |
7c673cae FG |
25 | if (!ISP2(block_size)) { |
26 | derr << __func__ << " block_size " << block_size | |
27 | << " not power of 2 aligned!" | |
28 | << dendl; | |
31f18b77 | 29 | assert(ISP2(block_size)); |
7c673cae FG |
30 | return; |
31 | } | |
32 | ||
33 | int64_t zone_size_blks = cct->_conf->bluestore_bitmapallocator_blocks_per_zone; | |
7c673cae FG |
34 | if (!ISP2(zone_size_blks)) { |
35 | derr << __func__ << " zone_size " << zone_size_blks | |
36 | << " not power of 2 aligned!" | |
37 | << dendl; | |
31f18b77 | 38 | assert(ISP2(zone_size_blks)); |
7c673cae FG |
39 | return; |
40 | } | |
41 | ||
42 | int64_t span_size = cct->_conf->bluestore_bitmapallocator_span_size; | |
7c673cae FG |
43 | if (!ISP2(span_size)) { |
44 | derr << __func__ << " span_size " << span_size | |
45 | << " not power of 2 aligned!" | |
46 | << dendl; | |
31f18b77 | 47 | assert(ISP2(span_size)); |
7c673cae FG |
48 | return; |
49 | } | |
50 | ||
51 | m_block_size = block_size; | |
31f18b77 | 52 | m_total_size = P2ALIGN(device_size, block_size); |
7c673cae FG |
53 | m_bit_alloc = new BitAllocator(cct, device_size / block_size, |
54 | zone_size_blks, CONCURRENT, true); | |
7c673cae FG |
55 | if (!m_bit_alloc) { |
56 | derr << __func__ << " Unable to intialize Bit Allocator" << dendl; | |
31f18b77 | 57 | assert(m_bit_alloc); |
7c673cae FG |
58 | } |
59 | dout(10) << __func__ << " instance " << (uint64_t) this | |
60 | << " size 0x" << std::hex << device_size << std::dec | |
61 | << dendl; | |
62 | } | |
63 | ||
64 | BitMapAllocator::~BitMapAllocator() | |
65 | { | |
66 | delete m_bit_alloc; | |
67 | } | |
68 | ||
69 | void BitMapAllocator::insert_free(uint64_t off, uint64_t len) | |
70 | { | |
71 | dout(20) << __func__ << " instance " << (uint64_t) this | |
72 | << " off 0x" << std::hex << off | |
73 | << " len 0x" << len << std::dec | |
74 | << dendl; | |
75 | ||
76 | assert(!(off % m_block_size)); | |
77 | assert(!(len % m_block_size)); | |
78 | ||
79 | m_bit_alloc->free_blocks(off / m_block_size, | |
80 | len / m_block_size); | |
81 | } | |
82 | ||
83 | int BitMapAllocator::reserve(uint64_t need) | |
84 | { | |
85 | int nblks = need / m_block_size; // apply floor | |
86 | assert(!(need % m_block_size)); | |
87 | dout(10) << __func__ << " instance " << (uint64_t) this | |
88 | << " num_used " << m_bit_alloc->get_used_blocks() | |
89 | << " total " << m_bit_alloc->total_blocks() | |
90 | << dendl; | |
91 | ||
92 | if (!m_bit_alloc->reserve_blocks(nblks)) { | |
93 | return -ENOSPC; | |
94 | } | |
95 | return 0; | |
96 | } | |
97 | ||
98 | void BitMapAllocator::unreserve(uint64_t unused) | |
99 | { | |
100 | int nblks = unused / m_block_size; | |
101 | assert(!(unused % m_block_size)); | |
102 | ||
103 | dout(10) << __func__ << " instance " << (uint64_t) this | |
104 | << " unused " << nblks | |
105 | << " num used " << m_bit_alloc->get_used_blocks() | |
106 | << " total " << m_bit_alloc->total_blocks() | |
107 | << dendl; | |
108 | ||
109 | m_bit_alloc->unreserve_blocks(nblks); | |
110 | } | |
111 | ||
112 | int64_t BitMapAllocator::allocate( | |
113 | uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size, | |
114 | int64_t hint, mempool::bluestore_alloc::vector<AllocExtent> *extents) | |
115 | { | |
116 | ||
117 | assert(!(alloc_unit % m_block_size)); | |
118 | assert(alloc_unit); | |
119 | ||
120 | assert(!max_alloc_size || max_alloc_size >= alloc_unit); | |
121 | ||
122 | dout(10) << __func__ <<" instance "<< (uint64_t) this | |
123 | << " want_size " << want_size | |
124 | << " alloc_unit " << alloc_unit | |
125 | << " hint " << hint | |
126 | << dendl; | |
31f18b77 | 127 | hint = hint % m_total_size; // make hint error-tolerant |
7c673cae FG |
128 | return allocate_dis(want_size, alloc_unit / m_block_size, |
129 | max_alloc_size, hint / m_block_size, extents); | |
130 | } | |
131 | ||
132 | int64_t BitMapAllocator::allocate_dis( | |
133 | uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size, | |
134 | int64_t hint, mempool::bluestore_alloc::vector<AllocExtent> *extents) | |
135 | { | |
136 | ExtentList block_list = ExtentList(extents, m_block_size, max_alloc_size); | |
137 | int64_t nblks = (want_size + m_block_size - 1) / m_block_size; | |
138 | int64_t num = 0; | |
139 | ||
140 | num = m_bit_alloc->alloc_blocks_dis_res(nblks, alloc_unit, hint, &block_list); | |
141 | if (num == 0) { | |
142 | return -ENOSPC; | |
143 | } | |
144 | ||
145 | return num * m_block_size; | |
146 | } | |
147 | ||
148 | void BitMapAllocator::release( | |
149 | uint64_t offset, uint64_t length) | |
150 | { | |
151 | dout(10) << __func__ << " 0x" | |
152 | << std::hex << offset << "~" << length << std::dec | |
153 | << dendl; | |
154 | insert_free(offset, length); | |
155 | } | |
156 | ||
157 | uint64_t BitMapAllocator::get_free() | |
158 | { | |
159 | assert(m_bit_alloc->total_blocks() >= m_bit_alloc->get_used_blocks()); | |
160 | return (( | |
161 | m_bit_alloc->total_blocks() - m_bit_alloc->get_used_blocks()) * | |
162 | m_block_size); | |
163 | } | |
164 | ||
165 | void BitMapAllocator::dump() | |
166 | { | |
167 | dout(0) << __func__ << " instance " << this << dendl; | |
168 | m_bit_alloc->dump(); | |
169 | } | |
170 | ||
171 | void BitMapAllocator::init_add_free(uint64_t offset, uint64_t length) | |
172 | { | |
173 | dout(10) << __func__ << " instance " << (uint64_t) this | |
174 | << " offset 0x" << std::hex << offset | |
175 | << " length 0x" << length << std::dec | |
176 | << dendl; | |
177 | uint64_t size = m_bit_alloc->size() * m_block_size; | |
178 | ||
179 | uint64_t offset_adj = ROUND_UP_TO(offset, m_block_size); | |
180 | uint64_t length_adj = ((length - (offset_adj - offset)) / | |
181 | m_block_size) * m_block_size; | |
182 | ||
183 | if ((offset_adj + length_adj) > size) { | |
184 | assert(((offset_adj + length_adj) - m_block_size) < size); | |
185 | length_adj = size - offset_adj; | |
186 | } | |
187 | ||
188 | insert_free(offset_adj, length_adj); | |
189 | } | |
190 | ||
191 | void BitMapAllocator::init_rm_free(uint64_t offset, uint64_t length) | |
192 | { | |
193 | dout(10) << __func__ << " instance " << (uint64_t) this | |
194 | << " offset 0x" << std::hex << offset | |
195 | << " length 0x" << length << std::dec | |
196 | << dendl; | |
197 | ||
198 | // we use the same adjustment/alignment that init_add_free does | |
199 | // above so that we can yank back some of the space. | |
200 | uint64_t offset_adj = ROUND_UP_TO(offset, m_block_size); | |
201 | uint64_t length_adj = ((length - (offset_adj - offset)) / | |
202 | m_block_size) * m_block_size; | |
203 | ||
204 | assert(!(offset_adj % m_block_size)); | |
205 | assert(!(length_adj % m_block_size)); | |
206 | ||
207 | int64_t first_blk = offset_adj / m_block_size; | |
208 | int64_t count = length_adj / m_block_size; | |
209 | ||
210 | if (count) | |
211 | m_bit_alloc->set_blocks_used(first_blk, count); | |
212 | } | |
213 | ||
214 | ||
215 | void BitMapAllocator::shutdown() | |
216 | { | |
217 | dout(10) << __func__ << " instance " << (uint64_t) this << dendl; | |
218 | m_bit_alloc->shutdown(); | |
219 | } | |
220 |