Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c3c7c0cc authored by Omar Sandoval's avatar Omar Sandoval Committed by Greg Kroah-Hartman
Browse files

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: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: default avatarOmar Sandoval <osandov@fb.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 5baa2f38
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -734,21 +734,19 @@ static int reada_start_machine_dev(struct btrfs_fs_info *fs_info,
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)