瀏覽代碼

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: Justin Maggard <jmaggard@netgear.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Justin Maggard 9 年之前
父節點
當前提交
7343dd61fd
共有 2 個文件被更改,包括 9 次插入3 次删除
  1. 3 0
      fs/btrfs/disk-io.c
  2. 6 3
      fs/btrfs/qgroup.c

+ 3 - 0
fs/btrfs/disk-io.c

@@ -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 */

+ 6 - 3
fs/btrfs/qgroup.c

@@ -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,7 +2307,8 @@ out:
 	btrfs_free_path(path);
 	btrfs_free_path(path);
 
 
 	mutex_lock(&fs_info->qgroup_rescan_lock);
 	mutex_lock(&fs_info->qgroup_rescan_lock);
-	fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
+	if (!btrfs_fs_closing(fs_info))
+		fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
 
 
 	if (err > 0 &&
 	if (err > 0 &&
 	    fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) {
 	    fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) {
@@ -2336,7 +2337,9 @@ out:
 	}
 	}
 	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 {