diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 10 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 3 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 101 |
3 files changed, 87 insertions, 27 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 2d166ca8b104..26d0cdd46f49 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -244,12 +244,17 @@ struct btrfs_fs_info { | |||
244 | struct btrfs_root *extent_root; | 244 | struct btrfs_root *extent_root; |
245 | struct btrfs_root *tree_root; | 245 | struct btrfs_root *tree_root; |
246 | struct btrfs_root *dev_root; | 246 | struct btrfs_root *dev_root; |
247 | struct btrfs_key current_insert; | ||
248 | struct btrfs_key last_insert; | 247 | struct btrfs_key last_insert; |
249 | struct radix_tree_root fs_roots_radix; | 248 | struct radix_tree_root fs_roots_radix; |
250 | struct radix_tree_root pending_del_radix; | 249 | struct radix_tree_root pending_del_radix; |
251 | struct radix_tree_root pinned_radix; | 250 | struct radix_tree_root pinned_radix; |
252 | struct radix_tree_root dev_radix; | 251 | struct radix_tree_root dev_radix; |
252 | |||
253 | u64 extent_tree_insert[BTRFS_MAX_LEVEL * 3]; | ||
254 | int extent_tree_insert_nr; | ||
255 | u64 extent_tree_prealloc[BTRFS_MAX_LEVEL * 3]; | ||
256 | int extent_tree_prealloc_nr; | ||
257 | |||
253 | u64 generation; | 258 | u64 generation; |
254 | struct btrfs_transaction *running_transaction; | 259 | struct btrfs_transaction *running_transaction; |
255 | struct btrfs_super_block *disk_super; | 260 | struct btrfs_super_block *disk_super; |
@@ -267,8 +272,7 @@ struct btrfs_fs_info { | |||
267 | 272 | ||
268 | /* | 273 | /* |
269 | * in ram representation of the tree. extent_root is used for all allocations | 274 | * in ram representation of the tree. extent_root is used for all allocations |
270 | * and for the extent tree extent_root root. current_insert is used | 275 | * and for the extent tree extent_root root. |
271 | * only for the extent tree. | ||
272 | */ | 276 | */ |
273 | struct btrfs_root { | 277 | struct btrfs_root { |
274 | struct buffer_head *node; | 278 | struct buffer_head *node; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 7aff6bb55d91..956727f015a5 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -542,6 +542,8 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
542 | fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; | 542 | fs_info->btree_inode->i_size = sb->s_bdev->bd_inode->i_size; |
543 | fs_info->btree_inode->i_mapping->a_ops = &btree_aops; | 543 | fs_info->btree_inode->i_mapping->a_ops = &btree_aops; |
544 | fs_info->do_barriers = 1; | 544 | fs_info->do_barriers = 1; |
545 | fs_info->extent_tree_insert_nr = 0; | ||
546 | fs_info->extent_tree_prealloc_nr = 0; | ||
545 | BTRFS_I(fs_info->btree_inode)->root = tree_root; | 547 | BTRFS_I(fs_info->btree_inode)->root = tree_root; |
546 | memset(&BTRFS_I(fs_info->btree_inode)->location, 0, | 548 | memset(&BTRFS_I(fs_info->btree_inode)->location, 0, |
547 | sizeof(struct btrfs_key)); | 549 | sizeof(struct btrfs_key)); |
@@ -555,7 +557,6 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
555 | } | 557 | } |
556 | mutex_init(&fs_info->trans_mutex); | 558 | mutex_init(&fs_info->trans_mutex); |
557 | mutex_init(&fs_info->fs_mutex); | 559 | mutex_init(&fs_info->fs_mutex); |
558 | memset(&fs_info->current_insert, 0, sizeof(fs_info->current_insert)); | ||
559 | memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert)); | 560 | memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert)); |
560 | 561 | ||
561 | __setup_root(sb->s_blocksize, dev_root, | 562 | __setup_root(sb->s_blocksize, dev_root, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 116519503d0c..e6fe3fd38819 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -169,9 +169,8 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct | |||
169 | btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY); | 169 | btrfs_set_key_type(&ins, BTRFS_EXTENT_ITEM_KEY); |
170 | btrfs_set_extent_owner(&extent_item, extent_root->root_key.objectid); | 170 | btrfs_set_extent_owner(&extent_item, extent_root->root_key.objectid); |
171 | 171 | ||
172 | for (i = 0; i < extent_root->fs_info->current_insert.flags; i++) { | 172 | for (i = 0; i < extent_root->fs_info->extent_tree_insert_nr; i++) { |
173 | ins.objectid = extent_root->fs_info->current_insert.objectid + | 173 | ins.objectid = extent_root->fs_info->extent_tree_insert[i]; |
174 | i; | ||
175 | super_blocks_used = btrfs_super_blocks_used(info->disk_super); | 174 | super_blocks_used = btrfs_super_blocks_used(info->disk_super); |
176 | btrfs_set_super_blocks_used(info->disk_super, | 175 | btrfs_set_super_blocks_used(info->disk_super, |
177 | super_blocks_used + 1); | 176 | super_blocks_used + 1); |
@@ -179,7 +178,8 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct | |||
179 | sizeof(extent_item)); | 178 | sizeof(extent_item)); |
180 | BUG_ON(ret); | 179 | BUG_ON(ret); |
181 | } | 180 | } |
182 | extent_root->fs_info->current_insert.offset = 0; | 181 | extent_root->fs_info->extent_tree_insert_nr = 0; |
182 | extent_root->fs_info->extent_tree_prealloc_nr = 0; | ||
183 | return 0; | 183 | return 0; |
184 | } | 184 | } |
185 | 185 | ||
@@ -349,7 +349,10 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
349 | int start_found; | 349 | int start_found; |
350 | struct btrfs_leaf *l; | 350 | struct btrfs_leaf *l; |
351 | struct btrfs_root * root = orig_root->fs_info->extent_root; | 351 | struct btrfs_root * root = orig_root->fs_info->extent_root; |
352 | struct btrfs_fs_info *info = root->fs_info; | ||
352 | int total_needed = num_blocks; | 353 | int total_needed = num_blocks; |
354 | int total_found = 0; | ||
355 | int fill_prealloc = 0; | ||
353 | int level; | 356 | int level; |
354 | 357 | ||
355 | path = btrfs_alloc_path(); | 358 | path = btrfs_alloc_path(); |
@@ -357,8 +360,12 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
357 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); | 360 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); |
358 | 361 | ||
359 | level = btrfs_header_level(btrfs_buffer_header(root->node)); | 362 | level = btrfs_header_level(btrfs_buffer_header(root->node)); |
360 | total_needed += (level + 2) * 3; | 363 | if (num_blocks == 0) { |
361 | if (root->fs_info->last_insert.objectid == 0 && search_end == (u64)-1) { | 364 | fill_prealloc = 1; |
365 | num_blocks = 1; | ||
366 | total_needed = min(level + 2, BTRFS_MAX_LEVEL) * 3; | ||
367 | } | ||
368 | if (info->last_insert.objectid == 0 && search_end == (u64)-1) { | ||
362 | struct btrfs_disk_key *last_key; | 369 | struct btrfs_disk_key *last_key; |
363 | btrfs_init_path(path); | 370 | btrfs_init_path(path); |
364 | ins->objectid = (u64)-1; | 371 | ins->objectid = (u64)-1; |
@@ -373,8 +380,8 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
373 | last_key = &l->items[path->slots[0]].key; | 380 | last_key = &l->items[path->slots[0]].key; |
374 | search_start = btrfs_disk_key_objectid(last_key); | 381 | search_start = btrfs_disk_key_objectid(last_key); |
375 | } | 382 | } |
376 | if (root->fs_info->last_insert.objectid > search_start) | 383 | if (info->last_insert.objectid > search_start) |
377 | search_start = root->fs_info->last_insert.objectid; | 384 | search_start = info->last_insert.objectid; |
378 | 385 | ||
379 | check_failed: | 386 | check_failed: |
380 | btrfs_init_path(path); | 387 | btrfs_init_path(path); |
@@ -392,6 +399,10 @@ check_failed: | |||
392 | l = btrfs_buffer_leaf(path->nodes[0]); | 399 | l = btrfs_buffer_leaf(path->nodes[0]); |
393 | slot = path->slots[0]; | 400 | slot = path->slots[0]; |
394 | if (slot >= btrfs_header_nritems(&l->header)) { | 401 | if (slot >= btrfs_header_nritems(&l->header)) { |
402 | if (fill_prealloc) { | ||
403 | info->extent_tree_prealloc_nr = 0; | ||
404 | total_found = 0; | ||
405 | } | ||
395 | ret = btrfs_next_leaf(root, path); | 406 | ret = btrfs_next_leaf(root, path); |
396 | if (ret == 0) | 407 | if (ret == 0) |
397 | continue; | 408 | continue; |
@@ -399,13 +410,13 @@ check_failed: | |||
399 | goto error; | 410 | goto error; |
400 | if (!start_found) { | 411 | if (!start_found) { |
401 | ins->objectid = search_start; | 412 | ins->objectid = search_start; |
402 | ins->offset = (u64)-1; | 413 | ins->offset = (u64)-1 - search_start; |
403 | start_found = 1; | 414 | start_found = 1; |
404 | goto check_pending; | 415 | goto check_pending; |
405 | } | 416 | } |
406 | ins->objectid = last_block > search_start ? | 417 | ins->objectid = last_block > search_start ? |
407 | last_block : search_start; | 418 | last_block : search_start; |
408 | ins->offset = (u64)-1; | 419 | ins->offset = (u64)-1 - ins->objectid; |
409 | goto check_pending; | 420 | goto check_pending; |
410 | } | 421 | } |
411 | btrfs_disk_key_to_cpu(&key, &l->items[slot].key); | 422 | btrfs_disk_key_to_cpu(&key, &l->items[slot].key); |
@@ -414,7 +425,7 @@ check_failed: | |||
414 | if (last_block < search_start) | 425 | if (last_block < search_start) |
415 | last_block = search_start; | 426 | last_block = search_start; |
416 | hole_size = key.objectid - last_block; | 427 | hole_size = key.objectid - last_block; |
417 | if (hole_size > total_needed) { | 428 | if (hole_size > num_blocks) { |
418 | ins->objectid = last_block; | 429 | ins->objectid = last_block; |
419 | ins->offset = hole_size; | 430 | ins->offset = hole_size; |
420 | goto check_pending; | 431 | goto check_pending; |
@@ -433,17 +444,51 @@ check_pending: | |||
433 | btrfs_release_path(root, path); | 444 | btrfs_release_path(root, path); |
434 | BUG_ON(ins->objectid < search_start); | 445 | BUG_ON(ins->objectid < search_start); |
435 | for (test_block = ins->objectid; | 446 | for (test_block = ins->objectid; |
436 | test_block < ins->objectid + total_needed; test_block++) { | 447 | test_block < ins->objectid + num_blocks; test_block++) { |
437 | if (test_radix_bit(&root->fs_info->pinned_radix, | 448 | if (test_radix_bit(&info->pinned_radix, test_block)) { |
438 | test_block)) { | ||
439 | search_start = test_block + 1; | 449 | search_start = test_block + 1; |
440 | goto check_failed; | 450 | goto check_failed; |
441 | } | 451 | } |
442 | } | 452 | } |
443 | BUG_ON(root->fs_info->current_insert.offset); | 453 | if (!fill_prealloc && info->extent_tree_insert_nr) { |
444 | root->fs_info->current_insert.offset = total_needed - num_blocks; | 454 | u64 last = |
445 | root->fs_info->current_insert.objectid = ins->objectid + num_blocks; | 455 | info->extent_tree_insert[info->extent_tree_insert_nr - 1]; |
446 | root->fs_info->current_insert.flags = 0; | 456 | if (ins->objectid + num_blocks > |
457 | info->extent_tree_insert[0] && | ||
458 | ins->objectid <= last) { | ||
459 | search_start = last + 1; | ||
460 | WARN_ON(1); | ||
461 | goto check_failed; | ||
462 | } | ||
463 | } | ||
464 | if (!fill_prealloc && info->extent_tree_prealloc_nr) { | ||
465 | u64 first = | ||
466 | info->extent_tree_prealloc[info->extent_tree_prealloc_nr - 1]; | ||
467 | if (ins->objectid + num_blocks > first && | ||
468 | ins->objectid <= info->extent_tree_prealloc[0]) { | ||
469 | search_start = info->extent_tree_prealloc[0] + 1; | ||
470 | WARN_ON(1); | ||
471 | goto check_failed; | ||
472 | } | ||
473 | } | ||
474 | if (fill_prealloc) { | ||
475 | int nr; | ||
476 | test_block = ins->objectid; | ||
477 | while(test_block < ins->objectid + ins->offset && | ||
478 | total_found < total_needed) { | ||
479 | nr = total_needed - total_found - 1; | ||
480 | BUG_ON(nr < 0); | ||
481 | root->fs_info->extent_tree_prealloc[nr] = | ||
482 | test_block; | ||
483 | total_found++; | ||
484 | test_block++; | ||
485 | } | ||
486 | if (total_found < total_needed) { | ||
487 | search_start = test_block; | ||
488 | goto check_failed; | ||
489 | } | ||
490 | root->fs_info->extent_tree_prealloc_nr = total_found; | ||
491 | } | ||
447 | root->fs_info->last_insert.objectid = ins->objectid; | 492 | root->fs_info->last_insert.objectid = ins->objectid; |
448 | ins->offset = num_blocks; | 493 | ins->offset = num_blocks; |
449 | btrfs_free_path(path); | 494 | btrfs_free_path(path); |
@@ -472,25 +517,35 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
472 | struct btrfs_fs_info *info = root->fs_info; | 517 | struct btrfs_fs_info *info = root->fs_info; |
473 | struct btrfs_root *extent_root = info->extent_root; | 518 | struct btrfs_root *extent_root = info->extent_root; |
474 | struct btrfs_extent_item extent_item; | 519 | struct btrfs_extent_item extent_item; |
520 | struct btrfs_key prealloc_key; | ||
475 | 521 | ||
476 | btrfs_set_extent_refs(&extent_item, 1); | 522 | btrfs_set_extent_refs(&extent_item, 1); |
477 | btrfs_set_extent_owner(&extent_item, owner); | 523 | btrfs_set_extent_owner(&extent_item, owner); |
478 | 524 | ||
479 | if (root == extent_root) { | 525 | if (root == extent_root) { |
480 | BUG_ON(extent_root->fs_info->current_insert.offset == 0); | 526 | int nr; |
527 | BUG_ON(info->extent_tree_prealloc_nr == 0); | ||
481 | BUG_ON(num_blocks != 1); | 528 | BUG_ON(num_blocks != 1); |
482 | BUG_ON(extent_root->fs_info->current_insert.flags == | ||
483 | extent_root->fs_info->current_insert.offset); | ||
484 | ins->offset = 1; | 529 | ins->offset = 1; |
485 | ins->objectid = extent_root->fs_info->current_insert.objectid + | 530 | info->extent_tree_prealloc_nr--; |
486 | extent_root->fs_info->current_insert.flags++; | 531 | nr = info->extent_tree_prealloc_nr; |
532 | ins->objectid = info->extent_tree_prealloc[nr]; | ||
533 | info->extent_tree_insert[info->extent_tree_insert_nr++] = | ||
534 | ins->objectid; | ||
487 | return 0; | 535 | return 0; |
488 | } | 536 | } |
537 | /* do the real allocation */ | ||
489 | ret = find_free_extent(trans, root, num_blocks, search_start, | 538 | ret = find_free_extent(trans, root, num_blocks, search_start, |
490 | search_end, ins); | 539 | search_end, ins); |
491 | if (ret) | 540 | if (ret) |
492 | return ret; | 541 | return ret; |
493 | 542 | ||
543 | /* then do prealloc for the extent tree */ | ||
544 | ret = find_free_extent(trans, root, 0, ins->objectid + ins->offset, | ||
545 | search_end, &prealloc_key); | ||
546 | if (ret) | ||
547 | return ret; | ||
548 | |||
494 | super_blocks_used = btrfs_super_blocks_used(info->disk_super); | 549 | super_blocks_used = btrfs_super_blocks_used(info->disk_super); |
495 | btrfs_set_super_blocks_used(info->disk_super, super_blocks_used + | 550 | btrfs_set_super_blocks_used(info->disk_super, super_blocks_used + |
496 | num_blocks); | 551 | num_blocks); |