Btrfs: more block allocator work
authorChris Mason <chris.mason@oracle.com>
Fri, 27 Apr 2007 14:08:34 +0000 (10:08 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Fri, 27 Apr 2007 14:08:34 +0000 (10:08 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/super.c

index 419917279e65aa730bc0a3dc67e008d9576131bd..c432222d40e39cc55b4185974bcea1a3190660be 100644 (file)
@@ -250,6 +250,8 @@ struct btrfs_block_group_item {
 struct btrfs_block_group_cache {
        struct btrfs_key key;
        struct btrfs_block_group_item item;
+       u64 first_free;
+       u64 last_alloc;
 };
 
 struct crypto_hash;
@@ -257,7 +259,7 @@ struct btrfs_fs_info {
        struct btrfs_root *extent_root;
        struct btrfs_root *tree_root;
        struct btrfs_root *dev_root;
-       struct btrfs_key last_insert;
+       struct btrfs_block_group_cache *block_group_cache;
        struct radix_tree_root fs_roots_radix;
        struct radix_tree_root pending_del_radix;
        struct radix_tree_root pinned_radix;
index 1c27eb645510739550d153db4cb12fc5303b7cda..2489ffa5fb38425693ea4492d48c7851ec3b46fd 100644 (file)
@@ -558,7 +558,7 @@ struct btrfs_root *open_ctree(struct super_block *sb)
        }
        mutex_init(&fs_info->trans_mutex);
        mutex_init(&fs_info->fs_mutex);
-       memset(&fs_info->last_insert, 0, sizeof(fs_info->last_insert));
+       fs_info->block_group_cache = NULL;
 
        __setup_root(sb->s_blocksize, dev_root,
                     fs_info, BTRFS_DEV_TREE_OBJECTID);
index 0bb4fc83cfd619454c2c6bc8e46b714983a72674..71e3b311fc42feb20a2c973fd3e3da6e1b61c7f8 100644 (file)
@@ -12,6 +12,63 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
 static int del_pending_extents(struct btrfs_trans_handle *trans, struct
                               btrfs_root *extent_root);
 
+static int find_search_start(struct btrfs_root *root, int data)
+{
+       struct btrfs_block_group_cache *cache[8];
+       struct btrfs_fs_info *info = root->fs_info;
+       u64 used;
+       u64 last;
+       int i;
+       int ret;
+
+       cache[0] = info->block_group_cache;
+       if (!cache[0])
+               goto find_new;
+       used = btrfs_block_group_used(&cache[0]->item);
+       if (used < (cache[0]->key.offset * 3 / 2))
+               return 0;
+find_new:
+       last = 0;
+       while(1) {
+               ret = radix_tree_gang_lookup_tag(&info->block_group_radix,
+                                                (void **)cache,
+                                                last, ARRAY_SIZE(cache),
+                                                BTRFS_BLOCK_GROUP_DIRTY);
+               if (!ret)
+                       break;
+               for (i = 0; i < ret; i++) {
+                       used = btrfs_block_group_used(&cache[i]->item);
+                       if (used < (cache[i]->key.offset * 3 / 2)) {
+                               info->block_group_cache = cache[i];
+                               cache[i]->last_alloc = cache[i]->first_free;
+                               return 0;
+                       }
+                       last = cache[i]->key.objectid +
+                               cache[i]->key.offset - 1;
+               }
+       }
+       last = 0;
+       while(1) {
+               ret = radix_tree_gang_lookup(&info->block_group_radix,
+                                                (void **)cache,
+                                                last, ARRAY_SIZE(cache));
+               if (!ret)
+                       break;
+               for (i = 0; i < ret; i++) {
+                       used = btrfs_block_group_used(&cache[i]->item);
+                       if (used < (cache[i]->key.offset * 3 / 2)) {
+                               info->block_group_cache = cache[i];
+                               cache[i]->last_alloc = cache[i]->first_free;
+                               return 0;
+                       }
+                       last = cache[i]->key.objectid +
+                               cache[i]->key.offset - 1;
+               }
+       }
+       info->block_group_cache = NULL;
+       return 0;
+}
+
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root,
                                u64 blocknr, u64 num_blocks)
@@ -205,8 +262,11 @@ static int update_block_group(struct btrfs_trans_handle *trans,
        while(total) {
                ret = radix_tree_gang_lookup(&info->block_group_radix,
                                             (void **)&cache, blocknr, 1);
-               if (!ret)
+               if (!ret) {
+                       printk(KERN_CRIT "blocknr %Lu lookup failed\n",
+                              blocknr);
                        return -1;
+               }
                block_in_group = blocknr - cache->key.objectid;
                WARN_ON(block_in_group > cache->key.offset);
                radix_tree_tag_set(&info->block_group_radix,
@@ -217,10 +277,15 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                num = min(total, cache->key.offset - block_in_group);
                total -= num;
                blocknr += num;
-               if (alloc)
+               if (alloc) {
                        old_val += num;
-               else
+                       if (blocknr > cache->last_alloc)
+                               cache->last_alloc = blocknr;
+               } else {
                        old_val -= num;
+                       if (blocknr < cache->first_free)
+                               cache->first_free = blocknr;
+               }
                btrfs_set_block_group_used(&cache->item, old_val);
        }
        return 0;
@@ -246,9 +311,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
                        clear_radix_bit(pinned_radix, gang[i]);
                }
        }
-       if (root->fs_info->last_insert.objectid > first)
-               root->fs_info->last_insert.objectid = first;
-       root->fs_info->last_insert.offset = 0;
+       root->fs_info->block_group_cache = NULL;
        return 0;
 }
 
@@ -466,8 +529,10 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
                num_blocks = 1;
                total_needed = min(level + 2, BTRFS_MAX_LEVEL) * 3;
        }
