diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2010-12-20 03:30:25 -0500 |
---|---|---|
committer | Li Zefan <lizf@cn.fujitsu.com> | 2010-12-22 19:49:19 -0500 |
commit | 0caa102da82799efaba88e234484786a9591c797 (patch) | |
tree | 748bb0d8054bb85256904ffe29913277e5b80684 | |
parent | b83cc9693f39689490970c19f6c5b866f6719a70 (diff) |
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>
-rw-r--r-- | fs/btrfs/ioctl.c | 83 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 2 |
2 files changed, 85 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f066ccb5dddf..ad1983524f97 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -1009,6 +1009,85 @@ out: | |||
1009 | return ret; | 1009 | return ret; |
1010 | } | 1010 | } |
1011 | 1011 | ||
1012 | static noinline int btrfs_ioctl_subvol_getflags(struct file *file, | ||
1013 | void __user *arg) | ||
1014 | { | ||
1015 | struct inode *inode = fdentry(file)->d_inode; | ||
1016 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
1017 | int ret = 0; | ||
1018 | u64 flags = 0; | ||
1019 | |||
1020 | if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) | ||
1021 | return -EINVAL; | ||
1022 | |||
1023 | down_read(&root->fs_info->subvol_sem); | ||
1024 | if (btrfs_root_readonly(root)) | ||
1025 | flags |= BTRFS_SUBVOL_RDONLY; | ||
1026 | up_read(&root->fs_info->subvol_sem); | ||
1027 | |||
1028 | if (copy_to_user(arg, &flags, sizeof(flags))) | ||
1029 | ret = -EFAULT; | ||
1030 | |||
1031 | return ret; | ||
1032 | } | ||
1033 | |||
1034 | static noinline int btrfs_ioctl_subvol_setflags(struct file *file, | ||
1035 | void __user *arg) | ||
1036 | { | ||
1037 | struct inode *inode = fdentry(file)->d_inode; | ||
1038 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
1039 | struct btrfs_trans_handle *trans; | ||
1040 | u64 root_flags; | ||
1041 | u64 flags; | ||
1042 | int ret = 0; | ||
1043 | |||
1044 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
1045 | return -EROFS; | ||
1046 | |||
1047 | if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) | ||
1048 | return -EINVAL; | ||
1049 | |||
1050 | if (copy_from_user(&flags, arg, sizeof(flags))) | ||
1051 | return -EFAULT; | ||
1052 | |||
1053 | if (flags & ~BTRFS_SUBVOL_CREATE_ASYNC) | ||
1054 | return -EINVAL; | ||
1055 | |||
1056 | if (flags & ~BTRFS_SUBVOL_RDONLY) | ||
1057 | return -EOPNOTSUPP; | ||
1058 | |||
1059 | down_write(&root->fs_info->subvol_sem); | ||
1060 | |||
1061 | /* nothing to do */ | ||
1062 | if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root)) | ||
1063 | goto out; | ||
1064 | |||
1065 | root_flags = btrfs_root_flags(&root->root_item); | ||
1066 | if (flags & BTRFS_SUBVOL_RDONLY) | ||
1067 | btrfs_set_root_flags(&root->root_item, | ||
1068 | root_flags | BTRFS_ROOT_SUBVOL_RDONLY); | ||
1069 | else | ||
1070 | btrfs_set_root_flags(&root->root_item, | ||
1071 | root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY); | ||
1072 | |||
1073 | trans = btrfs_start_transaction(root, 1); | ||
1074 | if (IS_ERR(trans)) { | ||
1075 | ret = PTR_ERR(trans); | ||
1076 | goto out_reset; | ||
1077 | } | ||
1078 | |||
1079 | ret = btrfs_update_root(trans, root, | ||
1080 | &root->root_key, &root->root_item); | ||
1081 | |||
1082 | btrfs_commit_transaction(trans, root); | ||
1083 | out_reset: | ||
1084 | if (ret) | ||
1085 | btrfs_set_root_flags(&root->root_item, root_flags); | ||
1086 | out: | ||
1087 | up_write(&root->fs_info->subvol_sem); | ||
1088 | return ret; | ||
1089 | } | ||
1090 | |||
1012 | /* | 1091 | /* |
1013 | * helper to check if the subvolume references other subvolumes | 1092 | * helper to check if the subvolume references other subvolumes |
1014 | */ | 1093 | */ |
@@ -2282,6 +2361,10 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2282 | return btrfs_ioctl_snap_create(file, argp, 1); | 2361 | return btrfs_ioctl_snap_create(file, argp, 1); |
2283 | case BTRFS_IOC_SNAP_DESTROY: | 2362 | case BTRFS_IOC_SNAP_DESTROY: |
2284 | return btrfs_ioctl_snap_destroy(file, argp); | 2363 | return btrfs_ioctl_snap_destroy(file, argp); |
2364 | case BTRFS_IOC_SUBVOL_GETFLAGS: | ||
2365 | return btrfs_ioctl_subvol_getflags(file, argp); | ||
2366 | case BTRFS_IOC_SUBVOL_SETFLAGS: | ||
2367 | return btrfs_ioctl_subvol_setflags(file, argp); | ||
2285 | case BTRFS_IOC_DEFAULT_SUBVOL: | 2368 | case BTRFS_IOC_DEFAULT_SUBVOL: |
2286 | return btrfs_ioctl_default_subvol(file, argp); | 2369 | return btrfs_ioctl_default_subvol(file, argp); |
2287 | case BTRFS_IOC_DEFRAG: | 2370 | case BTRFS_IOC_DEFRAG: |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 52ae489974be..1223223351fa 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
@@ -194,4 +194,6 @@ struct btrfs_ioctl_space_args { | |||
194 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) | 194 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) |
195 | #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ | 195 | #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ |
196 | struct btrfs_ioctl_vol_args_v2) | 196 | struct btrfs_ioctl_vol_args_v2) |
197 | #define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64) | ||
198 | #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) | ||
197 | #endif | 199 | #endif |