Btrfs: allocator improvements, inode block groups
Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
committed by
David Woodhouse
parent
308535a05e
commit
31f3c99b73
@@ -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
|
|||||||
*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
|
|||||||
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
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
|
|
||||||
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 {
|
|||||||
__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 {
|
|||||||
|
|
||||||
/* 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)
|
|||||||
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)
|
|||||||
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
|
|||||||
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,
|
||||||
last = 0;
|
BTRFS_BLOCK_GROUP_AVAIL);
|
||||||
|
last = hint->key.objectid + hint->key.offset;
|
||||||
|
hint_last = last;
|
||||||
|
} else {
|
||||||
|
hint_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 @@ find_new:
|
|||||||
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,
|
|||||||
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
|
|||||||
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
|
|||||||
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 @@ check_pending:
|
|||||||
}
|
}
|
||||||
info->extent_tree_prealloc_nr = total_found;
|
info->extent_tree_prealloc_nr = total_found;
|
||||||
}
|
}
|
||||||
ret = radix_tree_gang_lookup(&info->block_group_radix,
|
if (update_block_group) {
|
||||||
(void **)&info->block_group_cache,
|
ret = radix_tree_gang_lookup(&info->block_group_radix,
|
||||||
ins->objectid, 1);
|
(void **)&trans->block_group,
|
||||||
if (ret) {
|
ins->objectid, 1);
|
||||||
info->block_group_cache->last_alloc = ins->objectid;
|
if (ret) {
|
||||||
|
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,
|
|||||||
* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* 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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
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,
|
|||||||
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;
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#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 {
|
|||||||
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,
|
||||||
|
Reference in New Issue
Block a user