Btrfs: fix ->iterate_shared() by upgrading i_rwsem for delayed nodes
Commit fe742fd4f9
("Revert "btrfs: switch to ->iterate_shared()"")
backed out the conversion to ->iterate_shared() for Btrfs because the
delayed inode handling in btrfs_real_readdir() is racy. However, we can
still do readdir in parallel if there are no delayed nodes.
This is a temporary fix which upgrades the shared inode lock to an
exclusive lock only when we have delayed items until we come up with a
more complete solution. While we're here, rename the
btrfs_{get,put}_delayed_items functions to make it very clear that
they're just for readdir.
Tested with xfstests and by doing a parallel kernel build:
while make tinyconfig && make -j4 && git clean dqfx; do
:
done
along with a bunch of parallel finds in another shell:
while true; do
for ((i=0; i<4; i++)); do
find . >/dev/null &
done
wait
done
Signed-off-by: Omar Sandoval <osandov@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:

committed by
Chris Mason

parent
33688abb28
commit
02dbfc99b4
@@ -5757,6 +5757,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
|
||||
int name_len;
|
||||
int is_curr = 0; /* ctx->pos points to the current index? */
|
||||
bool emitted;
|
||||
bool put = false;
|
||||
|
||||
/* FIXME, use a real flag for deciding about the key type */
|
||||
if (root->fs_info->tree_root == root)
|
||||
@@ -5774,7 +5775,8 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
|
||||
if (key_type == BTRFS_DIR_INDEX_KEY) {
|
||||
INIT_LIST_HEAD(&ins_list);
|
||||
INIT_LIST_HEAD(&del_list);
|
||||
btrfs_get_delayed_items(inode, &ins_list, &del_list);
|
||||
put = btrfs_readdir_get_delayed_items(inode, &ins_list,
|
||||
&del_list);
|
||||
}
|
||||
|
||||
key.type = key_type;
|
||||
@@ -5921,8 +5923,8 @@ next:
|
||||
nopos:
|
||||
ret = 0;
|
||||
err:
|
||||
if (key_type == BTRFS_DIR_INDEX_KEY)
|
||||
btrfs_put_delayed_items(&ins_list, &del_list);
|
||||
if (put)
|
||||
btrfs_readdir_put_delayed_items(inode, &ins_list, &del_list);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
@@ -10534,7 +10536,7 @@ static const struct inode_operations btrfs_dir_ro_inode_operations = {
|
||||
static const struct file_operations btrfs_dir_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read = generic_read_dir,
|
||||
.iterate = btrfs_real_readdir,
|
||||
.iterate_shared = btrfs_real_readdir,
|
||||
.unlocked_ioctl = btrfs_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = btrfs_compat_ioctl,
|
||||
|
Reference in New Issue
Block a user