Btrfs: allocator improvements, inode block groups
authorChris Mason <chris.mason@oracle.com>
Mon, 30 Apr 2007 19:25:45 +0000 (15:25 -0400)
committerDavid Woodhouse <dwmw2@hera.kernel.org>
Mon, 30 Apr 2007 19:25:45 +0000 (15:25 -0400)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/extent-tree.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h

index 43a4f1ddb3758e436cf042fde22fbb9634cac14e..6b50076b02d502d08b6b84f9bd1ae34af353f90b 100644 (file)
@@ -3,6 +3,7 @@
 
 struct btrfs_inode {
        struct btrfs_root *root;
+       struct btrfs_block_group_cache *block_group;
        struct btrfs_key location;
        struct inode vfs_inode;
 };
index b4783bf8bf4fc2729c1cedaacd272917fcb88885..dbd3f636dd3d324c3bdea49c6845078e0f660659 100644 (file)
@@ -61,7 +61,7 @@ static int btrfs_cow_block(struct btrfs_trans_handle *trans, struct btrfs_root
                *cow_ret = buf;
                return 0;
        }
-       cow = btrfs_alloc_free_block(trans, root);
+       cow = btrfs_alloc_free_block(trans, root, buf->b_blocknr);
        cow_node = btrfs_buffer_node(cow);
        if (buf->b_size != root->blocksize || cow->b_size != root->blocksize)
                WARN_ON(1);
@@ -800,7 +800,7 @@ static int insert_new_root(struct btrfs_trans_handle *trans, struct btrfs_root
        BUG_ON(path->nodes[level]);
        BUG_ON(path->nodes[level-1] != root->node);
 
-       t = btrfs_alloc_free_block(trans, root);
+       t = btrfs_alloc_free_block(trans, root, root->node->b_blocknr);
        c = btrfs_buffer_node(t);
        memset(c, 0, root->blocksize);
        btrfs_set_header_nritems(&c->header, 1);
@@ -905,7 +905,7 @@ static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root
        }
 
        c_nritems = btrfs_header_nritems(&c->header);
-       split_buffer = btrfs_alloc_free_block(trans, root);
+       split_buffer = btrfs_alloc_free_block(trans, root, t->b_blocknr);
        split = btrfs_buffer_node(split_buffer);
        btrfs_set_header_flags(&split->header, btrfs_header_flags(&c->header));
        btrfs_set_header_level(&split->header, btrfs_header_level(&c->header));
@@ -1277,7 +1277,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
        slot = path->slots[0];
        nritems = btrfs_header_nritems(&l->header);
        mid = (nritems + 1)/ 2;
-       right_buffer = btrfs_alloc_free_block(trans, root);
+       right_buffer = btrfs_alloc_free_block(trans, root, l_buf->b_blocknr);
        BUG_ON(!right_buffer);
        right = btrfs_buffer_leaf(right_buffer);
        memset(&right->header, 0, sizeof(right->header));
@@ -1374,7 +1374,7 @@ static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root
 
        if (!double_split)
                return ret;
-       right_buffer = btrfs_alloc_free_block(trans, root);
+       right_buffer = btrfs_alloc_free_block(trans, root, l_buf->b_blocknr);
        BUG_ON(!right_buffer);
        right = btrfs_buffer_leaf(right_buffer);
        memset(&right->header, 0, sizeof(right->header));
