mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-15 15:04:27 +08:00
btrfs: split out ro->rw and rw->ro helpers into their own functions
When we remount ro->rw or rw->ro we have some cleanup tasks that have to be managed. Split these out into their own function to make btrfs_remount smaller. Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Reviewed-by: Anand Jain <anand.jain@oracle.com> Acked-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Josef Bacik <josef@toxicpanda.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
272efa308f
commit
9ef40c2e9b
229
fs/btrfs/super.c
229
fs/btrfs/super.c
@ -1676,6 +1676,115 @@ static inline void btrfs_remount_cleanup(struct btrfs_fs_info *fs_info,
|
||||
btrfs_set_free_space_cache_v1_active(fs_info, cache_opt);
|
||||
}
|
||||
|
||||
static int btrfs_remount_rw(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (BTRFS_FS_ERROR(fs_info)) {
|
||||
btrfs_err(fs_info,
|
||||
"remounting read-write after error is not allowed");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (fs_info->fs_devices->rw_devices == 0)
|
||||
return -EACCES;
|
||||
|
||||
if (!btrfs_check_rw_degradable(fs_info, NULL)) {
|
||||
btrfs_warn(fs_info,
|
||||
"too many missing devices, writable remount is not allowed");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (btrfs_super_log_root(fs_info->super_copy) != 0) {
|
||||
btrfs_warn(fs_info,
|
||||
"mount required to replay tree-log, cannot remount read-write");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: when remounting with a change that does writes, don't put it
|
||||
* anywhere above this point, as we are not sure to be safe to write
|
||||
* until we pass the above checks.
|
||||
*/
|
||||
ret = btrfs_start_pre_rw_mount(fs_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
btrfs_clear_sb_rdonly(fs_info->sb);
|
||||
|
||||
set_bit(BTRFS_FS_OPEN, &fs_info->flags);
|
||||
|
||||
/*
|
||||
* If we've gone from readonly -> read-write, we need to get our
|
||||
* sync/async discard lists in the right state.
|
||||
*/
|
||||
btrfs_discard_resume(fs_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btrfs_remount_ro(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
/*
|
||||
* This also happens on 'umount -rf' or on shutdown, when the
|
||||
* filesystem is busy.
|
||||
*/
|
||||
cancel_work_sync(&fs_info->async_reclaim_work);
|
||||
cancel_work_sync(&fs_info->async_data_reclaim_work);
|
||||
|
||||
btrfs_discard_cleanup(fs_info);
|
||||
|
||||
/* Wait for the uuid_scan task to finish */
|
||||
down(&fs_info->uuid_tree_rescan_sem);
|
||||
/* Avoid complains from lockdep et al. */
|
||||
up(&fs_info->uuid_tree_rescan_sem);
|
||||
|
||||
btrfs_set_sb_rdonly(fs_info->sb);
|
||||
|
||||
/*
|
||||
* Setting SB_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.
|
||||
*/
|
||||
btrfs_delete_unused_bgs(fs_info);
|
||||
|
||||
/*
|
||||
* The cleaner task could be already running before we set the flag
|
||||
* BTRFS_FS_STATE_RO (and SB_RDONLY in the superblock). We must make
|
||||
* sure that after we finish the remount, i.e. after we call
|
||||
* btrfs_commit_super(), the cleaner can no longer start a transaction
|
||||
* - either because it was dropping a dead root, running delayed iputs
|
||||
* or deleting an unused block group (the cleaner picked a block
|
||||
* group from the list of unused block groups before we were able to
|
||||
* in the previous call to btrfs_delete_unused_bgs()).
|
||||
*/
|
||||
wait_on_bit(&fs_info->flags, BTRFS_FS_CLEANER_RUNNING, TASK_UNINTERRUPTIBLE);
|
||||
|
||||
/*
|
||||
* We've set the superblock to RO mode, so we might have made the
|
||||
* cleaner task sleep without running all pending delayed iputs. Go
|
||||
* through all the delayed iputs here, so that if an unmount happens
|
||||
* without remounting RW we don't end up at finishing close_ctree()
|
||||
* with a non-empty list of delayed iputs.
|
||||
*/
|
||||
btrfs_run_delayed_iputs(fs_info);
|
||||
|
||||
btrfs_dev_replace_suspend_for_unmount(fs_info);
|
||||
btrfs_scrub_cancel(fs_info);
|
||||
btrfs_pause_balance(fs_info);
|
||||
|
||||
/*
|
||||
* Pause the qgroup rescan worker if it is running. We don't want it to
|
||||
* be still running after we are in RO mode, as after that, by the time
|
||||
* we unmount, it might have left a transaction open, so we would leak
|
||||
* the transaction and/or crash.
|
||||
*/
|
||||
btrfs_qgroup_wait_for_completion(fs_info, false);
|
||||
|
||||
return btrfs_commit_super(fs_info);
|
||||
}
|
||||
|
||||
static int btrfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(sb);
|
||||
@ -1729,120 +1838,14 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
}
|
||||
}
|
||||
|
||||
if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb))
|
||||
goto out;
|
||||
ret = 0;
|
||||
if (!sb_rdonly(sb) && (*flags & SB_RDONLY))
|
||||
ret = btrfs_remount_ro(fs_info);
|
||||
else if (sb_rdonly(sb) && !(*flags & SB_RDONLY))
|
||||
ret = btrfs_remount_rw(fs_info);
|
||||
if (ret)
|
||||
goto restore;
|
||||
|
||||
if (*flags & SB_RDONLY) {
|
||||
/*
|
||||
* this also happens on 'umount -rf' or on shutdown, when
|
||||
* the filesystem is busy.
|
||||
*/
|
||||
cancel_work_sync(&fs_info->async_reclaim_work);
|
||||
cancel_work_sync(&fs_info->async_data_reclaim_work);
|
||||
|
||||
btrfs_discard_cleanup(fs_info);
|
||||
|
||||
/* wait for the uuid_scan task to finish */
|
||||
down(&fs_info->uuid_tree_rescan_sem);
|
||||
/* avoid complains from lockdep et al. */
|
||||
up(&fs_info->uuid_tree_rescan_sem);
|
||||
|
||||
btrfs_set_sb_rdonly(sb);
|
||||
|
||||
/*
|
||||
* Setting SB_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.
|
||||
*/
|
||||
btrfs_delete_unused_bgs(fs_info);
|
||||
|
||||
/*
|
||||
* The cleaner task could be already running before we set the
|
||||
* flag BTRFS_FS_STATE_RO (and SB_RDONLY in the superblock).
|
||||
* We must make sure that after we finish the remount, i.e. after
|
||||
* we call btrfs_commit_super(), the cleaner can no longer start
|
||||
* a transaction - either because it was dropping a dead root,
|
||||
* running delayed iputs or deleting an unused block group (the
|
||||
* cleaner picked a block group from the list of unused block
|
||||
* groups before we were able to in the previous call to
|
||||
* btrfs_delete_unused_bgs()).
|
||||
*/
|
||||
wait_on_bit(&fs_info->flags, BTRFS_FS_CLEANER_RUNNING,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
|
||||
/*
|
||||
* We've set the superblock to RO mode, so we might have made
|
||||
* the cleaner task sleep without running all pending delayed
|
||||
* iputs. Go through all the delayed iputs here, so that if an
|
||||
* unmount happens without remounting RW we don't end up at
|
||||
* finishing close_ctree() with a non-empty list of delayed
|
||||
* iputs.
|
||||
*/
|
||||
btrfs_run_delayed_iputs(fs_info);
|
||||
|
||||
btrfs_dev_replace_suspend_for_unmount(fs_info);
|
||||
btrfs_scrub_cancel(fs_info);
|
||||
btrfs_pause_balance(fs_info);
|
||||
|
||||
/*
|
||||
* Pause the qgroup rescan worker if it is running. We don't want
|
||||
* it to be still running after we are in RO mode, as after that,
|
||||
* by the time we unmount, it might have left a transaction open,
|
||||
* so we would leak the transaction and/or crash.
|
||||
*/
|
||||
btrfs_qgroup_wait_for_completion(fs_info, false);
|
||||
|
||||
ret = btrfs_commit_super(fs_info);
|
||||
if (ret)
|
||||
goto restore;
|
||||
} else {
|
||||
if (BTRFS_FS_ERROR(fs_info)) {
|
||||
btrfs_err(fs_info,
|
||||
"Remounting read-write after error is not allowed");
|
||||
ret = -EINVAL;
|
||||
goto restore;
|
||||
}
|
||||
if (fs_info->fs_devices->rw_devices == 0) {
|
||||
ret = -EACCES;
|
||||
goto restore;
|
||||
}
|
||||
|
||||
if (!btrfs_check_rw_degradable(fs_info, NULL)) {
|
||||
btrfs_warn(fs_info,
|
||||
"too many missing devices, writable remount is not allowed");
|
||||
ret = -EACCES;
|
||||
goto restore;
|
||||
}
|
||||
|
||||
if (btrfs_super_log_root(fs_info->super_copy) != 0) {
|
||||
btrfs_warn(fs_info,
|
||||
"mount required to replay tree-log, cannot remount read-write");
|
||||
ret = -EINVAL;
|
||||
goto restore;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: when remounting with a change that does writes, don't
|
||||
* put it anywhere above this point, as we are not sure to be
|
||||
* safe to write until we pass the above checks.
|
||||
*/
|
||||
ret = btrfs_start_pre_rw_mount(fs_info);
|
||||
if (ret)
|
||||
goto restore;
|
||||
|
||||
btrfs_clear_sb_rdonly(sb);
|
||||
|
||||
set_bit(BTRFS_FS_OPEN, &fs_info->flags);
|
||||
|
||||
/*
|
||||
* If we've gone from readonly -> read/write, we need to get
|
||||
* our sync/async discard lists in the right state.
|
||||
*/
|
||||
btrfs_discard_resume(fs_info);
|
||||
}
|
||||
out:
|
||||
/*
|
||||
* We need to set SB_I_VERSION here otherwise it'll get cleared by VFS,
|
||||
* since the absence of the flag means it can be toggled off by remount.
|
||||
|
Loading…
Reference in New Issue
Block a user