diff options
author | Zygo Blaxell <ce3g8jdj@umail.furryterror.org> | 2016-06-12 23:39:58 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2016-06-17 12:32:40 -0400 |
commit | 90c711ab380d633bf85249bd5d819edb601feda7 (patch) | |
tree | 556934ae4488ebae6490610894bbfe92bd405478 /fs | |
parent | 3b6571c180da85e43550c608e954ab7b2a31d954 (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.c | 25 | ||||
-rw-r--r-- | fs/btrfs/super.c | 2 |
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 | ||
3191 | fail_sysfs: | 3190 | fail_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 | ||
3198 | fail_fsdev_sysfs: | 3193 | fail_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 | } |
1811 | out: | 1813 | out: |
1812 | wake_up_process(fs_info->transaction_kthread); | 1814 | wake_up_process(fs_info->transaction_kthread); |