index c432222d40e39cc55b4185974bcea1a3190660be..e6bf9919536a64c20e243cd817778cf753262b80 100644 (file)
@@ -174,6 +174,7 @@ struct btrfs_inode_item {
        __le64 generation;
        __le64 size;
        __le64 nblocks;
+       __le64 block_group;
        __le32 nlink;
        __le32 uid;
        __le32 gid;
@@ -241,6 +242,7 @@ struct btrfs_device_item {
 
 /* tag for the radix tree of block groups in ram */
 #define BTRFS_BLOCK_GROUP_DIRTY 0
+#define BTRFS_BLOCK_GROUP_AVAIL 1
 #define BTRFS_BLOCK_GROUP_HINTS 8
 #define BTRFS_BLOCK_GROUP_SIZE (256 * 1024 * 1024)
 struct btrfs_block_group_item {
@@ -410,6 +412,17 @@ static inline void btrfs_set_inode_nblocks(struct btrfs_inode_item *i, u64 val)
        i->nblocks = cpu_to_le64(val);
 }
 
+static inline u64 btrfs_inode_block_group(struct btrfs_inode_item *i)
+{
+       return le64_to_cpu(i->block_group);
+}
+
+static inline void btrfs_set_inode_block_group(struct btrfs_inode_item *i,
+                                               u64 val)
+{
+       i->block_group = cpu_to_le64(val);
+}
+
 static inline u32 btrfs_inode_nlink(struct btrfs_inode_item *i)
 {
        return le32_to_cpu(i->nlink);
@@ -1054,10 +1067,13 @@ static inline void btrfs_mark_buffer_dirty(struct buffer_head *bh)
        btrfs_item_offset((leaf)->items + (slot))))
 
 /* extent-tree.c */
+struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
+                                                struct btrfs_block_group_cache
+                                                *hint, int data);
 int btrfs_inc_root_ref(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root);
 struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
-                                           struct btrfs_root *root);
+                                           struct btrfs_root *root, u64 hint);
 int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root, u64 owner,
                       u64 num_blocks, u64 search_start,
index 62051a36664a001e4836c07ba1ba70b7e9670aff..8b8cbe25fffbcd4109f959118b6ce325a4c8a54c 100644 (file)
@@ -12,42 +12,57 @@ 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 *btrfs_find_block_group(struct btrfs_root *root,
+                                                struct btrfs_block_group_cache
+                                                *hint, int data)
 {
        struct btrfs_block_group_cache *cache[8];
+       struct btrfs_block_group_cache *found_group = NULL;
        struct btrfs_fs_info *info = root->fs_info;
        u64 used;
-       u64 last;
+       u64 last = 0;
+       u64 hint_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;
+       int full_search = 0;
+       if (hint) {
+               used = btrfs_block_group_used(&hint->item);
+               if (used < (hint->key.offset * 2) / 3) {
+                       return hint;
+               }
+               radix_tree_tag_clear(&info->block_group_radix,
+                                    hint->key.objectid + hint->key.offset - 1,
+                                    BTRFS_BLOCK_GROUP_AVAIL);
+               last = hint->key.objectid + hint->key.offset;
+               hint_last = last;
+       } else {
+               hint_last = 0;
+               last = 0;
+       }
        while(1) {
                ret = radix_tree_gang_lookup_tag(&info->block_group_radix,
                                                 (void **)cache,
                                                 last, ARRAY_SIZE(cache),
-                                                BTRFS_BLOCK_GROUP_DIRTY);
+                                                BTRFS_BLOCK_GROUP_AVAIL);
                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)) {
+                       if (used < (cache[i]->key.offset * 2) / 3) {
                                info->block_group_cache = cache[i];
-                               cache[i]->last_alloc = cache[i]->first_free;
-                               return 0;
+                               found_group = cache[i];
+                               goto found;
                        }
+                       radix_tree_tag_clear(&info->block_group_radix,
+                                          cache[i]->key.objectid +
+                                          cache[i]->key.offset - 1,
+                                          BTRFS_BLOCK_GROUP_AVAIL);
                        last = cache[i]->key.objectid +
-                               cache[i]->key.offset - 1;
+                               cache[i]->key.offset;
                }
        }
-       last = 0;
+       last = hint_last;
+again:
        while(1) {
                ret = radix_tree_gang_lookup(&info->block_group_radix,
                                                 (void **)cache,
@@ -56,17 +71,32 @@ find_new:
                        break;
                for (i = 0; i < ret; i++) {
                        used = btrfs_block_group_used(&cache[i]->item);
-                       if (used < (cache[i]->key.offset * 3 / 2)) {
+                       if (used < cache[i]->key.offset) {
                                info->block_group_cache = cache[i];
-                               cache[i]->last_alloc = cache[i]->first_free;
-                               return 0;
+                               found_group = cache[i];
+                               goto found;
                        }
+                       radix_tree_tag_clear(&info->block_group_radix,
+                                          cache[i]->key.objectid +
+                                          cache[i]->key.offset - 1,
+                                          BTRFS_BLOCK_GROUP_AVAIL);
                        last = cache[i]->key.objectid +
-                               cache[i]->key.offset - 1;
+                               cache[i]->key.offset;
                }
        }
        info->block_group_cache = NULL;
-       return 0;
+       if (!full_search) {
+               last = 0;
+               full_search = 1;
+               goto again;
+       }
+found:
+       if (!found_group) {
+               ret = radix_tree_gang_lookup(&info->block_group_radix,
+                                            (void **)&found_group, 0, 1);
+               BUG_ON(ret != 1);
+       }
+       return found_group;
 }
 
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
@@ -243,6 +273,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
                                                    path, cache[i]);
                        if (err)
                                werr = err;
