diff options
| -rw-r--r-- | fs/btrfs/ctree.h | 4 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/extent-tree.c | 95 | ||||
| -rw-r--r-- | fs/btrfs/super.c | 3 |
4 files changed, 90 insertions, 14 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 419917279e65..c432222d40e3 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -250,6 +250,8 @@ struct btrfs_block_group_item { | |||
| 250 | struct btrfs_block_group_cache { | 250 | struct btrfs_block_group_cache { |
| 251 | struct btrfs_key key; | 251 | struct btrfs_key key; |
| 252 | struct btrfs_block_group_item item; | 252 | struct btrfs_block_group_item item; |
| 253 | u64 first_free; | ||
| 254 | u64 last_alloc; | ||
| 253 | }; | 255 | }; |
| 254 | 256 | ||
| 255 | struct crypto_hash; | 257 | struct crypto_hash; |
| @@ -257,7 +259,7 @@ struct btrfs_fs_info { | |||
| 257 | struct btrfs_root *extent_root; | 259 | struct btrfs_root *extent_root; |
| 258 | struct btrfs_root *tree_root; | 260 | struct btrfs_root *tree_root; |
| 259 | struct btrfs_root *dev_root; | 261 | struct btrfs_root *dev_root; |
| 260 | struct btrfs_key last_insert; | 262 | struct btrfs_block_group_cache *block_group_cache; |
| 261 | struct radix_tree_root fs_roots_radix; | 263 | struct radix_tree_root fs_roots_radix; |
| 262 | struct radix_tree_root pending_del_radix; | 264 | struct radix_tree_root pending_del_radix; |
| 263 | struct radix_tree_root pinned_radix; | 265 | struct radix_tree_root pinned_radix; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 1c27eb645510..2489ffa5fb38 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -558,7 +558,7 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
| 558 | } | 558 | } |
| 559 | mutex_init(&fs_info->trans_mutex); | 559 | mutex_init(&fs_info->trans_mutex); |
| 560 | mutex_init(&fs_info->fs_mutex); | 560 | mutex_init(&fs_info->fs_mutex); |
| 561 | memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert)); | 561 | fs_info->block_group_cache = NULL; |
| 562 | 562 | ||
| 563 | __setup_root(sb->s_blocksize, dev_root, | 563 | __setup_root(sb->s_blocksize, dev_root, |
| 564 | fs_info, BTRFS_DEV_TREE_OBJECTID); | 564 | fs_info, BTRFS_DEV_TREE_OBJECTID); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 0bb4fc83cfd6..71e3b311fc42 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
| @@ -12,6 +12,63 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct | |||
| 12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct | 12 | static int del_pending_extents(struct btrfs_trans_handle *trans, struct |
| 13 | btrfs_root *extent_root); | 13 | btrfs_root *extent_root); |
| 14 | 14 | ||
| 15 | static int find_search_start(struct btrfs_root *root, int data) | ||
| 16 | { | ||
| 17 | struct btrfs_block_group_cache *cache[8]; | ||
| 18 | struct btrfs_fs_info *info = root->fs_info; | ||
| 19 | u64 used; | ||
| 20 | u64 last; | ||
| 21 | int i; | ||
| 22 | int ret; | ||
| 23 | |||
| 24 | cache[0] = info->block_group_cache; | ||
| 25 | if (!cache[0]) | ||
| 26 | goto find_new; | ||
| 27 | used = btrfs_block_group_used(&cache[0]->item); | ||
| 28 | if (used < (cache[0]->key.offset * 3 / 2)) | ||
| 29 | return 0; | ||
| 30 | find_new: | ||
| 31 | last = 0; | ||
| 32 | while(1) { | ||
| 33 | ret = radix_tree_gang_lookup_tag(&info->block_group_radix, | ||
| 34 | (void **)cache, | ||
| 35 | last, ARRAY_SIZE(cache), | ||
| 36 | BTRFS_BLOCK_GROUP_DIRTY); | ||
| 37 | if (!ret) | ||
| 38 | break; | ||
| 39 | for (i = 0; i < ret; i++) { | ||
| 40 | used = btrfs_block_group_used(&cache[i]->item); | ||
| 41 | if (used < (cache[i]->key.offset * 3 / 2)) { | ||
| 42 | info->block_group_cache = cache[i]; | ||
| 43 | cache[i]->last_alloc = cache[i]->first_free; | ||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | last = cache[i]->key.objectid + | ||
| 47 | cache[i]->key.offset - 1; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | last = 0; | ||
| 51 | while(1) { | ||
| 52 | ret = radix_tree_gang_lookup(&info->block_group_radix, | ||
| 53 | (void **)cache, | ||
| 54 | last, ARRAY_SIZE(cache)); | ||
| 55 | if (!ret) | ||
| 56 | break; | ||
| 57 | for (i = 0; i < ret; i++) { | ||
| 58 | used = btrfs_block_group_used(&cache[i]->item); | ||
| 59 | if (used < (cache[i]->key.offset * 3 / 2)) { | ||
| 60 | info->block_group_cache = cache[i]; | ||
| 61 | cache[i]->last_alloc = cache[i]->first_free; | ||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | last = cache[i]->key.objectid + | ||
| 65 | cache[i]->key.offset - 1; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | info->block_group_cache = NULL; | ||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 15 | int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | 72 | int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, |
| 16 | struct btrfs_root *root, | 73 | struct btrfs_root *root, |
| 17 | u64 blocknr, u64 num_blocks) | 74 | u64 blocknr, u64 num_blocks) |
| @@ -205,8 +262,11 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
| 205 | while(total) { | 262 | while(total) { |
| 206 | ret = radix_tree_gang_lookup(&info->block_group_radix, | 263 | ret = radix_tree_gang_lookup(&info->block_group_radix, |
| 207 | (void **)&cache, blocknr, 1); | 264 | (void **)&cache, blocknr, 1); |
| 208 | if (!ret) | 265 | if (!ret) { |
| 266 | printk(KERN_CRIT "blocknr %Lu lookup failed\n", | ||
| 267 | blocknr); | ||
| 209 | return -1; | 268 | return -1; |
| 269 | } | ||
| 210 | block_in_group = blocknr - cache->key.objectid; | 270 | block_in_group = blocknr - cache->key.objectid; |
| 211 | WARN_ON(block_in_group > cache->key.offset); | 271 | WARN_ON(block_in_group > cache->key.offset); |
| 212 | radix_tree_tag_set(&info->block_group_radix, | 272 | radix_tree_tag_set(&info->block_group_radix, |
| @@ -217,10 +277,15 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
| 217 | num = min(total, cache->key.offset - block_in_group); | 277 | num = min(total, cache->key.offset - block_in_group); |
| 218 | total -= num; | 278 | total -= num; |
| 219 | blocknr += num; | 279 | blocknr += num; |
| 220 | if (alloc) | 280 | if (alloc) { |
| 221 | old_val += num; | 281 | old_val += num; |
| 222 | else | 282 | if (blocknr > cache->last_alloc) |
| 283 | cache->last_alloc = blocknr; | ||
| 284 | } else { | ||
| 223 | old_val -= num; | 285 | old_val -= num; |
| 286 | if (blocknr < cache->first_free) | ||
| 287 | cache->first_free = blocknr; | ||
| 288 | } | ||
| 224 | btrfs_set_block_group_used(&cache->item, old_val); | 289 | btrfs_set_block_group_used(&cache->item, old_val); |
| 225 | } | 290 | } |
| 226 | return 0; | 291 | return 0; |
| @@ -246,9 +311,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct | |||
| 246 | clear_radix_bit(pinned_radix, gang[i]); | 311 | clear_radix_bit(pinned_radix, gang[i]); |
| 247 | } | 312 | } |
| 248 | } | 313 | } |
| 249 | if (root->fs_info->last_insert.objectid > first) | 314 | root->fs_info->block_group_cache = NULL; |
| 250 | root->fs_info->last_insert.objectid = first; | ||
| 251 | root->fs_info->last_insert.offset = 0; | ||
| 252 | return 0; | 315 | return 0; |
| 253 | } | 316 | } |
| 254 | 317 | ||
| @@ -466,8 +529,10 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
| 466 | num_blocks = 1; | 529 | num_blocks = 1; |
| 467 | total_needed = min(level + 2, BTRFS_MAX_LEVEL) * 3; | 530 | total_needed = min(level + 2, BTRFS_MAX_LEVEL) * 3; |
| 468 | } | 531 | } |
| 469 | if (info->last_insert.objectid > search_start) | 532 | find_search_start(root, 0); |
| 470 | search_start = info->last_insert.objectid; | 533 | if (info->block_group_cache && |
| 534 | info->block_group_cache->last_alloc > search_start) | ||
| 535 | search_start = info->block_group_cache->last_alloc; | ||
| 471 | 536 | ||
| 472 | check_failed: | 537 | check_failed: |
| 473 | btrfs_init_path(path); | 538 | btrfs_init_path(path); |
| @@ -567,8 +632,7 @@ check_pending: | |||
| 567 | total_found < total_needed) { | 632 | total_found < total_needed) { |
| 568 | nr = total_needed - total_found - 1; | 633 | nr = total_needed - total_found - 1; |
| 569 | BUG_ON(nr < 0); | 634 | BUG_ON(nr < 0); |
| 570 | root->fs_info->extent_tree_prealloc[nr] = | 635 | info->extent_tree_prealloc[nr] = test_block; |
| 571 | test_block; | ||
| 572 | total_found++; | 636 | total_found++; |
| 573 | test_block++; | 637 | test_block++; |
| 574 | } | 638 | } |
| @@ -576,9 +640,14 @@ check_pending: | |||
| 576 | search_start = test_block; | 640 | search_start = test_block; |
| 577 | goto check_failed; | 641 | goto check_failed; |
| 578 | } | 642 | } |
| 579 | root->fs_info->extent_tree_prealloc_nr = total_found; | 643 | info->extent_tree_prealloc_nr = total_found; |
| 644 | } | ||
| 645 | ret = radix_tree_gang_lookup(&info->block_group_radix, | ||
| 646 | (void **)&info->block_group_cache, | ||
| 647 | ins->objectid, 1); | ||
| 648 | if (ret) { | ||
| 649 | info->block_group_cache->last_alloc = ins->objectid; | ||
| 580 | } | 650 | } |
| 581 | root->fs_info->last_insert.objectid = ins->objectid; | ||
| 582 | ins->offset = num_blocks; | 651 | ins->offset = num_blocks; |
| 583 | btrfs_free_path(path); | 652 | btrfs_free_path(path); |
| 584 | return 0; | 653 | return 0; |
| @@ -915,6 +984,8 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
| 915 | struct btrfs_block_group_item); | 984 | struct btrfs_block_group_item); |
| 916 | memcpy(&cache->item, bi, sizeof(*bi)); | 985 | memcpy(&cache->item, bi, sizeof(*bi)); |
| 917 | memcpy(&cache->key, &found_key, sizeof(found_key)); | 986 | memcpy(&cache->key, &found_key, sizeof(found_key)); |
| 987 | cache->last_alloc = 0; | ||
| 988 | cache->first_free = 0; | ||
| 918 | key.objectid = found_key.objectid + found_key.offset; | 989 | key.objectid = found_key.objectid + found_key.offset; |
| 919 | btrfs_release_path(root, path); | 990 | btrfs_release_path(root, path); |
| 920 | ret = radix_tree_insert(&root->fs_info->block_group_radix, | 991 | ret = radix_tree_insert(&root->fs_info->block_group_radix, |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index edcebf79b04a..a10e902d3102 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
| @@ -223,6 +223,7 @@ err: | |||
| 223 | btrfs_update_inode(trans, root, dir); | 223 | btrfs_update_inode(trans, root, dir); |
| 224 | drop_nlink(dentry->d_inode); | 224 | drop_nlink(dentry->d_inode); |
| 225 | btrfs_update_inode(trans, root, dentry->d_inode); | 225 | btrfs_update_inode(trans, root, dentry->d_inode); |
| 226 | dir->i_sb->s_dirt = 1; | ||
| 226 | } | 227 | } |
| 227 | return ret; | 228 | return ret; |
| 228 | } | 229 | } |
| @@ -411,6 +412,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
| 411 | error: | 412 | error: |
| 412 | btrfs_release_path(root, path); | 413 | btrfs_release_path(root, path); |
| 413 | btrfs_free_path(path); | 414 | btrfs_free_path(path); |
| 415 | inode->i_sb->s_dirt = 1; | ||
| 414 | return ret; | 416 | return ret; |
| 415 | } | 417 | } |
| 416 | 418 | ||
| @@ -935,6 +937,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 935 | goto out_fail; | 937 | goto out_fail; |
| 936 | d_instantiate(dentry, inode); | 938 | d_instantiate(dentry, inode); |
| 937 | drop_on_err = 0; | 939 | drop_on_err = 0; |
| 940 | dir->i_sb->s_dirt = 1; | ||
| 938 | 941 | ||
| 939 | out_fail: | 942 | out_fail: |
| 940 | btrfs_end_transaction(trans, root); | 943 | btrfs_end_transaction(trans, root); |
