Commit ba38eb4d authored by Miao Xie's avatar Miao Xie Committed by Chris Mason

Btrfs: fix no reserved space for writing out inode cache

I-node cache forgets to reserve the space when writing out it. And when
we do some stress test, such as synctest, it will trigger WARN_ON() in
use_block_rsv().

WARNING: at fs/btrfs/extent-tree.c:5718 btrfs_alloc_free_block+0xbf/0x281 [btrfs]()
...
Call Trace:
 [<ffffffff8104df86>] warn_slowpath_common+0x80/0x98
 [<ffffffff8104dfb3>] warn_slowpath_null+0x15/0x17
 [<ffffffffa0369c60>] btrfs_alloc_free_block+0xbf/0x281 [btrfs]
 [<ffffffff810cbcb8>] ? __set_page_dirty_nobuffers+0xfe/0x108
 [<ffffffffa035c040>] __btrfs_cow_block+0x118/0x3b5 [btrfs]
 [<ffffffffa035c7ba>] btrfs_cow_block+0x103/0x14e [btrfs]
 [<ffffffffa035e4c4>] btrfs_search_slot+0x249/0x6a4 [btrfs]
 [<ffffffffa036d086>] btrfs_lookup_inode+0x2a/0x8a [btrfs]
 [<ffffffffa03788b7>] btrfs_update_inode+0xaa/0x141 [btrfs]
 [<ffffffffa036d7ec>] btrfs_save_ino_cache+0xea/0x202 [btrfs]
 [<ffffffffa03a761e>] ? btrfs_update_reloc_root+0x17e/0x197 [btrfs]
 [<ffffffffa0373867>] commit_fs_roots+0xaa/0x158 [btrfs]
 [<ffffffffa03746a6>] btrfs_commit_transaction+0x405/0x731 [btrfs]
 [<ffffffff810690df>] ? wake_up_bit+0x25/0x25
 [<ffffffffa039d652>] ? btrfs_log_dentry_safe+0x43/0x51 [btrfs]
 [<ffffffffa0381c5f>] btrfs_sync_file+0x16a/0x198 [btrfs]
 [<ffffffff81122806>] ? mntput+0x21/0x23
 [<ffffffff8112d150>] vfs_fsync_range+0x18/0x21
 [<ffffffff8112d170>] vfs_fsync+0x17/0x19
 [<ffffffff8112d316>] do_fsync+0x29/0x3e
 [<ffffffff8112d348>] sys_fsync+0xb/0xf
 [<ffffffff81468352>] system_call_fastpath+0x16/0x1b

Sometimes it causes BUG_ON() in the reservation code of the delayed inode
is triggered.

So we must reserve enough space for inode cache.

Note: If we can not reserve the enough space for inode cache, we will
give up writing out it.
Signed-off-by: default avatarMiao Xie <miaox@cn.fujitsu.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 924cd8fb
...@@ -398,6 +398,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root, ...@@ -398,6 +398,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
struct btrfs_path *path; struct btrfs_path *path;
struct inode *inode; struct inode *inode;
struct btrfs_block_rsv *rsv;
u64 num_bytes;
u64 alloc_hint = 0; u64 alloc_hint = 0;
int ret; int ret;
int prealloc; int prealloc;
...@@ -421,11 +423,26 @@ int btrfs_save_ino_cache(struct btrfs_root *root, ...@@ -421,11 +423,26 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
rsv = trans->block_rsv;
trans->block_rsv = &root->fs_info->trans_block_rsv;
num_bytes = trans->bytes_reserved;
/*
* 1 item for inode item insertion if need
* 3 items for inode item update (in the worst case)
* 1 item for free space object
* 3 items for pre-allocation
*/
trans->bytes_reserved = btrfs_calc_trans_metadata_size(root, 8);
ret = btrfs_block_rsv_add_noflush(root, trans->block_rsv,
trans->bytes_reserved);
if (ret)
goto out;
again: again:
inode = lookup_free_ino_inode(root, path); inode = lookup_free_ino_inode(root, path);
if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) { if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
ret = PTR_ERR(inode); ret = PTR_ERR(inode);
goto out; goto out_release;
} }
if (IS_ERR(inode)) { if (IS_ERR(inode)) {
...@@ -434,7 +451,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root, ...@@ -434,7 +451,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
ret = create_free_ino_inode(root, trans, path); ret = create_free_ino_inode(root, trans, path);
if (ret) if (ret)
goto out; goto out_release;
goto again; goto again;
} }
...@@ -477,11 +494,14 @@ int btrfs_save_ino_cache(struct btrfs_root *root, ...@@ -477,11 +494,14 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
} }
btrfs_free_reserved_data_space(inode, prealloc); btrfs_free_reserved_data_space(inode, prealloc);
ret = btrfs_write_out_ino_cache(root, trans, path);
out_put: out_put:
iput(inode); iput(inode);
out_release:
btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
out: out:
if (ret == 0) trans->block_rsv = rsv;
ret = btrfs_write_out_ino_cache(root, trans, path); trans->bytes_reserved = num_bytes;
btrfs_free_path(path); btrfs_free_path(path);
return ret; return ret;
......
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