+                       cache[i]->last_alloc = cache[i]->first_free;
                }
        }
        btrfs_free_path(path);
@@ -322,10 +353,6 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, struct
                                                    btree_inode->i_blkbits));
                }
        }
-       if (root->fs_info->block_group_cache) {
-               root->fs_info->block_group_cache->last_alloc =
-                       root->fs_info->block_group_cache->first_free;
-       }
        return 0;
 }
 
@@ -532,22 +559,43 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
        int total_found = 0;
        int fill_prealloc = 0;
        int level;
+       int update_block_group = 0;
+       struct btrfs_block_group_cache *hint_block_group;
 
        path = btrfs_alloc_path();
        ins->flags = 0;
        btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
 
        level = btrfs_header_level(btrfs_buffer_header(root->node));
+       /* find search start here */
+       if (0 && search_start && num_blocks) {
+               u64 used;
+               ret = radix_tree_gang_lookup(&info->block_group_radix,
+                                            (void **)&hint_block_group,
+                                            search_start, 1);
+               if (ret) {
+                       used = btrfs_block_group_used(&hint_block_group->item);
+                       if (used > (hint_block_group->key.offset * 9) / 10)
+                               search_start = 0;
+                       else if (search_start < hint_block_group->last_alloc)
+                               search_start = hint_block_group->last_alloc;
+               } else {
+                       search_start = 0;
+               }
+       }
        if (num_blocks == 0) {
                fill_prealloc = 1;
                num_blocks = 1;
                total_needed = (min(level + 1, BTRFS_MAX_LEVEL) + 2) * 3;
        }
-       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;
-
+       if (1 || !search_start) {
+               trans->block_group = btrfs_find_block_group(root,
+                                                           trans->block_group,
+                                                           0);
+               if (trans->block_group->last_alloc > search_start)
+                       search_start = trans->block_group->last_alloc;
+               update_block_group = 1;
+       }
 check_failed:
        btrfs_init_path(path);
        ins->objectid = search_start;
@@ -662,11 +710,13 @@ check_pending:
                }
                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;
+       if (update_block_group) {
+               ret = radix_tree_gang_lookup(&info->block_group_radix,
+                                            (void **)&trans->block_group,
+                                            ins->objectid, 1);
+               if (ret) {
+                       trans->block_group->last_alloc = ins->objectid;
+               }
        }
        ins->offset = num_blocks;
        btrfs_free_path(path);
@@ -747,14 +797,14 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
  * returns the tree buffer or NULL.
  */
 struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
