diff options
author | Chris Mason <chris.mason@oracle.com> | 2011-01-16 11:24:45 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2011-01-16 11:24:45 -0500 |
commit | 26c79f6ba0ccdc4bbc8ef8721406d37e9178e30b (patch) | |
tree | c5bcbf8f605afdae1a89ea2617f29052ac8c6f18 /fs/btrfs/ioctl.c | |
parent | 65e5341b9a0c39767ae1fecc727d70eda0dd6d83 (diff) | |
parent | 0caa102da82799efaba88e234484786a9591c797 (diff) |
Merge branch 'readonly-snapshots' of git://repo.or.cz/linux-btrfs-devel into btrfs-38
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 199 |
1 files changed, 150 insertions, 49 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f87552a1d7ea..ad1983524f97 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -147,6 +147,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
147 | unsigned int flags, oldflags; | 147 | unsigned int flags, oldflags; |
148 | int ret; | 148 | int ret; |
149 | 149 | ||
150 | if (btrfs_root_readonly(root)) | ||
151 | return -EROFS; | ||
152 | |||
150 | if (copy_from_user(&flags, arg, sizeof(flags))) | 153 | if (copy_from_user(&flags, arg, sizeof(flags))) |
151 | return -EFAULT; | 154 | return -EFAULT; |
152 | 155 | ||
@@ -360,7 +363,8 @@ fail: | |||
360 | } | 363 | } |
361 | 364 | ||
362 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | 365 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, |
363 | char *name, int namelen, u64 *async_transid) | 366 | char *name, int namelen, u64 *async_transid, |
367 | bool readonly) | ||
364 | { | 368 | { |
365 | struct inode *inode; | 369 | struct inode *inode; |
366 | struct dentry *parent; | 370 | struct dentry *parent; |
@@ -378,6 +382,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
378 | btrfs_init_block_rsv(&pending_snapshot->block_rsv); | 382 | btrfs_init_block_rsv(&pending_snapshot->block_rsv); |
379 | pending_snapshot->dentry = dentry; | 383 | pending_snapshot->dentry = dentry; |
380 | pending_snapshot->root = root; | 384 | pending_snapshot->root = root; |
385 | pending_snapshot->readonly = readonly; | ||
381 | 386 | ||
382 | trans = btrfs_start_transaction(root->fs_info->extent_root, 5); | 387 | trans = btrfs_start_transaction(root->fs_info->extent_root, 5); |
383 | if (IS_ERR(trans)) { | 388 | if (IS_ERR(trans)) { |
@@ -509,7 +514,7 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | |||
509 | static noinline int btrfs_mksubvol(struct path *parent, | 514 | static noinline int btrfs_mksubvol(struct path *parent, |
510 | char *name, int namelen, | 515 | char *name, int namelen, |
511 | struct btrfs_root *snap_src, | 516 | struct btrfs_root *snap_src, |
512 | u64 *async_transid) | 517 | u64 *async_transid, bool readonly) |
513 | { | 518 | { |
514 | struct inode *dir = parent->dentry->d_inode; | 519 | struct inode *dir = parent->dentry->d_inode; |
515 | struct dentry *dentry; | 520 | struct dentry *dentry; |
@@ -541,7 +546,7 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
541 | 546 | ||
542 | if (snap_src) { | 547 | if (snap_src) { |
543 | error = create_snapshot(snap_src, dentry, | 548 | error = create_snapshot(snap_src, dentry, |
544 | name, namelen, async_transid); | 549 | name, namelen, async_transid, readonly); |
545 | } else { | 550 | } else { |
546 | error = create_subvol(BTRFS_I(dir)->root, dentry, | 551 | error = create_subvol(BTRFS_I(dir)->root, dentry, |
547 | name, namelen, async_transid); | 552 | name, namelen, async_transid); |
@@ -901,7 +906,8 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | |||
901 | char *name, | 906 | char *name, |
902 | unsigned long fd, | 907 | unsigned long fd, |
903 | int subvol, | 908 | int subvol, |
904 | u64 *transid) | 909 | u64 *transid, |
910 | bool readonly) | ||
905 | { | 911 | { |
906 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | 912 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; |
907 | struct file *src_file; | 913 | struct file *src_file; |
@@ -919,7 +925,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | |||
919 | 925 | ||
920 | if (subvol) { | 926 | if (subvol) { |
921 | ret = btrfs_mksubvol(&file->f_path, name, namelen, | 927 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
922 | NULL, transid); | 928 | NULL, transid, readonly); |
923 | } else { | 929 | } else { |
924 | struct inode *src_inode; | 930 | struct inode *src_inode; |
925 | src_file = fget(fd); | 931 | src_file = fget(fd); |
@@ -938,7 +944,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | |||
938 | } | 944 | } |
939 | ret = btrfs_mksubvol(&file->f_path, name, namelen, | 945 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
940 | BTRFS_I(src_inode)->root, | 946 | BTRFS_I(src_inode)->root, |
941 | transid); | 947 | transid, readonly); |
942 | fput(src_file); | 948 | fput(src_file); |
943 | } | 949 | } |
944 | out: | 950 | out: |
@@ -946,58 +952,139 @@ out: | |||
946 | } | 952 | } |
947 | 953 | ||
948 | static noinline int btrfs_ioctl_snap_create(struct file *file, | 954 | static noinline int btrfs_ioctl_snap_create(struct file *file, |
949 | void __user *arg, int subvol, | 955 | void __user *arg, int subvol) |
950 | int v2) | ||
951 | { | 956 | { |
952 | struct btrfs_ioctl_vol_args *vol_args = NULL; | 957 | struct btrfs_ioctl_vol_args *vol_args; |
953 | struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL; | ||
954 | char *name; | ||
955 | u64 fd; | ||
956 | int ret; | 958 | int ret; |
957 | 959 | ||
958 | if (v2) { | 960 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
959 | u64 transid = 0; | 961 | if (IS_ERR(vol_args)) |
960 | u64 *ptr = NULL; | 962 | return PTR_ERR(vol_args); |
961 | 963 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | |
962 | vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2)); | ||
963 | if (IS_ERR(vol_args_v2)) | ||
964 | return PTR_ERR(vol_args_v2); | ||
965 | 964 | ||
966 | if (vol_args_v2->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) { | 965 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
967 | ret = -EINVAL; | 966 | vol_args->fd, subvol, |
968 | goto out; | 967 | NULL, false); |
969 | } | ||
970 | 968 | ||
971 | name = vol_args_v2->name; | 969 | kfree(vol_args); |
972 | fd = vol_args_v2->fd; | 970 | return ret; |
973 | vol_args_v2->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; | 971 | } |
974 | 972 | ||
975 | if (vol_args_v2->flags & BTRFS_SUBVOL_CREATE_ASYNC) | 973 | static noinline int btrfs_ioctl_snap_create_v2(struct file *file, |
976 | ptr = &transid; | 974 | void __user *arg, int subvol) |
975 | { | ||
976 | struct btrfs_ioctl_vol_args_v2 *vol_args; | ||
977 | int ret; | ||
978 | u64 transid = 0; | ||
979 | u64 *ptr = NULL; | ||
980 | bool readonly = false; | ||
977 | 981 | ||
978 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | 982 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
979 | subvol, ptr); | 983 | if (IS_ERR(vol_args)) |
984 | return PTR_ERR(vol_args); | ||
985 | vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; | ||
980 | 986 | ||
981 | if (ret == 0 && ptr && | 987 | if (vol_args->flags & |
982 | copy_to_user(arg + | 988 | ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY)) { |
983 | offsetof(struct btrfs_ioctl_vol_args_v2, | 989 | ret = -EOPNOTSUPP; |
984 | transid), ptr, sizeof(*ptr))) | 990 | goto out; |
985 | ret = -EFAULT; | ||
986 | } else { | ||
987 | vol_args = memdup_user(arg, sizeof(*vol_args)); | ||
988 | if (IS_ERR(vol_args)) | ||
989 | return PTR_ERR(vol_args); | ||
990 | name = vol_args->name; | ||
991 | fd = vol_args->fd; | ||
992 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | ||
993 | |||
994 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | ||
995 | subvol, NULL); | ||
996 | } | 991 | } |
992 | |||
993 | if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC) | ||
994 | ptr = &transid; | ||
995 | if (vol_args->flags & BTRFS_SUBVOL_RDONLY) | ||
996 | readonly = true; | ||
997 | |||
998 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, | ||
999 | vol_args->fd, subvol, | ||
1000 | ptr, readonly); | ||
1001 | |||
1002 | if (ret == 0 && ptr && | ||
1003 | copy_to_user(arg + | ||
1004 | offsetof(struct btrfs_ioctl_vol_args_v2, | ||
1005 | transid), ptr, sizeof(*ptr))) | ||
1006 | ret = -EFAULT; | ||
997 | out: | 1007 | out: |
998 | kfree(vol_args); | 1008 | kfree(vol_args); |
999 | kfree(vol_args_v2); | 1009 | return ret; |
1010 | } | ||
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 | } | ||
1000 | 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); | ||
1001 | return ret; | 1088 | return ret; |
1002 | } | 1089 | } |
1003 | 1090 | ||
@@ -1509,6 +1596,9 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) | |||
1509 | struct btrfs_ioctl_defrag_range_args *range; | 1596 | struct btrfs_ioctl_defrag_range_args *range; |
1510 | int ret; | 1597 | int ret; |
1511 | 1598 | ||
1599 | if (btrfs_root_readonly(root)) | ||
1600 | return -EROFS; | ||
1601 | |||
1512 | ret = mnt_want_write(file->f_path.mnt); | 1602 | ret = mnt_want_write(file->f_path.mnt); |
1513 | if (ret) | 1603 | if (ret) |
1514 | return ret; | 1604 | return ret; |
@@ -1637,6 +1727,9 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1637 | if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) | 1727 | if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) |
1638 | return -EINVAL; | 1728 | return -EINVAL; |
1639 | 1729 | ||
1730 | if (btrfs_root_readonly(root)) | ||
1731 | return -EROFS; | ||
1732 | |||
1640 | ret = mnt_want_write(file->f_path.mnt); | 1733 | ret = mnt_want_write(file->f_path.mnt); |
1641 | if (ret) | 1734 | if (ret) |
1642 | return ret; | 1735 | return ret; |
@@ -1958,6 +2051,10 @@ static long btrfs_ioctl_trans_start(struct file *file) | |||
1958 | if (file->private_data) | 2051 | if (file->private_data) |
1959 | goto out; | 2052 | goto out; |
1960 | 2053 | ||
2054 | ret = -EROFS; | ||
2055 | if (btrfs_root_readonly(root)) | ||
2056 | goto out; | ||
2057 | |||
1961 | ret = mnt_want_write(file->f_path.mnt); | 2058 | ret = mnt_want_write(file->f_path.mnt); |
1962 | if (ret) | 2059 | if (ret) |
1963 | goto out; | 2060 | goto out; |
@@ -2257,13 +2354,17 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2257 | case FS_IOC_GETVERSION: | 2354 | case FS_IOC_GETVERSION: |
2258 | return btrfs_ioctl_getversion(file, argp); | 2355 | return btrfs_ioctl_getversion(file, argp); |
2259 | case BTRFS_IOC_SNAP_CREATE: | 2356 | case BTRFS_IOC_SNAP_CREATE: |
2260 | return btrfs_ioctl_snap_create(file, argp, 0, 0); | 2357 | return btrfs_ioctl_snap_create(file, argp, 0); |
2261 | case BTRFS_IOC_SNAP_CREATE_V2: | 2358 | case BTRFS_IOC_SNAP_CREATE_V2: |
2262 | return btrfs_ioctl_snap_create(file, argp, 0, 1); | 2359 | return btrfs_ioctl_snap_create_v2(file, argp, 0); |
2263 | case BTRFS_IOC_SUBVOL_CREATE: | 2360 | case BTRFS_IOC_SUBVOL_CREATE: |
2264 | return btrfs_ioctl_snap_create(file, argp, 1, 0); | 2361 | return btrfs_ioctl_snap_create(file, argp, 1); |
2265 | case BTRFS_IOC_SNAP_DESTROY: | 2362 | case BTRFS_IOC_SNAP_DESTROY: |
2266 | 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); | ||
2267 | case BTRFS_IOC_DEFAULT_SUBVOL: | 2368 | case BTRFS_IOC_DEFAULT_SUBVOL: |
2268 | return btrfs_ioctl_default_subvol(file, argp); | 2369 | return btrfs_ioctl_default_subvol(file, argp); |
2269 | case BTRFS_IOC_DEFRAG: | 2370 | case BTRFS_IOC_DEFRAG: |