Commit 7343dd61 authored by Justin Maggard's avatar Justin Maggard Committed by Filipe Manana

btrfs: qgroup: exit the rescan worker during umount

I was hitting a consistent NULL pointer dereference during shutdown that
showed the trace running through end_workqueue_bio().  I traced it back to
the endio_meta_workers workqueue being poked after it had already been
destroyed.

Eventually I found that the root cause was a qgroup rescan that was still
in progress while we were stopping all the btrfs workers.

Currently we explicitly pause balance and scrub operations in
close_ctree(), but we do nothing to stop the qgroup rescan.  We should
probably be doing the same for qgroup rescan, but that's a much larger
change.  This small change is good enough to allow me to unmount without
crashing.
Signed-off-by: default avatarJustin Maggard <jmaggard@netgear.com>
Reviewed-by: default avatarFilipe Manana <fdmanana@suse.com>
parent 9c9464cc
...@@ -3780,6 +3780,9 @@ void close_ctree(struct btrfs_root *root) ...@@ -3780,6 +3780,9 @@ void close_ctree(struct btrfs_root *root)
fs_info->closing = 1; fs_info->closing = 1;
smp_mb(); smp_mb();
/* wait for the qgroup rescan worker to stop */
btrfs_qgroup_wait_for_completion(fs_info);
/* wait for the uuid_scan task to finish */ /* wait for the uuid_scan task to finish */
down(&fs_info->uuid_tree_rescan_sem); down(&fs_info->uuid_tree_rescan_sem);
/* avoid complains from lockdep et al., set sem back to initial state */ /* avoid complains from lockdep et al., set sem back to initial state */
......
...@@ -2286,7 +2286,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) ...@@ -2286,7 +2286,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
goto out; goto out;
err = 0; err = 0;
while (!err) { while (!err && !btrfs_fs_closing(fs_info)) {
trans = btrfs_start_transaction(fs_info->fs_root, 0); trans = btrfs_start_transaction(fs_info->fs_root, 0);
if (IS_ERR(trans)) { if (IS_ERR(trans)) {
err = PTR_ERR(trans); err = PTR_ERR(trans);
...@@ -2307,6 +2307,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) ...@@ -2307,6 +2307,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
btrfs_free_path(path); btrfs_free_path(path);
mutex_lock(&fs_info->qgroup_rescan_lock); mutex_lock(&fs_info->qgroup_rescan_lock);
if (!btrfs_fs_closing(fs_info))
fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
if (err > 0 && if (err > 0 &&
...@@ -2336,7 +2337,9 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) ...@@ -2336,7 +2337,9 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
} }
btrfs_end_transaction(trans, fs_info->quota_root); btrfs_end_transaction(trans, fs_info->quota_root);
if (err >= 0) { if (btrfs_fs_closing(fs_info)) {
btrfs_info(fs_info, "qgroup scan paused");
} else if (err >= 0) {
btrfs_info(fs_info, "qgroup scan completed%s", btrfs_info(fs_info, "qgroup scan completed%s",
err > 0 ? " (inconsistency flag cleared)" : ""); err > 0 ? " (inconsistency flag cleared)" : "");
} else { } else {
......
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