diff options
author | Omar Sandoval <osandov@fb.com> | 2019-09-16 11:30:55 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-12-31 16:36:16 +0100 |
commit | ff90b89eb2465b836605f8949b584f697590bf92 (patch) | |
tree | bfd049b43d35bd84febbde050b5b2d22ffbe2410 /fs | |
parent | f4f8b2ec1ebf68d490dd896e5590b898908dd218 (diff) | |
download | linux-stable-ff90b89eb2465b836605f8949b584f697590bf92.tar.gz linux-stable-ff90b89eb2465b836605f8949b584f697590bf92.tar.bz2 linux-stable-ff90b89eb2465b836605f8949b584f697590bf92.zip |
btrfs: don't prematurely free work in reada_start_machine_worker()
[ Upstream commit e732fe95e4cad35fc1df278c23a32903341b08b3 ]
Currently, reada_start_machine_worker() frees the reada_machine_work and
then calls __reada_start_machine() to do readahead. This is another
potential instance of the bug in "btrfs: don't prematurely free work in
run_ordered_work()".
There _might_ already be a deadlock here: reada_start_machine_worker()
can depend on itself through stacked filesystems (__read_start_machine()
-> reada_start_machine_dev() -> reada_tree_block_flagged() ->
read_extent_buffer_pages() -> submit_one_bio() ->
btree_submit_bio_hook() -> btrfs_map_bio() -> submit_stripe_bio() ->
submit_bio() onto a loop device can trigger readahead on the lower
filesystem).
Either way, let's fix it by freeing the work at the end.
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Omar Sandoval <osandov@fb.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/reada.c | 10 |
1 files changed, 4 insertions, 6 deletions
diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c index 859274e38417..4c81ffe12385 100644 --- a/fs/btrfs/reada.c +++ b/fs/btrfs/reada.c @@ -720,21 +720,19 @@ static int reada_start_machine_dev(struct btrfs_device *dev) static void reada_start_machine_worker(struct btrfs_work *work) { struct reada_machine_work *rmw; - struct btrfs_fs_info *fs_info; int old_ioprio; rmw = container_of(work, struct reada_machine_work, work); - fs_info = rmw->fs_info; - - kfree(rmw); old_ioprio = IOPRIO_PRIO_VALUE(task_nice_ioclass(current), task_nice_ioprio(current)); set_task_ioprio(current, BTRFS_IOPRIO_READA); - __reada_start_machine(fs_info); + __reada_start_machine(rmw->fs_info); set_task_ioprio(current, old_ioprio); - atomic_dec(&fs_info->reada_works_cnt); + atomic_dec(&rmw->fs_info->reada_works_cnt); + + kfree(rmw); } static void __reada_start_machine(struct btrfs_fs_info *fs_info) |