aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>2016-06-12 23:39:58 -0400
committerDavid Sterba <dsterba@suse.com>2016-06-17 12:32:40 -0400
commit90c711ab380d633bf85249bd5d819edb601feda7 (patch)
tree556934ae4488ebae6490610894bbfe92bd405478 /fs
parent3b6571c180da85e43550c608e954ab7b2a31d954 (diff)
btrfs: avoid blocking open_ctree from cleaner_kthread
This fixes a problem introduced in commit 2f3165ecf103599f82bf0ea254039db335fb5005 "btrfs: don't force mounts to wait for cleaner_kthread to delete one or more subvolumes". open_ctree eventually calls btrfs_replay_log which in turn calls btrfs_commit_super which tries to lock the cleaner_mutex, causing a recursive mutex deadlock during mount. Instead of playing whack-a-mole trying to keep up with all the functions that may want to lock cleaner_mutex, put all the cleaner_mutex lockers back where they were, and attack the problem more directly: keep cleaner_kthread asleep until the filesystem is mounted. When filesystems are mounted read-only and later remounted read-write, open_ctree did not set fs_info->open and neither does anything else. Set this flag in btrfs_remount so that neither btrfs_delete_unused_bgs nor cleaner_kthread get confused by the common case of "/" filesystem read-only mount followed by read-write remount. Signed-off-by: Zygo Blaxell <ce3g8jdj@umail.furryterror.org> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/disk-io.c25
-rw-r--r--fs/btrfs/super.c2
2 files changed, 12 insertions, 15 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 7b5d5e8efde6..789f5f233940 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1806,6 +1806,13 @@ static int cleaner_kthread(void *arg)
1806 if (btrfs_need_cleaner_sleep(root)) 1806 if (btrfs_need_cleaner_sleep(root))
1807 goto sleep; 1807 goto sleep;
1808 1808
1809 /*
1810 * Do not do anything if we might cause open_ctree() to block
1811 * before we have finished mounting the filesystem.
1812 */
1813 if (!root->fs_info->open)
1814 goto sleep;
1815
1809 if (!mutex_trylock(&root->fs_info->cleaner_mutex)) 1816 if (!mutex_trylock(&root->fs_info->cleaner_mutex))
1810 goto sleep; 1817 goto sleep;
1811 1818
@@ -2520,7 +2527,6 @@ int open_ctree(struct super_block *sb,
2520 int num_backups_tried = 0; 2527 int num_backups_tried = 0;
2521 int backup_index = 0; 2528 int backup_index = 0;
2522 int max_active; 2529 int max_active;
2523 bool cleaner_mutex_locked = false;
2524 2530
2525 tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL); 2531 tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
2526 chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL); 2532 chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL);
@@ -2999,13 +3005,6 @@ retry_root_backup:
2999 goto fail_sysfs; 3005 goto fail_sysfs;
3000 } 3006 }
3001 3007
3002 /*
3003 * Hold the cleaner_mutex thread here so that we don't block
3004 * for a long time on btrfs_recover_relocation. cleaner_kthread
3005 * will wait for us to finish mounting the filesystem.
3006 */
3007 mutex_lock(&fs_info->cleaner_mutex);
3008 cleaner_mutex_locked = true;
3009 fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, 3008 fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root,
3010 "btrfs-cleaner"); 3009 "btrfs-cleaner");
3011 if (IS_ERR(fs_info->cleaner_kthread)) 3010 if (IS_ERR(fs_info->cleaner_kthread))
@@ -3065,8 +3064,10 @@ retry_root_backup:
3065 ret = btrfs_cleanup_fs_roots(fs_info); 3064 ret = btrfs_cleanup_fs_roots(fs_info);
3066 if (ret) 3065 if (ret)
3067 goto fail_qgroup; 3066 goto fail_qgroup;
3068 /* We locked cleaner_mutex before creating cleaner_kthread. */ 3067
3068 mutex_lock(&fs_info->cleaner_mutex);
3069 ret = btrfs_recover_relocation(tree_root); 3069 ret = btrfs_recover_relocation(tree_root);
3070 mutex_unlock(&fs_info->cleaner_mutex);
3070 if (ret < 0) { 3071 if (ret < 0) {
3071 btrfs_warn(fs_info, "failed to recover relocation: %d", 3072 btrfs_warn(fs_info, "failed to recover relocation: %d",
3072 ret); 3073 ret);
@@ -3074,8 +3075,6 @@ retry_root_backup:
3074 goto fail_qgroup; 3075 goto fail_qgroup;
3075 } 3076 }
3076 } 3077 }
3077 mutex_unlock(&fs_info->cleaner_mutex);
3078 cleaner_mutex_locked = false;
3079 3078
3080 location.objectid = BTRFS_FS_TREE_OBJECTID; 3079 location.objectid = BTRFS_FS_TREE_OBJECTID;
3081 location.type = BTRFS_ROOT_ITEM_KEY; 3080 location.type = BTRFS_ROOT_ITEM_KEY;
@@ -3189,10 +3188,6 @@ fail_cleaner:
3189 filemap_write_and_wait(fs_info->btree_inode->i_mapping); 3188 filemap_write_and_wait(fs_info->btree_inode->i_mapping);
3190 3189
3191fail_sysfs: 3190fail_sysfs:
3192 if (cleaner_mutex_locked) {
3193 mutex_unlock(&fs_info->cleaner_mutex);
3194 cleaner_mutex_locked = false;
3195 }
3196 btrfs_sysfs_remove_mounted(fs_info); 3191 btrfs_sysfs_remove_mounted(fs_info);
3197 3192
3198fail_fsdev_sysfs: 3193fail_fsdev_sysfs:
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index bf70d33b5791..60e7179ed4b7 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1807,6 +1807,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
1807 } 1807 }
1808 } 1808 }
1809 sb->s_flags &= ~MS_RDONLY; 1809 sb->s_flags &= ~MS_RDONLY;
1810
1811 fs_info->open = 1;
1810 } 1812 }
1811out: 1813out:
1812 wake_up_process(fs_info->transaction_kthread); 1814 wake_up_process(fs_info->transaction_kthread);