[4/7] btrfs: don't prematurely free work in reada_start_machine_worker()
diff mbox series

Message ID 15b3aebf569f2a2831bc852789935fae37798f8d.1568658527.git.osandov@fb.com
State New
Headers show
Series
  • btrfs: workqueue fixes+cleanups
Related show

Commit Message

Omar Sandoval Sept. 16, 2019, 6:30 p.m. UTC
From: Omar Sandoval <osandov@fb.com>

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.

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/reada.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

Comments

Johannes Thumshirn Sept. 17, 2019, 12:09 p.m. UTC | #1
On Mon, Sep 16, 2019 at 11:30:55AM -0700, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
> 
> 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.


Also remove the local fs_info variable as it got obsolete.

Anyways,
Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de>

Patch
diff mbox series

diff --git a/fs/btrfs/reada.c b/fs/btrfs/reada.c
index ee6f60547a8d..dd4f9c2b7107 100644
--- a/fs/btrfs/reada.c
+++ b/fs/btrfs/reada.c
@@ -752,21 +752,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)