Commit 6b1ac78d authored by Qu Wenruo's avatar Qu Wenruo Committed by David Sterba
Browse files

btrfs: implement shutdown ioctl



The shutdown ioctl should follow the XFS one, which use magic number 'X',
and ioctl number 125, with a uint32 as flags.

For now btrfs don't distinguish DEFAULT and LOGFLUSH flags (just like
f2fs), both will freeze the fs first (implies committing the current
transaction), setting the SHUTDOWN flag and finally thaw the fs.

For NOLOGFLUSH flag, the freeze/thaw part is skipped thus the current
transaction is aborted.

The new shutdown ioctl is hidden behind experimental features for more
testing.

Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: default avatarAnand Jain <asj@kernel.org>
Tested-by: default avatarAnand Jain <asj@kernel.org>
Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 9b283945
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
@@ -5223,6 +5223,43 @@ static int btrfs_ioctl_subvol_sync(struct btrfs_fs_info *fs_info, void __user *a
	return 0;
}

#ifdef CONFIG_BTRFS_EXPERIMENTAL
static int btrfs_ioctl_shutdown(struct btrfs_fs_info *fs_info, unsigned long arg)
{
	int ret = 0;
	u32 flags;

	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	if (get_user(flags, (u32 __user *)arg))
		return -EFAULT;

	if (flags >= BTRFS_SHUTDOWN_FLAGS_LAST)
		return -EINVAL;

	if (btrfs_is_shutdown(fs_info))
		return 0;

	switch (flags) {
	case BTRFS_SHUTDOWN_FLAGS_LOGFLUSH:
	case BTRFS_SHUTDOWN_FLAGS_DEFAULT:
		ret = freeze_super(fs_info->sb, FREEZE_HOLDER_KERNEL, NULL);
		if (ret)
			return ret;
		btrfs_force_shutdown(fs_info);
		ret = thaw_super(fs_info->sb, FREEZE_HOLDER_KERNEL, NULL);
		if (ret)
			return ret;
		break;
	case BTRFS_SHUTDOWN_FLAGS_NOLOGFLUSH:
		btrfs_force_shutdown(fs_info);
		break;
	}
	return ret;
}
#endif

long btrfs_ioctl(struct file *file, unsigned int
		cmd, unsigned long arg)
{
@@ -5378,6 +5415,10 @@ long btrfs_ioctl(struct file *file, unsigned int
#endif
	case BTRFS_IOC_SUBVOL_SYNC_WAIT:
		return btrfs_ioctl_subvol_sync(fs_info, argp);
#ifdef CONFIG_BTRFS_EXPERIMENTAL
	case BTRFS_IOC_SHUTDOWN:
		return btrfs_ioctl_shutdown(fs_info, arg);
#endif
	}

	return -ENOTTY;
+9 −0
Original line number Diff line number Diff line
@@ -1099,6 +1099,12 @@ enum btrfs_err_code {
	BTRFS_ERROR_DEV_RAID1C4_MIN_NOT_MET,
};

/* Flags for IOC_SHUTDOWN, must match XFS_FSOP_GOING_FLAGS_* flags. */
#define BTRFS_SHUTDOWN_FLAGS_DEFAULT			0x0
#define BTRFS_SHUTDOWN_FLAGS_LOGFLUSH			0x1
#define BTRFS_SHUTDOWN_FLAGS_NOLOGFLUSH			0x2
#define BTRFS_SHUTDOWN_FLAGS_LAST			0x3

#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
				   struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -1220,6 +1226,9 @@ enum btrfs_err_code {
#define BTRFS_IOC_SUBVOL_SYNC_WAIT _IOW(BTRFS_IOCTL_MAGIC, 65, \
					struct btrfs_ioctl_subvol_wait)

/* Shutdown ioctl should follow XFS's interfaces, thus not using btrfs magic. */
#define BTRFS_IOC_SHUTDOWN	_IOR('X', 125, __u32)

#ifdef __cplusplus
}
#endif