Commit d68fc57b authored by Yan, Zheng's avatar Yan, Zheng Committed by Chris Mason

Btrfs: Metadata reservation for orphan inodes

reserve metadata space for handling orphan inodes
Signed-off-by: default avatarYan Zheng <zheng.yan@oracle.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 8929ecfa
...@@ -151,6 +151,7 @@ struct btrfs_inode { ...@@ -151,6 +151,7 @@ struct btrfs_inode {
* of these. * of these.
*/ */
unsigned ordered_data_close:1; unsigned ordered_data_close:1;
unsigned orphan_meta_reserved:1;
unsigned dummy_inode:1; unsigned dummy_inode:1;
/* /*
......
...@@ -1069,7 +1069,6 @@ struct btrfs_root { ...@@ -1069,7 +1069,6 @@ struct btrfs_root {
int ref_cows; int ref_cows;
int track_dirty; int track_dirty;
int in_radix; int in_radix;
int clean_orphans;
u64 defrag_trans_start; u64 defrag_trans_start;
struct btrfs_key defrag_progress; struct btrfs_key defrag_progress;
...@@ -1083,8 +1082,11 @@ struct btrfs_root { ...@@ -1083,8 +1082,11 @@ struct btrfs_root {
struct list_head root_list; struct list_head root_list;
spinlock_t list_lock; spinlock_t orphan_lock;
struct list_head orphan_list; struct list_head orphan_list;
struct btrfs_block_rsv *orphan_block_rsv;
int orphan_item_inserted;
int orphan_cleanup_state;
spinlock_t inode_lock; spinlock_t inode_lock;
/* red-black tree that keeps track of in-memory inodes */ /* red-black tree that keeps track of in-memory inodes */
...@@ -2080,6 +2082,9 @@ int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans, ...@@ -2080,6 +2082,9 @@ int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
int num_items, int *retries); int num_items, int *retries);
void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
struct inode *inode);
void btrfs_orphan_release_metadata(struct inode *inode);
int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans, int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
struct btrfs_pending_snapshot *pending); struct btrfs_pending_snapshot *pending);
int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes); int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes);
...@@ -2404,6 +2409,13 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans, ...@@ -2404,6 +2409,13 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans,
int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode);
int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
void btrfs_orphan_cleanup(struct btrfs_root *root); void btrfs_orphan_cleanup(struct btrfs_root *root);
void btrfs_orphan_pre_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_pending_snapshot *pending,
u64 *bytes_to_reserve);
void btrfs_orphan_post_snapshot(struct btrfs_trans_handle *trans,
struct btrfs_pending_snapshot *pending);
void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_cont_expand(struct inode *inode, loff_t size); int btrfs_cont_expand(struct inode *inode, loff_t size);
int btrfs_invalidate_inodes(struct btrfs_root *root); int btrfs_invalidate_inodes(struct btrfs_root *root);
void btrfs_add_delayed_iput(struct inode *inode); void btrfs_add_delayed_iput(struct inode *inode);
......
...@@ -894,7 +894,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, ...@@ -894,7 +894,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
root->ref_cows = 0; root->ref_cows = 0;
root->track_dirty = 0; root->track_dirty = 0;
root->in_radix = 0; root->in_radix = 0;
root->clean_orphans = 0; root->orphan_item_inserted = 0;
root->orphan_cleanup_state = 0;
root->fs_info = fs_info; root->fs_info = fs_info;
root->objectid = objectid; root->objectid = objectid;
...@@ -904,12 +905,13 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, ...@@ -904,12 +905,13 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
root->in_sysfs = 0; root->in_sysfs = 0;
root->inode_tree = RB_ROOT; root->inode_tree = RB_ROOT;
root->block_rsv = NULL; root->block_rsv = NULL;
root->orphan_block_rsv = NULL;
INIT_LIST_HEAD(&root->dirty_list); INIT_LIST_HEAD(&root->dirty_list);
INIT_LIST_HEAD(&root->orphan_list); INIT_LIST_HEAD(&root->orphan_list);
INIT_LIST_HEAD(&root->root_list); INIT_LIST_HEAD(&root->root_list);
spin_lock_init(&root->node_lock); spin_lock_init(&root->node_lock);
spin_lock_init(&root->list_lock); spin_lock_init(&root->orphan_lock);
spin_lock_init(&root->inode_lock); spin_lock_init(&root->inode_lock);
spin_lock_init(&root->accounting_lock); spin_lock_init(&root->accounting_lock);
mutex_init(&root->objectid_mutex); mutex_init(&root->objectid_mutex);
...@@ -1193,19 +1195,23 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, ...@@ -1193,19 +1195,23 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
if (root) if (root)
return root; return root;
ret = btrfs_find_orphan_item(fs_info->tree_root, location->objectid);
if (ret == 0)
ret = -ENOENT;
if (ret < 0)
return ERR_PTR(ret);
root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location); root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location);
if (IS_ERR(root)) if (IS_ERR(root))
return root; return root;
WARN_ON(btrfs_root_refs(&root->root_item) == 0);
set_anon_super(&root->anon_super, NULL); set_anon_super(&root->anon_super, NULL);
if (btrfs_root_refs(&root->root_item) == 0) {
ret = -ENOENT;
goto fail;
}
ret = btrfs_find_orphan_item(fs_info->tree_root, location->objectid);
if (ret < 0)
goto fail;
if (ret == 0)
root->orphan_item_inserted = 1;
ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM); ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
if (ret) if (ret)
goto fail; goto fail;
...@@ -1214,10 +1220,9 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, ...@@ -1214,10 +1220,9 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
ret = radix_tree_insert(&fs_info->fs_roots_radix, ret = radix_tree_insert(&fs_info->fs_roots_radix,
(unsigned long)root->root_key.objectid, (unsigned long)root->root_key.objectid,
root); root);
if (ret == 0) { if (ret == 0)
root->in_radix = 1; root->in_radix = 1;
root->clean_orphans = 1;
}
spin_unlock(&fs_info->fs_roots_radix_lock); spin_unlock(&fs_info->fs_roots_radix_lock);
radix_tree_preload_end(); radix_tree_preload_end();
if (ret) { if (ret) {
...@@ -1981,6 +1986,9 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1981,6 +1986,9 @@ struct btrfs_root *open_ctree(struct super_block *sb,
BUG_ON(ret); BUG_ON(ret);
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
ret = btrfs_cleanup_fs_roots(fs_info);
BUG_ON(ret);
ret = btrfs_recover_relocation(tree_root); ret = btrfs_recover_relocation(tree_root);
if (ret < 0) { if (ret < 0) {
printk(KERN_WARNING printk(KERN_WARNING
......
...@@ -3626,6 +3626,34 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, ...@@ -3626,6 +3626,34 @@ void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
trans->bytes_reserved = 0; trans->bytes_reserved = 0;
} }
int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
struct inode *inode)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_block_rsv *src_rsv = get_block_rsv(trans, root);
struct btrfs_block_rsv *dst_rsv = root->orphan_block_rsv;
/*
* one for deleting orphan item, one for updating inode and
* two for calling btrfs_truncate_inode_items.
*
* btrfs_truncate_inode_items is a delete operation, it frees
* more space than it uses in most cases. So two units of
* metadata space should be enough for calling it many times.
* If all of the metadata space is used, we can commit
* transaction and use space it freed.
*/
u64 num_bytes = calc_trans_metadata_size(root, 4);
return block_rsv_migrate_bytes(src_rsv, dst_rsv, num_bytes);
}
void btrfs_orphan_release_metadata(struct inode *inode)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
u64 num_bytes = calc_trans_metadata_size(root, 4);
btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes);
}
int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans, int btrfs_snap_reserve_metadata(struct btrfs_trans_handle *trans,
struct btrfs_pending_snapshot *pending) struct btrfs_pending_snapshot *pending)
{ {
......
This diff is collapsed.
...@@ -1297,10 +1297,12 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -1297,10 +1297,12 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
dest->root_item.drop_level = 0; dest->root_item.drop_level = 0;
btrfs_set_root_refs(&dest->root_item, 0); btrfs_set_root_refs(&dest->root_item, 0);
if (!xchg(&dest->orphan_item_inserted, 1)) {
ret = btrfs_insert_orphan_item(trans, ret = btrfs_insert_orphan_item(trans,
root->fs_info->tree_root, root->fs_info->tree_root,
dest->root_key.objectid); dest->root_key.objectid);
BUG_ON(ret); BUG_ON(ret);
}
ret = btrfs_commit_transaction(trans, root); ret = btrfs_commit_transaction(trans, root);
BUG_ON(ret); BUG_ON(ret);
......
...@@ -259,6 +259,8 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) ...@@ -259,6 +259,8 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_key key; struct btrfs_key key;
struct btrfs_key root_key;
struct btrfs_root *root;
int err = 0; int err = 0;
int ret; int ret;
...@@ -270,6 +272,9 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) ...@@ -270,6 +272,9 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
key.type = BTRFS_ORPHAN_ITEM_KEY; key.type = BTRFS_ORPHAN_ITEM_KEY;
key.offset = 0; key.offset = 0;
root_key.type = BTRFS_ROOT_ITEM_KEY;
root_key.offset = (u64)-1;
while (1) { while (1) {
ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
if (ret < 0) { if (ret < 0) {
...@@ -294,13 +299,25 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) ...@@ -294,13 +299,25 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
key.type != BTRFS_ORPHAN_ITEM_KEY) key.type != BTRFS_ORPHAN_ITEM_KEY)
break; break;
ret = btrfs_find_dead_roots(tree_root, key.offset); root_key.objectid = key.offset;
if (ret) { key.offset++;
root = btrfs_read_fs_root_no_name(tree_root->fs_info,
&root_key);
if (!IS_ERR(root))
continue;
ret = PTR_ERR(root);
if (ret != -ENOENT) {
err = ret; err = ret;
break; break;
} }
key.offset++; ret = btrfs_find_dead_roots(tree_root, root_key.objectid);
if (ret) {
err = ret;
break;
}
} }
btrfs_free_path(path); btrfs_free_path(path);
......
...@@ -694,11 +694,11 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -694,11 +694,11 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
if (btrfs_super_log_root(&root->fs_info->super_copy) != 0) if (btrfs_super_log_root(&root->fs_info->super_copy) != 0)
return -EINVAL; return -EINVAL;
/* recover relocation */ ret = btrfs_cleanup_fs_roots(root->fs_info);
ret = btrfs_recover_relocation(root);
WARN_ON(ret); WARN_ON(ret);
ret = btrfs_cleanup_fs_roots(root->fs_info); /* recover relocation */
ret = btrfs_recover_relocation(root);
WARN_ON(ret); WARN_ON(ret);
sb->s_flags &= ~MS_RDONLY; sb->s_flags &= ~MS_RDONLY;
......
...@@ -676,6 +676,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, ...@@ -676,6 +676,7 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
btrfs_free_log(trans, root); btrfs_free_log(trans, root);
btrfs_update_reloc_root(trans, root); btrfs_update_reloc_root(trans, root);
btrfs_orphan_commit_root(trans, root);
if (root->commit_root != root->node) { if (root->commit_root != root->node) {
switch_commit_root(root); switch_commit_root(root);
...@@ -835,6 +836,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -835,6 +836,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
struct extent_buffer *tmp; struct extent_buffer *tmp;
struct extent_buffer *old; struct extent_buffer *old;
int ret; int ret;
int retries = 0;
u64 to_reserve = 0;
u64 index = 0; u64 index = 0;
u64 objectid; u64 objectid;
...@@ -850,6 +853,17 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -850,6 +853,17 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
goto fail; goto fail;
} }
btrfs_orphan_pre_snapshot(trans, pending, &to_reserve);
if (to_reserve > 0) {
ret = btrfs_block_rsv_add(trans, root, &pending->block_rsv,
to_reserve, &retries);
if (ret) {
pending->error = ret;
goto fail;
}
}
key.objectid = objectid; key.objectid = objectid;
key.offset = (u64)-1; key.offset = (u64)-1;
key.type = BTRFS_ROOT_ITEM_KEY; key.type = BTRFS_ROOT_ITEM_KEY;
...@@ -909,6 +923,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, ...@@ -909,6 +923,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
key.offset = (u64)-1; key.offset = (u64)-1;
pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key); pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
BUG_ON(IS_ERR(pending->snap)); BUG_ON(IS_ERR(pending->snap));
btrfs_orphan_post_snapshot(trans, pending);
fail: fail:
kfree(new_root_item); kfree(new_root_item);
btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1); btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
......
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