-       if (info->last_insert.objectid > search_start)
-               search_start = info->last_insert.objectid;
+       find_search_start(root, 0);
+       if (info->block_group_cache &&
+           info->block_group_cache->last_alloc > search_start)
+               search_start = info->block_group_cache->last_alloc;
 
 check_failed:
        btrfs_init_path(path);
@@ -567,8 +632,7 @@ check_pending:
                      total_found < total_needed) {
                        nr = total_needed - total_found - 1;
                        BUG_ON(nr < 0);
-                       root->fs_info->extent_tree_prealloc[nr] =
-                               test_block;
+                       info->extent_tree_prealloc[nr] = test_block;
                        total_found++;
                        test_block++;
                }
@@ -576,9 +640,14 @@ check_pending:
                        search_start = test_block;
                        goto check_failed;
                }
-               root->fs_info->extent_tree_prealloc_nr = total_found;
+               info->extent_tree_prealloc_nr = total_found;
+       }
+       ret = radix_tree_gang_lookup(&info->block_group_radix,
+                                    (void **)&info->block_group_cache,
+                                    ins->objectid, 1);
+       if (ret) {
+               info->block_group_cache->last_alloc = ins->objectid;
        }
-       root->fs_info->last_insert.objectid = ins->objectid;
        ins->offset = num_blocks;
        btrfs_free_path(path);
        return 0;
@@ -915,6 +984,8 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                                    struct btrfs_block_group_item);
                memcpy(&cache->item, bi, sizeof(*bi));
                memcpy(&cache->key, &found_key, sizeof(found_key));
+               cache->last_alloc = 0;
+               cache->first_free = 0;
                key.objectid = found_key.objectid + found_key.offset;
                btrfs_release_path(root, path);
                ret = radix_tree_insert(&root->fs_info->block_group_radix,
index edcebf79b04a0a8d0a7f4a13e9b16b827b0dd419..a10e902d31025b29deace9200ba64f58bab4d2df 100644 (file)
@@ -223,6 +223,7 @@ err:
                btrfs_update_inode(trans, root, dir);
                drop_nlink(dentry->d_inode);
                btrfs_update_inode(trans, root, dentry->d_inode);
+               dir->i_sb->s_dirt = 1;
        }
        return ret;
 }
@@ -411,6 +412,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans,
 error:
        btrfs_release_path(root, path);
        btrfs_free_path(path);
+       inode->i_sb->s_dirt = 1;
        return ret;
 }
 
@@ -935,6 +937,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                goto out_fail;
        d_instantiate(dentry, inode);
        drop_on_err = 0;
+       dir->i_sb->s_dirt = 1;
 
 out_fail:
        btrfs_end_transaction(trans, root);