-                                          struct btrfs_root *root)
+                                          struct btrfs_root *root, u64 hint)
 {
        struct btrfs_key ins;
        int ret;
        struct buffer_head *buf;
 
        ret = btrfs_alloc_extent(trans, root, root->root_key.objectid,
-                                1, 0, (unsigned long)-1, &ins);
+                                1, hint, (unsigned long)-1, &ins);
        if (ret) {
                BUG();
                return NULL;
@@ -975,6 +1025,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
        struct btrfs_key found_key;
        struct btrfs_leaf *leaf;
        u64 group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->blocksize;
+       u64 used;
 
        root = root->fs_info->extent_root;
        key.objectid = 0;
@@ -1005,8 +1056,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;
+               cache->last_alloc = cache->key.objectid;
+               cache->first_free = cache->key.objectid;
                key.objectid = found_key.objectid + found_key.offset;
                btrfs_release_path(root, path);
                ret = radix_tree_insert(&root->fs_info->block_group_radix,
@@ -1014,6 +1065,13 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                                        found_key.offset - 1,
                                        (void *)cache);
                BUG_ON(ret);
+               used = btrfs_block_group_used(bi);
+               if (used < (key.offset * 2) / 3) {
+                       radix_tree_tag_set(&root->fs_info->block_group_radix,
+                                          found_key.objectid +
+                                          found_key.offset - 1,
+                                          BTRFS_BLOCK_GROUP_AVAIL);
+               }
                if (key.objectid >=
                    btrfs_super_total_blocks(root->fs_info->disk_super))
                        break;
index 1890e8648dbde17da72419cb7d8d466bdc1d3a19..7ecbe7c8618640f26c3d02443ca14945393fafd8 100644 (file)
@@ -52,6 +52,8 @@ static void btrfs_read_locked_inode(struct inode *inode)
        struct btrfs_inode_item *inode_item;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_key location;
+       struct btrfs_block_group_cache *alloc_group;
+       u64 alloc_group_block;
        int ret;
 
        path = btrfs_alloc_path();
@@ -82,6 +84,12 @@ static void btrfs_read_locked_inode(struct inode *inode)
        inode->i_ctime.tv_nsec = btrfs_timespec_nsec(&inode_item->ctime);
        inode->i_blocks = btrfs_inode_nblocks(inode_item);
        inode->i_generation = btrfs_inode_generation(inode_item);
+       alloc_group_block = btrfs_inode_block_group(inode_item);
+       ret = radix_tree_gang_lookup(&root->fs_info->block_group_radix,
+                                    (void **)&alloc_group,
+                                    alloc_group_block, 1);
+       BUG_ON(!ret);
+       BTRFS_I(inode)->block_group = alloc_group;
 
        btrfs_free_path(path);
        inode_item = NULL;
@@ -136,6 +144,8 @@ static void fill_inode_item(struct btrfs_inode_item *item,
        btrfs_set_timespec_nsec(&item->ctime, inode->i_ctime.tv_nsec);
        btrfs_set_inode_nblocks(item, inode->i_blocks);
        btrfs_set_inode_generation(item, inode->i_generation);
+       btrfs_set_inode_block_group(item,
+                                   BTRFS_I(inode)->block_group->key.objectid);
 }
 
 
@@ -237,6 +247,7 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
        root = BTRFS_I(dir)->root;
        mutex_lock(&root->fs_info->fs_mutex);
        trans = btrfs_start_transaction(root, 1);
+       btrfs_set_trans_block_group(trans, dir);
        ret = btrfs_unlink_trans(trans, root, dir, dentry);
        btrfs_end_transaction(trans, root);
        mutex_unlock(&root->fs_info->fs_mutex);
@@ -262,6 +273,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
        btrfs_init_path(path);
        mutex_lock(&root->fs_info->fs_mutex);
        trans = btrfs_start_transaction(root, 1);
+       btrfs_set_trans_block_group(trans, dir);
        key.objectid = inode->i_ino;
        key.offset = (u64)-1;
        key.flags = (u32)-1;
@@ -429,6 +441,7 @@ static void btrfs_delete_inode(struct inode *inode)
        inode->i_size = 0;
        mutex_lock(&root->fs_info->fs_mutex);
        trans = btrfs_start_transaction(root, 1);
+       btrfs_set_trans_block_group(trans, inode);
        if (S_ISREG(inode->i_mode)) {
                ret = btrfs_truncate_in_trans(trans, root, inode);
                BUG_ON(ret);
@@ -731,6 +744,7 @@ static int btrfs_write_inode(struct inode *inode, int wait)
        if (wait) {
                mutex_lock(&root->fs_info->fs_mutex);
                trans = btrfs_start_transaction(root, 1);
+               btrfs_set_trans_block_group(trans, inode);
                ret = btrfs_commit_transaction(trans, root);
                mutex_unlock(&root->fs_info->fs_mutex);
        }
@@ -744,6 +758,7 @@ static void btrfs_dirty_inode(struct inode *inode)
 
        mutex_lock(&root->fs_info->fs_mutex);
        trans = btrfs_start_transaction(root, 1);
+       btrfs_set_trans_block_group(trans, inode);
        btrfs_update_inode(trans, root, inode);
        btrfs_end_transaction(trans, root);
        mutex_unlock(&root->fs_info->fs_mutex);
@@ -751,7 +766,9 @@ static void btrfs_dirty_inode(struct inode *inode)
 
 static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root,
-                                    u64 objectid, int mode)
+                                    u64 objectid,
+                                    struct btrfs_block_group_cache *group,
+                                    int mode)
 {
        struct inode *inode;
        struct btrfs_inode_item inode_item;
@@ -763,6 +780,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
                return ERR_PTR(-ENOMEM);
 
        BTRFS_I(inode)->root = root;
+       group = btrfs_find_block_group(root, group, 0);
+       BTRFS_I(inode)->block_group = group;
 
        inode->i_uid = current->fsuid;
        inode->i_gid = current->fsgid;
@@ -832,6 +851,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
 
        mutex_lock(&root->fs_info->fs_mutex);
        trans = btrfs_start_transaction(root, 1);
+       btrfs_set_trans_block_group(trans, dir);
 
        err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid);
        if (err) {
@@ -839,11 +859,13 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
                goto out_unlock;
        }
 
