struct btrfs_inode {
struct btrfs_root *root;
+ struct btrfs_block_group_cache *block_group;
struct btrfs_key location;
struct inode vfs_inode;
};
*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);
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);
}
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));
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));
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));
__le64 generation;
__le64 size;
__le64 nblocks;
+ __le64 block_group;
__le32 nlink;
__le32 uid;
__le32 gid;
/* 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 {
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);
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,
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,
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,
path, cache[i]);
if (err)
werr = err;
+ cache[i]->last_alloc = cache[i]->first_free;
}
}
btrfs_free_path(path);
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;
}
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;
}
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);
* 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;
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;
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,
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;
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();
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;
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);
}
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);
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;
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);
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);
}
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);
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;
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;
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) {
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;
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);
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;
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;
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)
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);
/* 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);
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) {
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);
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) {
}
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);
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;
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);
* 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);
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;
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;
#ifndef __TRANSACTION__
#define __TRANSACTION__
+#include "btrfs_inode.h"
struct btrfs_transaction {
u64 transid;
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,