btrfs: explictly delete unused block groups in close_ctree and ro-remount
authorJeff Mahoney <jeffm@suse.com>
Mon, 15 Jun 2015 13:41:18 +0000 (09:41 -0400)
committerChris Mason <clm@fb.com>
Wed, 29 Jul 2015 15:15:27 +0000 (08:15 -0700)
The cleaner thread may already be sleeping by the time we enter
close_ctree.  If that's the case, we'll skip removing any unused
block groups queued for removal, even during a normal umount.
They'll be cleaned up automatically at next mount, but users
expect a umount to be a clean synchronization point, especially
when used on thin-provisioned storage with -odiscard.  We also
explicitly remove unused block groups in the ro-remount path
for the same reason.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Tested-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/disk-io.c
fs/btrfs/super.c

index 84cbbb2d562ea1c8f281cc0e103b547f5530a73a..053109ba26b7e22a8ce995d2485977dc58dbd9ba 100644 (file)
@@ -3767,6 +3767,15 @@ void close_ctree(struct btrfs_root *root)
        cancel_work_sync(&fs_info->async_reclaim_work);
 
        if (!(fs_info->sb->s_flags & MS_RDONLY)) {
+               /*
+                * If the cleaner thread is stopped and there are
+                * block groups queued for removal, the deletion will be
+                * skipped when we quit the cleaner thread.
+                */
+               mutex_lock(&root->fs_info->cleaner_mutex);
+               btrfs_delete_unused_bgs(root->fs_info);
+               mutex_unlock(&root->fs_info->cleaner_mutex);
+
                ret = btrfs_commit_super(root);
                if (ret)
                        btrfs_err(fs_info, "commit super ret %d", ret);
index cd7ef34d2dce99987fe87f3040ba20038bb3f041..a1077e0ffaa88ee85a541feb752fe7c7b844d062 100644 (file)
@@ -1650,6 +1650,17 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 
                sb->s_flags |= MS_RDONLY;
 
+               /*
+                * Setting MS_RDONLY will put the cleaner thread to
+                * sleep at the next loop if it's already active.
+                * If it's already asleep, we'll leave unused block
+                * groups on disk until we're mounted read-write again
+                * unless we clean them up here.
+                */
+               mutex_lock(&root->fs_info->cleaner_mutex);
+               btrfs_delete_unused_bgs(fs_info);
+               mutex_unlock(&root->fs_info->cleaner_mutex);
+
                btrfs_dev_replace_suspend_for_unmount(fs_info);
                btrfs_scrub_cancel(fs_info);
                btrfs_pause_balance(fs_info);