aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/free-space-cache.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@redhat.com>2009-04-03 10:14:18 -0400
committerChris Mason <chris.mason@oracle.com>2009-04-03 10:14:18 -0400
commit6226cb0a5ea3f6289883753c15d53f48a6c6bbfb (patch)
tree819765cd5a5816017580f638c4b2a3e7f6354aea /fs/btrfs/free-space-cache.c
parent2552d17e328044d1811cae733087a1fb9aac2eb6 (diff)
Btrfs: kill the block group alloc mutex
This patch removes the block group alloc mutex used to protect the free space tree for allocations and replaces it with a spin lock which is used only to protect the free space rb tree. This means we only take the lock when we are directly manipulating the tree, which makes us a touch faster with multi-threaded workloads. This patch also gets rid of btrfs_find_free_space and replaces it with btrfs_find_space_for_alloc, which takes the number of bytes you want to allocate, and empty_size, which is used to indicate how much free space should be at the end of the allocation. It will return an offset for the allocator to use. If we don't end up using it we _must_ call btrfs_add_free_space to put it back. This is the tradeoff to kill the alloc_mutex, since we need to make sure nobody else comes along and takes our space. Signed-off-by: Josef Bacik <jbacik@redhat.com>
Diffstat (limited to 'fs/btrfs/free-space-cache.c')
-rw-r--r--fs/btrfs/free-space-cache.c183
1 files changed, 57 insertions, 126 deletions
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 69b023ff6f72..df19b60eef61 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -182,6 +182,7 @@ static int link_free_space(struct btrfs_block_group_cache *block_group,
182 int ret = 0; 182 int ret = 0;
183 183
184 184
185 BUG_ON(!info->bytes);
185 ret = tree_insert_offset(&block_group->free_space_offset, info->offset, 186 ret = tree_insert_offset(&block_group->free_space_offset, info->offset,
186 &info->offset_index); 187 &info->offset_index);
187 if (ret) 188 if (ret)
@@ -195,14 +196,23 @@ static int link_free_space(struct btrfs_block_group_cache *block_group,
195 return ret; 196 return ret;
196} 197}
197 198
198static int __btrfs_add_free_space(struct btrfs_block_group_cache *block_group, 199int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
199 u64 offset, u64 bytes) 200 u64 offset, u64 bytes)
200{ 201{
201 struct btrfs_free_space *right_info; 202 struct btrfs_free_space *right_info;
202 struct btrfs_free_space *left_info; 203 struct btrfs_free_space *left_info;
203 struct btrfs_free_space *info = NULL; 204 struct btrfs_free_space *info = NULL;
204 int ret = 0; 205 int ret = 0;
205 206
207 info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS);
208 if (!info)
209 return -ENOMEM;
210
211 info->offset = offset;
212 info->bytes = bytes;
213
214 spin_lock(&block_group->tree_lock);
215
206 /* 216 /*
207 * first we want to see if there is free space adjacent to the range we 217 * first we want to see if there is free space adjacent to the range we
208 * are adding, if there is remove that struct and add a new one to 218 * are adding, if there is remove that struct and add a new one to
@@ -215,42 +225,23 @@ static int __btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
215 225
216 if (right_info) { 226 if (right_info) {
217 unlink_free_space(block_group, right_info); 227 unlink_free_space(block_group, right_info);
218 info = right_info; 228 info->bytes += right_info->bytes;
219 info->offset = offset; 229 kfree(right_info);
220 info->bytes += bytes;
221 } 230 }
222 231
223 if (left_info && left_info->offset + left_info->bytes == offset) { 232 if (left_info && left_info->offset + left_info->bytes == offset) {
224 unlink_free_space(block_group, left_info); 233 unlink_free_space(block_group, left_info);
225 234 info->offset = left_info->offset;
226 if (info) { 235 info->bytes += left_info->bytes;
227 info->offset = left_info->offset; 236 kfree(left_info);
228 info->bytes += left_info->bytes;
229 kfree(left_info);
230 } else {
231 info = left_info;
232 info->bytes += bytes;
233 }
234 }
235
236 if (info) {
237 ret = link_free_space(block_group, info);
238 if (ret)
239 kfree(info);
240 goto out;
241 } 237 }
242 238
243 info = kzalloc(sizeof(struct btrfs_free_space), GFP_NOFS);
244 if (!info)
245 return -ENOMEM;
246
247 info->offset = offset;
248 info->bytes = bytes;
249
250 ret = link_free_space(block_group, info); 239 ret = link_free_space(block_group, info);
251 if (ret) 240 if (ret)
252 kfree(info); 241 kfree(info);
253out: 242
243 spin_unlock(&block_group->tree_lock);
244
254 if (ret) { 245 if (ret) {
255 printk(KERN_ERR "btrfs: unable to add free space :%d\n", ret); 246 printk(KERN_ERR "btrfs: unable to add free space :%d\n", ret);
256 if (ret == -EEXIST) 247 if (ret == -EEXIST)
@@ -260,17 +251,16 @@ out:
260 return ret; 251 return ret;
261} 252}
262 253
263static int 254int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
264__btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, 255 u64 offset, u64 bytes)
265 u64 offset, u64 bytes)
266{ 256{
267 struct btrfs_free_space *info; 257 struct btrfs_free_space *info;
268 int ret = 0; 258 int ret = 0;
269 259
270 BUG_ON(!block_group->cached); 260 spin_lock(&block_group->tree_lock);
261
271 info = tree_search_offset(&block_group->free_space_offset, offset, 0, 262 info = tree_search_offset(&block_group->free_space_offset, offset, 0,
272 1); 263 1);
273
274 if (info && info->offset == offset) { 264 if (info && info->offset == offset) {
275 if (info->bytes < bytes) { 265 if (info->bytes < bytes) {
276 printk(KERN_ERR "Found free space at %llu, size %llu," 266 printk(KERN_ERR "Found free space at %llu, size %llu,"
@@ -280,12 +270,14 @@ __btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
280 (unsigned long long)bytes); 270 (unsigned long long)bytes);
281 WARN_ON(1); 271 WARN_ON(1);
282 ret = -EINVAL; 272 ret = -EINVAL;
273 spin_unlock(&block_group->tree_lock);
283 goto out; 274 goto out;
284 } 275 }
285 unlink_free_space(block_group, info); 276 unlink_free_space(block_group, info);
286 277
287 if (info->bytes == bytes) { 278 if (info->bytes == bytes) {
288 kfree(info); 279 kfree(info);
280 spin_unlock(&block_group->tree_lock);
289 goto out; 281 goto out;
290 } 282 }
291 283
@@ -293,6 +285,7 @@ __btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
293 info->bytes -= bytes; 285 info->bytes -= bytes;
294 286
295 ret = link_free_space(block_group, info); 287 ret = link_free_space(block_group, info);
288 spin_unlock(&block_group->tree_lock);
296 BUG_ON(ret); 289 BUG_ON(ret);
297 } else if (info && info->offset < offset && 290 } else if (info && info->offset < offset &&
298 info->offset + info->bytes >= offset + bytes) { 291 info->offset + info->bytes >= offset + bytes) {
@@ -318,14 +311,15 @@ __btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
318 */ 311 */
319 kfree(info); 312 kfree(info);
320 } 313 }
321 314 spin_unlock(&block_group->tree_lock);
322 /* step two, insert a new info struct to cover anything 315 /* step two, insert a new info struct to cover anything
323 * before the hole 316 * before the hole
324 */ 317 */
325 ret = __btrfs_add_free_space(block_group, old_start, 318 ret = btrfs_add_free_space(block_group, old_start,
326 offset - old_start); 319 offset - old_start);
327 BUG_ON(ret); 320 BUG_ON(ret);
328 } else { 321 } else {
322 spin_unlock(&block_group->tree_lock);
329 if (!info) { 323 if (!info) {
330 printk(KERN_ERR "couldn't find space %llu to free\n", 324 printk(KERN_ERR "couldn't find space %llu to free\n",
331 (unsigned long long)offset); 325 (unsigned long long)offset);
@@ -344,50 +338,6 @@ out:
344 return ret; 338 return ret;
345} 339}
346 340
347int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
348 u64 offset, u64 bytes)
349{
350 int ret;
351
352 mutex_lock(&block_group->alloc_mutex);
353 ret = __btrfs_add_free_space(block_group, offset, bytes);
354 mutex_unlock(&block_group->alloc_mutex);
355
356 return ret;
357}
358
359int btrfs_add_free_space_lock(struct btrfs_block_group_cache *block_group,
360 u64 offset, u64 bytes)
361{
362 int ret;
363
364 ret = __btrfs_add_free_space(block_group, offset, bytes);
365
366 return ret;
367}
368
369int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
370 u64 offset, u64 bytes)
371{
372 int ret = 0;
373
374 mutex_lock(&block_group->alloc_mutex);
375 ret = __btrfs_remove_free_space(block_group, offset, bytes);
376 mutex_unlock(&block_group->alloc_mutex);
377
378 return ret;
379}
380
381int btrfs_remove_free_space_lock(struct btrfs_block_group_cache *block_group,
382 u64 offset, u64 bytes)
383{
384 int ret;
385
386 ret = __btrfs_remove_free_space(block_group, offset, bytes);
387
388 return ret;
389}
390
391void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group, 341void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
392 u64 bytes) 342 u64 bytes)
393{ 343{
@@ -426,63 +376,44 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group)
426 struct btrfs_free_space *info; 376 struct btrfs_free_space *info;
427 struct rb_node *node; 377 struct rb_node *node;
428 378
429 mutex_lock(&block_group->alloc_mutex); 379 spin_lock(&block_group->tree_lock);
430 while ((node = rb_last(&block_group->free_space_bytes)) != NULL) { 380 while ((node = rb_last(&block_group->free_space_bytes)) != NULL) {
431 info = rb_entry(node, struct btrfs_free_space, bytes_index); 381 info = rb_entry(node, struct btrfs_free_space, bytes_index);
432 unlink_free_space(block_group, info); 382 unlink_free_space(block_group, info);
433 kfree(info); 383 kfree(info);
434 if (need_resched()) { 384 if (need_resched()) {
435 mutex_unlock(&block_group->alloc_mutex); 385 spin_unlock(&block_group->tree_lock);
436 cond_resched(); 386 cond_resched();
437 mutex_lock(&block_group->alloc_mutex); 387 spin_lock(&block_group->tree_lock);
438 } 388 }
439 } 389 }
440 mutex_unlock(&block_group->alloc_mutex); 390 spin_unlock(&block_group->tree_lock);
441}
442
443#if 0
444static struct btrfs_free_space *btrfs_find_free_space_offset(struct
445 btrfs_block_group_cache
446 *block_group, u64 offset,
447 u64 bytes)
448{
449 struct btrfs_free_space *ret;
450
451 mutex_lock(&block_group->alloc_mutex);
452 ret = tree_search_offset(&block_group->free_space_offset, offset,
453 bytes, 0);
454 mutex_unlock(&block_group->alloc_mutex);
455
456 return ret;
457} 391}
458 392
459static struct btrfs_free_space *btrfs_find_free_space_bytes(struct 393u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
460 btrfs_block_group_cache 394 u64 offset, u64 bytes, u64 empty_size)
461 *block_group, u64 offset,
462 u64 bytes)
463{ 395{
464 struct btrfs_free_space *ret; 396 struct btrfs_free_space *entry = NULL;
465 397 u64 ret = 0;
466 mutex_lock(&block_group->alloc_mutex);
467
468 ret = tree_search_bytes(&block_group->free_space_bytes, offset, bytes);
469 mutex_unlock(&block_group->alloc_mutex);
470
471 return ret;
472}
473#endif
474
475struct btrfs_free_space *btrfs_find_free_space(struct btrfs_block_group_cache
476 *block_group, u64 offset,
477 u64 bytes)
478{
479 struct btrfs_free_space *ret = NULL;
480 398
481 ret = tree_search_offset(&block_group->free_space_offset, offset, 399 spin_lock(&block_group->tree_lock);
482 bytes, 1); 400 entry = tree_search_offset(&block_group->free_space_offset, offset,
483 if (!ret) 401 bytes + empty_size, 1);
484 ret = tree_search_bytes(&block_group->free_space_bytes, 402 if (!entry)
485 offset, bytes); 403 entry = tree_search_bytes(&block_group->free_space_bytes,
404 offset, bytes + empty_size);
405 if (entry) {
406 unlink_free_space(block_group, entry);
407 ret = entry->offset;
408 entry->offset += bytes;
409 entry->bytes -= bytes;
410
411 if (!entry->bytes)
412 kfree(entry);
413 else
414 link_free_space(block_group, entry);
415 }
416 spin_unlock(&block_group->tree_lock);
486 417
487 return ret; 418 return ret;
488} 419}