aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>2016-05-05 00:23:49 -0400
committerDavid Sterba <dsterba@suse.com>2016-05-06 09:22:49 -0400
commit2f3165ecf103599f82bf0ea254039db335fb5005 (patch)
treef3e2bb153d2503a94148f12cd8c6a8173a6eaf50 /fs/btrfs/disk-io.c
parent58d7bbf81f54667e36940d5f4b5609606efa597b (diff)
btrfs: don't force mounts to wait for cleaner_kthread to delete one or more subvolumes
During a mount, we start the cleaner kthread first because the transaction kthread wants to wake up the cleaner kthread. We start the transaction kthread next because everything in btrfs wants transactions. We do reloc recovery in the thread that was doing the original mount call once the transaction kthread is running. This means that the cleaner kthread could already be running when reloc recovery happens (e.g. if a snapshot delete was started before a crash). Relocation does not play well with the cleaner kthread, so a mutex was added in commit 5f3164813b90f7dbcb5c3ab9006906222ce471b7 "Btrfs: fix race between balance recovery and root deletion" to prevent both from being active at the same time. If the cleaner kthread is already holding the mutex by the time we get to btrfs_recover_relocation, the mount will be blocked until at least one deleted subvolume is cleaned (possibly more if the mount process doesn't get the lock right away). During this time (which could be an arbitrarily long time on a large/slow filesystem), the mount process is stuck and the filesystem is unnecessarily inaccessible. Fix this by locking cleaner_mutex before we start cleaner_kthread, and unlocking the mutex after mount no longer requires it. This ensures that the mounting process will not be blocked by the cleaner kthread. The cleaner kthread is already prepared for mutex contention and will just go to sleep until the mutex is available. Signed-off-by: Zygo Blaxell <ce3g8jdj@umail.furryterror.org> Reviewed-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 4e47849d7427..070c1dad42bd 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2517,6 +2517,7 @@ int open_ctree(struct super_block *sb,
2517 int num_backups_tried = 0; 2517 int num_backups_tried = 0;
2518 int backup_index = 0; 2518 int backup_index = 0;
2519 int max_active; 2519 int max_active;
2520 bool cleaner_mutex_locked = false;
2520 2521
2521 tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL); 2522 tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
2522 chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL); 2523 chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
@@ -2997,6 +2998,13 @@ retry_root_backup:
2997 goto fail_sysfs; 2998 goto fail_sysfs;
2998 } 2999 }
2999 3000
3001 /*
3002 * Hold the cleaner_mutex thread here so that we don't block
3003 * for a long time on btrfs_recover_relocation. cleaner_kthread
3004 * will wait for us to finish mounting the filesystem.
3005 */
3006 mutex_lock(&fs_info->cleaner_mutex);
3007 cleaner_mutex_locked = true;
3000 fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, 3008 fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root,
3001 "btrfs-cleaner"); 3009 "btrfs-cleaner");
3002 if (IS_ERR(fs_info->cleaner_kthread)) 3010 if (IS_ERR(fs_info->cleaner_kthread))
@@ -3056,10 +3064,8 @@ retry_root_backup:
3056 ret = btrfs_cleanup_fs_roots(fs_info); 3064 ret = btrfs_cleanup_fs_roots(fs_info);
3057 if (ret) 3065 if (ret)
3058 goto fail_qgroup; 3066 goto fail_qgroup;
3059 3067 /* We locked cleaner_mutex before creating cleaner_kthread. */
3060 mutex_lock(&fs_info->cleaner_mutex);
3061 ret = btrfs_recover_relocation(tree_root); 3068 ret = btrfs_recover_relocation(tree_root);
3062 mutex_unlock(&fs_info->cleaner_mutex);
3063 if (ret < 0) { 3069 if (ret < 0) {
3064 printk(KERN_WARNING 3070 printk(KERN_WARNING
3065 "BTRFS: failed to recover relocation\n"); 3071 "BTRFS: failed to recover relocation\n");
@@ -3067,6 +3073,8 @@ retry_root_backup:
3067 goto fail_qgroup; 3073 goto fail_qgroup;
3068 } 3074 }
3069 } 3075 }
3076 mutex_unlock(&fs_info->cleaner_mutex);
3077 cleaner_mutex_locked = false;
3070 3078
3071 location.objectid = BTRFS_FS_TREE_OBJECTID; 3079 location.objectid = BTRFS_FS_TREE_OBJECTID;
3072 location.type = BTRFS_ROOT_ITEM_KEY; 3080 location.type = BTRFS_ROOT_ITEM_KEY;
@@ -3180,6 +3188,10 @@ fail_cleaner:
3180 filemap_write_and_wait(fs_info->btree_inode->i_mapping); 3188 filemap_write_and_wait(fs_info->btree_inode->i_mapping);
3181 3189
3182fail_sysfs: 3190fail_sysfs:
3191 if (cleaner_mutex_locked) {
3192 mutex_unlock(&fs_info->cleaner_mutex);
3193 cleaner_mutex_locked = false;
3194 }
3183 btrfs_sysfs_remove_mounted(fs_info); 3195 btrfs_sysfs_remove_mounted(fs_info);
3184 3196
3185fail_fsdev_sysfs: 3197fail_fsdev_sysfs: