Btrfs: Add BTRFS_IOC_SUBVOL_GETFLAGS/SETFLAGS ioctls
This allows us to set a snapshot or a subvolume readonly or writable on the fly. Usage: Set BTRFS_SUBVOL_RDONLY of btrfs_ioctl_vol_arg_v2->flags, and then call ioctl(BTRFS_IOCTL_SUBVOL_SETFLAGS); Changelog for v3: - Change to pass __u64 as ioctl parameter. Changelog for v2: - Add _GETFLAGS ioctl. - Check if the passed fd is the root of a subvolume. - Change the name from _SNAP_SETFLAGS to _SUBVOL_SETFLAGS. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
This commit is contained in:
parent
b83cc9693f
commit
0caa102da8
|
@ -1009,6 +1009,85 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static noinline int btrfs_ioctl_subvol_getflags(struct file *file,
|
||||
void __user *arg)
|
||||
{
|
||||
struct inode *inode = fdentry(file)->d_inode;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
int ret = 0;
|
||||
u64 flags = 0;
|
||||
|
||||
if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID)
|
||||
return -EINVAL;
|
||||
|
||||
down_read(&root->fs_info->subvol_sem);
|
||||
if (btrfs_root_readonly(root))
|
||||
flags |= BTRFS_SUBVOL_RDONLY;
|
||||
up_read(&root->fs_info->subvol_sem);
|
||||
|
||||
if (copy_to_user(arg, &flags, sizeof(flags)))
|
||||
ret = -EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
|
||||
void __user *arg)
|
||||
{
|
||||
struct inode *inode = fdentry(file)->d_inode;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_trans_handle *trans;
|
||||
u64 root_flags;
|
||||
u64 flags;
|
||||
int ret = 0;
|
||||
|
||||
if (root->fs_info->sb->s_flags & MS_RDONLY)
|
||||
return -EROFS;
|
||||
|
||||
if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&flags, arg, sizeof(flags)))
|
||||
return -EFAULT;
|
||||
|
||||
if (flags & ~BTRFS_SUBVOL_CREATE_ASYNC)
|
||||
return -EINVAL;
|
||||
|
||||
if (flags & ~BTRFS_SUBVOL_RDONLY)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
down_write(&root->fs_info->subvol_sem);
|
||||
|
||||
/* nothing to do */
|
||||
if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root))
|
||||
goto out;
|
||||
|
||||
root_flags = btrfs_root_flags(&root->root_item);
|
||||
if (flags & BTRFS_SUBVOL_RDONLY)
|
||||
btrfs_set_root_flags(&root->root_item,
|
||||
root_flags | BTRFS_ROOT_SUBVOL_RDONLY);
|
||||
else
|
||||
btrfs_set_root_flags(&root->root_item,
|
||||
root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY);
|
||||
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
if (IS_ERR(trans)) {
|
||||
ret = PTR_ERR(trans);
|
||||
goto out_reset;
|
||||
}
|
||||
|
||||
ret = btrfs_update_root(trans, root,
|
||||
&root->root_key, &root->root_item);
|
||||
|
||||
btrfs_commit_transaction(trans, root);
|
||||
out_reset:
|
||||
if (ret)
|
||||
btrfs_set_root_flags(&root->root_item, root_flags);
|
||||
out:
|
||||
up_write(&root->fs_info->subvol_sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* helper to check if the subvolume references other subvolumes
|
||||
*/
|
||||
|
@ -2282,6 +2361,10 @@ long btrfs_ioctl(struct file *file, unsigned int
|
|||
return btrfs_ioctl_snap_create(file, argp, 1);
|
||||
case BTRFS_IOC_SNAP_DESTROY:
|
||||
return btrfs_ioctl_snap_destroy(file, argp);
|
||||
case BTRFS_IOC_SUBVOL_GETFLAGS:
|
||||
return btrfs_ioctl_subvol_getflags(file, argp);
|
||||
case BTRFS_IOC_SUBVOL_SETFLAGS:
|
||||
return btrfs_ioctl_subvol_setflags(file, argp);
|
||||
case BTRFS_IOC_DEFAULT_SUBVOL:
|
||||
return btrfs_ioctl_default_subvol(file, argp);
|
||||
case BTRFS_IOC_DEFRAG:
|
||||
|
|
|
@ -194,4 +194,6 @@ struct btrfs_ioctl_space_args {
|
|||
#define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
|
||||
#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
|
||||
struct btrfs_ioctl_vol_args_v2)
|
||||
#define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64)
|
||||
#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue