Commit 31f3c99b authored by Chris Mason's avatar Chris Mason Committed by David Woodhouse

Btrfs: allocator improvements, inode block groups

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