-       inode = btrfs_new_inode(trans, root, objectid, mode);
+       inode = btrfs_new_inode(trans, root, objectid,
+                               BTRFS_I(dir)->block_group, mode);
        err = PTR_ERR(inode);
        if (IS_ERR(inode))
                goto out_unlock;
-       // FIXME mark the inode dirty
+
+       btrfs_set_trans_block_group(trans, inode);
        err = btrfs_add_nondir(trans, dentry, inode);
        if (err)
                drop_inode = 1;
@@ -853,6 +875,8 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
                inode->i_op = &btrfs_file_inode_operations;
        }
        dir->i_sb->s_dirt = 1;
+       btrfs_update_inode_block_group(trans, inode);
+       btrfs_update_inode_block_group(trans, dir);
 out_unlock:
        btrfs_end_transaction(trans, root);
        mutex_unlock(&root->fs_info->fs_mutex);
@@ -904,6 +928,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        mutex_lock(&root->fs_info->fs_mutex);
        trans = btrfs_start_transaction(root, 1);
+       btrfs_set_trans_block_group(trans, dir);
        if (IS_ERR(trans)) {
                err = PTR_ERR(trans);
                goto out_unlock;
@@ -915,7 +940,8 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
                goto out_unlock;
        }
 
-       inode = btrfs_new_inode(trans, root, objectid, S_IFDIR | mode);
+       inode = btrfs_new_inode(trans, root, objectid,
+                               BTRFS_I(dir)->block_group, S_IFDIR | mode);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto out_fail;
@@ -923,6 +949,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        drop_on_err = 1;
        inode->i_op = &btrfs_dir_inode_operations;
        inode->i_fop = &btrfs_dir_file_operations;
+       btrfs_set_trans_block_group(trans, inode);
 
        err = btrfs_make_empty_dir(trans, root, inode->i_ino, dir->i_ino);
        if (err)
@@ -938,6 +965,8 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        d_instantiate(dentry, inode);
        drop_on_err = 0;
        dir->i_sb->s_dirt = 1;
+       btrfs_update_inode_block_group(trans, inode);
+       btrfs_update_inode_block_group(trans, dir);
 
 out_fail:
        btrfs_end_transaction(trans, root);
@@ -1349,6 +1378,7 @@ static void btrfs_truncate(struct inode *inode)
        /* FIXME, add redo link to tree so we don't leak on crash */
        mutex_lock(&root->fs_info->fs_mutex);
        trans = btrfs_start_transaction(root, 1);
+       btrfs_set_trans_block_group(trans, inode);
        ret = btrfs_truncate_in_trans(trans, root, inode);
        BUG_ON(ret);
        ret = btrfs_end_transaction(trans, root);
@@ -1445,6 +1475,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
 
                mutex_lock(&root->fs_info->fs_mutex);
                trans = btrfs_start_transaction(root, 1);
+               btrfs_set_trans_block_group(trans, inode);
 
                bh = page_buffers(pages[i]);
                if (buffer_mapped(bh) && bh->b_blocknr == 0) {
@@ -1481,6 +1512,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
                        kunmap(pages[i]);
                }
                SetPageChecked(pages[i]);
+               btrfs_update_inode_block_group(trans, inode);
                ret = btrfs_end_transaction(trans, root);
                BUG_ON(ret);
                mutex_unlock(&root->fs_info->fs_mutex);
@@ -1821,6 +1853,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
                mutex_unlock(&root->fs_info->fs_mutex);
                goto out_unlock;
        }
+       btrfs_set_trans_block_group(trans, inode);
        /* FIXME blocksize != 4096 */
        inode->i_blocks += num_blocks << 3;
        if (start_pos < inode->i_size) {
@@ -1845,6 +1878,7 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
        }
        BUG_ON(ret);
        alloc_extent_start = ins.objectid;
+       btrfs_update_inode_block_group(trans, inode);
        ret = btrfs_end_transaction(trans, root);
        mutex_unlock(&root->fs_info->fs_mutex);
 
@@ -2017,6 +2051,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
        struct btrfs_leaf *leaf;
        struct btrfs_root *new_root;
        struct inode *inode;
+       struct inode *dir;
        int ret;
        u64 objectid;
        u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
@@ -2025,7 +2060,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
        trans = btrfs_start_transaction(root, 1);
        BUG_ON(!trans);
 
-       subvol = btrfs_alloc_free_block(trans, root);
+       subvol = btrfs_alloc_free_block(trans, root, 0);
        if (subvol == NULL)
                return -ENOSPC;
        leaf = btrfs_buffer_leaf(subvol);
@@ -2069,10 +2104,9 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
         * insert the directory item
         */
        key.offset = (u64)-1;
+       dir = root->fs_info->sb->s_root->d_inode;
        ret = btrfs_insert_dir_item(trans, root->fs_info->tree_root,
-                                   name, namelen,
-                                   root->fs_info->sb->s_root->d_inode->i_ino,
-                                   &key, 0);
+                                   name, namelen, dir->i_ino, &key, 0);
        BUG_ON(ret);
 
        ret = btrfs_commit_transaction(trans, root);
@@ -2084,7 +2118,8 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
        trans = btrfs_start_transaction(new_root, 1);
        BUG_ON(!trans);
 
-       inode = btrfs_new_inode(trans, new_root, new_dirid, S_IFDIR | 0700);
+       inode = btrfs_new_inode(trans, new_root, new_dirid,
+                               BTRFS_I(dir)->block_group, S_IFDIR | 0700);
        inode->i_op = &btrfs_dir_inode_operations;
        inode->i_fop = &btrfs_dir_file_operations;
 
index f9b8864dcc4072bf7697d6fb06f0ba36c38cd4f1..bdbf514c111f5a90505064fec2abd12768cce8ac 100644 (file)
@@ -77,6 +77,7 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
        h->transaction = root->fs_info->running_transaction;
        h->blocks_reserved = num_blocks;
        h->blocks_used = 0;
+       h->block_group = NULL;
        root->fs_info->running_transaction->use_count++;
        mutex_unlock(&root->fs_info->trans_mutex);
        h->magic = h->magic2 = TRANS_MAGIC;
index afe42d167cee09b85fff1c98b04ad7bb159a6873..b5378119e76cf7251b77f4292f41f547df8bb94b 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef __TRANSACTION__
 #define __TRANSACTION__
+#include "btrfs_inode.h"
 
 struct btrfs_transaction {
        u64 transid;
@@ -20,10 +21,24 @@ struct btrfs_trans_handle {
        unsigned long blocks_reserved;
        unsigned long blocks_used;
        struct btrfs_transaction *transaction;
+       struct btrfs_block_group_cache *block_group;
        int magic2;
 };
 
 
+static inline void btrfs_set_trans_block_group(struct btrfs_trans_handle *trans,
+                                              struct inode *inode)
+{
+       trans->block_group = BTRFS_I(inode)->block_group;
+}
+
+static inline void btrfs_update_inode_block_group(struct
+                                                 btrfs_trans_handle *trans,
+                                                 struct inode *inode)
+{
+       BTRFS_I(inode)->block_group = trans->block_group;
+}
+
 int btrfs_end_transaction(struct btrfs_trans_handle *trans,
                          struct btrfs_root *root);
 struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
This page took 0.036111 seconds and 5 git commands to generate.