diff options
-rw-r--r-- | fs/btrfs/ctree.h | 7 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 3 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 8 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 199 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 3 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 8 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 1 | ||||
-rw-r--r-- | fs/btrfs/xattr.c | 18 |
8 files changed, 197 insertions, 50 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 53b984623983..4acd4c611efa 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -601,6 +601,8 @@ struct btrfs_dir_item { | |||
601 | u8 type; | 601 | u8 type; |
602 | } __attribute__ ((__packed__)); | 602 | } __attribute__ ((__packed__)); |
603 | 603 | ||
604 | #define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) | ||
605 | |||
604 | struct btrfs_root_item { | 606 | struct btrfs_root_item { |
605 | struct btrfs_inode_item inode; | 607 | struct btrfs_inode_item inode; |
606 | __le64 generation; | 608 | __le64 generation; |
@@ -1898,6 +1900,11 @@ BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); | |||
1898 | BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, | 1900 | BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, |
1899 | last_snapshot, 64); | 1901 | last_snapshot, 64); |
1900 | 1902 | ||
1903 | static inline bool btrfs_root_readonly(struct btrfs_root *root) | ||
1904 | { | ||
1905 | return root->root_item.flags & BTRFS_ROOT_SUBVOL_RDONLY; | ||
1906 | } | ||
1907 | |||
1901 | /* struct btrfs_super_block */ | 1908 | /* struct btrfs_super_block */ |
1902 | 1909 | ||
1903 | BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); | 1910 | BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 7e5162e5c411..b180efdc8b68 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -7971,13 +7971,14 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache) | |||
7971 | 7971 | ||
7972 | if (sinfo->bytes_used + sinfo->bytes_reserved + sinfo->bytes_pinned + | 7972 | if (sinfo->bytes_used + sinfo->bytes_reserved + sinfo->bytes_pinned + |
7973 | sinfo->bytes_may_use + sinfo->bytes_readonly + | 7973 | sinfo->bytes_may_use + sinfo->bytes_readonly + |
7974 | cache->reserved_pinned + num_bytes < sinfo->total_bytes) { | 7974 | cache->reserved_pinned + num_bytes <= sinfo->total_bytes) { |
7975 | sinfo->bytes_readonly += num_bytes; | 7975 | sinfo->bytes_readonly += num_bytes; |
7976 | sinfo->bytes_reserved += cache->reserved_pinned; | 7976 | sinfo->bytes_reserved += cache->reserved_pinned; |
7977 | cache->reserved_pinned = 0; | 7977 | cache->reserved_pinned = 0; |
7978 | cache->ro = 1; | 7978 | cache->ro = 1; |
7979 | ret = 0; | 7979 | ret = 0; |
7980 | } | 7980 | } |
7981 | |||
7981 | spin_unlock(&cache->lock); | 7982 | spin_unlock(&cache->lock); |
7982 | spin_unlock(&sinfo->lock); | 7983 | spin_unlock(&sinfo->lock); |
7983 | return ret; | 7984 | return ret; |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index ba563b2a5d6c..1562765c8e6a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -3686,8 +3686,12 @@ static int btrfs_setattr_size(struct inode *inode, struct iattr *attr) | |||
3686 | static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | 3686 | static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) |
3687 | { | 3687 | { |
3688 | struct inode *inode = dentry->d_inode; | 3688 | struct inode *inode = dentry->d_inode; |
3689 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
3689 | int err; | 3690 | int err; |
3690 | 3691 | ||
3692 | if (btrfs_root_readonly(root)) | ||
3693 | return -EROFS; | ||
3694 | |||
3691 | err = inode_change_ok(inode, attr); | 3695 | err = inode_change_ok(inode, attr); |
3692 | if (err) | 3696 | if (err) |
3693 | return err; | 3697 | return err; |
@@ -7226,6 +7230,10 @@ static int btrfs_set_page_dirty(struct page *page) | |||
7226 | 7230 | ||
7227 | static int btrfs_permission(struct inode *inode, int mask) | 7231 | static int btrfs_permission(struct inode *inode, int mask) |
7228 | { | 7232 | { |
7233 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
7234 | |||
7235 | if (btrfs_root_readonly(root) && (mask & MAY_WRITE)) | ||
7236 | return -EROFS; | ||
7229 | if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) | 7237 | if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) |
7230 | return -EACCES; | 7238 | return -EACCES; |
7231 | return generic_permission(inode, mask, btrfs_check_acl); | 7239 | return generic_permission(inode, mask, btrfs_check_acl); |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index b6985d33eede..a506a22b522a 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); |
@@ -918,7 +923,8 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | |||
918 | char *name, | 923 | char *name, |
919 | unsigned long fd, | 924 | unsigned long fd, |
920 | int subvol, | 925 | int subvol, |
921 | u64 *transid) | 926 | u64 *transid, |
927 | bool readonly) | ||
922 | { | 928 | { |
923 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | 929 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; |
924 | struct file *src_file; | 930 | struct file *src_file; |
@@ -936,7 +942,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | |||
936 | 942 | ||
937 | if (subvol) { | 943 | if (subvol) { |
938 | ret = btrfs_mksubvol(&file->f_path, name, namelen, | 944 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
939 | NULL, transid); | 945 | NULL, transid, readonly); |
940 | } else { | 946 | } else { |
941 | struct inode *src_inode; | 947 | struct inode *src_inode; |
942 | src_file = fget(fd); | 948 | src_file = fget(fd); |
@@ -955,7 +961,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | |||
955 | } | 961 | } |
956 | ret = btrfs_mksubvol(&file->f_path, name, namelen, | 962 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
957 | BTRFS_I(src_inode)->root, | 963 | BTRFS_I(src_inode)->root, |
958 | transid); | 964 | transid, readonly); |
959 | fput(src_file); | 965 | fput(src_file); |
960 | } | 966 | } |
961 | out: | 967 | out: |
@@ -963,58 +969,139 @@ out: | |||
963 | } | 969 | } |
964 | 970 | ||
965 | static noinline int btrfs_ioctl_snap_create(struct file *file, | 971 | static noinline int btrfs_ioctl_snap_create(struct file *file, |
966 | void __user *arg, int subvol, | 972 | void __user *arg, int subvol) |
967 | int v2) | ||
968 | { | 973 | { |
969 | struct btrfs_ioctl_vol_args *vol_args = NULL; | 974 | struct btrfs_ioctl_vol_args *vol_args; |
970 | struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL; | ||
971 | char *name; | ||
972 | u64 fd; | ||
973 | int ret; | 975 | int ret; |
974 | 976 | ||
975 | if (v2) { | 977 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
976 | u64 transid = 0; | 978 | if (IS_ERR(vol_args)) |
977 | u64 *ptr = NULL; | 979 | return PTR_ERR(vol_args); |
978 | 980 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | |
979 | vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2)); | ||
980 | if (IS_ERR(vol_args_v2)) | ||
981 | return PTR_ERR(vol_args_v2); | ||
982 | 981 | ||
983 | if (vol_args_v2->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) { | 982 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
984 | ret = -EINVAL; | 983 | vol_args->fd, subvol, |
985 | goto out; | 984 | NULL, false); |
986 | } | ||
987 | 985 | ||
988 | name = vol_args_v2->name; | 986 | kfree(vol_args); |
989 | fd = vol_args_v2->fd; | 987 | return ret; |
990 | vol_args_v2->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; | 988 | } |
991 | 989 | ||
992 | if (vol_args_v2->flags & BTRFS_SUBVOL_CREATE_ASYNC) | 990 | static noinline int btrfs_ioctl_snap_create_v2(struct file *file, |
993 | ptr = &transid; | 991 | void __user *arg, int subvol) |
992 | { | ||
993 | struct btrfs_ioctl_vol_args_v2 *vol_args; | ||
994 | int ret; | ||
995 | u64 transid = 0; | ||
996 | u64 *ptr = NULL; | ||
997 | bool readonly = false; | ||
994 | 998 | ||
995 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | 999 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
996 | subvol, ptr); | 1000 | if (IS_ERR(vol_args)) |
1001 | return PTR_ERR(vol_args); | ||
1002 | vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; | ||
997 | 1003 | ||
998 | if (ret == 0 && ptr && | 1004 | if (vol_args->flags & |
999 | copy_to_user(arg + | 1005 | ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY)) { |
1000 | offsetof(struct btrfs_ioctl_vol_args_v2, | 1006 | ret = -EOPNOTSUPP; |
1001 | transid), ptr, sizeof(*ptr))) | 1007 | goto out; |
1002 | ret = -EFAULT; | ||
1003 | } else { | ||
1004 | vol_args = memdup_user(arg, sizeof(*vol_args)); | ||
1005 | if (IS_ERR(vol_args)) | ||
1006 | return PTR_ERR(vol_args); | ||
1007 | name = vol_args->name; | ||
1008 | fd = vol_args->fd; | ||
1009 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | ||
1010 | |||
1011 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | ||
1012 | subvol, NULL); | ||
1013 | } | 1008 | } |
1009 | |||
1010 | if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC) | ||
1011 | ptr = &transid; | ||
1012 | if (vol_args->flags & BTRFS_SUBVOL_RDONLY) | ||
1013 | readonly = true; | ||
1014 | |||
1015 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, | ||
1016 | vol_args->fd, subvol, | ||
1017 | ptr, readonly); | ||
1018 | |||
1019 | if (ret == 0 && ptr && | ||
1020 | copy_to_user(arg + | ||
1021 | offsetof(struct btrfs_ioctl_vol_args_v2, | ||
1022 | transid), ptr, sizeof(*ptr))) | ||
1023 | ret = -EFAULT; | ||
1014 | out: | 1024 | out: |
1015 | kfree(vol_args); | 1025 | kfree(vol_args); |
1016 | kfree(vol_args_v2); | 1026 | return ret; |
1027 | } | ||
1028 | |||
1029 | static noinline int btrfs_ioctl_subvol_getflags(struct file *file, | ||
1030 | void __user *arg) | ||
1031 | { | ||
1032 | struct inode *inode = fdentry(file)->d_inode; | ||
1033 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
1034 | int ret = 0; | ||
1035 | u64 flags = 0; | ||
1036 | |||
1037 | if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) | ||
1038 | return -EINVAL; | ||
1039 | |||
1040 | down_read(&root->fs_info->subvol_sem); | ||
1041 | if (btrfs_root_readonly(root)) | ||
1042 | flags |= BTRFS_SUBVOL_RDONLY; | ||
1043 | up_read(&root->fs_info->subvol_sem); | ||
1044 | |||
1045 | if (copy_to_user(arg, &flags, sizeof(flags))) | ||
1046 | ret = -EFAULT; | ||
1047 | |||
1048 | return ret; | ||
1049 | } | ||
1050 | |||
1051 | static noinline int btrfs_ioctl_subvol_setflags(struct file *file, | ||
1052 | void __user *arg) | ||
1053 | { | ||
1054 | struct inode *inode = fdentry(file)->d_inode; | ||
1055 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
1056 | struct btrfs_trans_handle *trans; | ||
1057 | u64 root_flags; | ||
1058 | u64 flags; | ||
1059 | int ret = 0; | ||
1060 | |||
1061 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
1062 | return -EROFS; | ||
1063 | |||
1064 | if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) | ||
1065 | return -EINVAL; | ||
1066 | |||
1067 | if (copy_from_user(&flags, arg, sizeof(flags))) | ||
1068 | return -EFAULT; | ||
1069 | |||
1070 | if (flags & ~BTRFS_SUBVOL_CREATE_ASYNC) | ||
1071 | return -EINVAL; | ||
1072 | |||
1073 | if (flags & ~BTRFS_SUBVOL_RDONLY) | ||
1074 | return -EOPNOTSUPP; | ||
1075 | |||
1076 | down_write(&root->fs_info->subvol_sem); | ||
1077 | |||
1078 | /* nothing to do */ | ||
1079 | if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root)) | ||
1080 | goto out; | ||
1081 | |||
1082 | root_flags = btrfs_root_flags(&root->root_item); | ||
1083 | if (flags & BTRFS_SUBVOL_RDONLY) | ||
1084 | btrfs_set_root_flags(&root->root_item, | ||
1085 | root_flags | BTRFS_ROOT_SUBVOL_RDONLY); | ||
1086 | else | ||
1087 | btrfs_set_root_flags(&root->root_item, | ||
1088 | root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY); | ||
1089 | |||
1090 | trans = btrfs_start_transaction(root, 1); | ||
1091 | if (IS_ERR(trans)) { | ||
1092 | ret = PTR_ERR(trans); | ||
1093 | goto out_reset; | ||
1094 | } | ||
1017 | 1095 | ||
1096 | ret = btrfs_update_root(trans, root, | ||
1097 | &root->root_key, &root->root_item); | ||
1098 | |||
1099 | btrfs_commit_transaction(trans, root); | ||
1100 | out_reset: | ||
1101 | if (ret) | ||
1102 | btrfs_set_root_flags(&root->root_item, root_flags); | ||
1103 | out: | ||
1104 | up_write(&root->fs_info->subvol_sem); | ||
1018 | return ret; | 1105 | return ret; |
1019 | } | 1106 | } |
1020 | 1107 | ||
@@ -1526,6 +1613,9 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) | |||
1526 | struct btrfs_ioctl_defrag_range_args *range; | 1613 | struct btrfs_ioctl_defrag_range_args *range; |
1527 | int ret; | 1614 | int ret; |
1528 | 1615 | ||
1616 | if (btrfs_root_readonly(root)) | ||
1617 | return -EROFS; | ||
1618 | |||
1529 | ret = mnt_want_write(file->f_path.mnt); | 1619 | ret = mnt_want_write(file->f_path.mnt); |
1530 | if (ret) | 1620 | if (ret) |
1531 | return ret; | 1621 | return ret; |
@@ -1654,6 +1744,9 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1654 | if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) | 1744 | if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) |
1655 | return -EINVAL; | 1745 | return -EINVAL; |
1656 | 1746 | ||
1747 | if (btrfs_root_readonly(root)) | ||
1748 | return -EROFS; | ||
1749 | |||
1657 | ret = mnt_want_write(file->f_path.mnt); | 1750 | ret = mnt_want_write(file->f_path.mnt); |
1658 | if (ret) | 1751 | if (ret) |
1659 | return ret; | 1752 | return ret; |
@@ -1975,6 +2068,10 @@ static long btrfs_ioctl_trans_start(struct file *file) | |||
1975 | if (file->private_data) | 2068 | if (file->private_data) |
1976 | goto out; | 2069 | goto out; |
1977 | 2070 | ||
2071 | ret = -EROFS; | ||
2072 | if (btrfs_root_readonly(root)) | ||
2073 | goto out; | ||
2074 | |||
1978 | ret = mnt_want_write(file->f_path.mnt); | 2075 | ret = mnt_want_write(file->f_path.mnt); |
1979 | if (ret) | 2076 | if (ret) |
1980 | goto out; | 2077 | goto out; |
@@ -2274,13 +2371,17 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2274 | case FS_IOC_GETVERSION: | 2371 | case FS_IOC_GETVERSION: |
2275 | return btrfs_ioctl_getversion(file, argp); | 2372 | return btrfs_ioctl_getversion(file, argp); |
2276 | case BTRFS_IOC_SNAP_CREATE: | 2373 | case BTRFS_IOC_SNAP_CREATE: |
2277 | return btrfs_ioctl_snap_create(file, argp, 0, 0); | 2374 | return btrfs_ioctl_snap_create(file, argp, 0); |
2278 | case BTRFS_IOC_SNAP_CREATE_V2: | 2375 | case BTRFS_IOC_SNAP_CREATE_V2: |
2279 | return btrfs_ioctl_snap_create(file, argp, 0, 1); | 2376 | return btrfs_ioctl_snap_create_v2(file, argp, 0); |
2280 | case BTRFS_IOC_SUBVOL_CREATE: | 2377 | case BTRFS_IOC_SUBVOL_CREATE: |
2281 | return btrfs_ioctl_snap_create(file, argp, 1, 0); | 2378 | return btrfs_ioctl_snap_create(file, argp, 1); |
2282 | case BTRFS_IOC_SNAP_DESTROY: | 2379 | case BTRFS_IOC_SNAP_DESTROY: |
2283 | return btrfs_ioctl_snap_destroy(file, argp); | 2380 | return btrfs_ioctl_snap_destroy(file, argp); |
2381 | case BTRFS_IOC_SUBVOL_GETFLAGS: | ||
2382 | return btrfs_ioctl_subvol_getflags(file, argp); | ||
2383 | case BTRFS_IOC_SUBVOL_SETFLAGS: | ||
2384 | return btrfs_ioctl_subvol_setflags(file, argp); | ||
2284 | case BTRFS_IOC_DEFAULT_SUBVOL: | 2385 | case BTRFS_IOC_DEFAULT_SUBVOL: |
2285 | return btrfs_ioctl_default_subvol(file, argp); | 2386 | return btrfs_ioctl_default_subvol(file, argp); |
2286 | case BTRFS_IOC_DEFRAG: | 2387 | case BTRFS_IOC_DEFRAG: |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 24d0f4628240..8fb382167b13 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
@@ -31,6 +31,7 @@ struct btrfs_ioctl_vol_args { | |||
31 | }; | 31 | }; |
32 | 32 | ||
33 | #define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) | 33 | #define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) |
34 | #define BTRFS_SUBVOL_RDONLY (1ULL << 1) | ||
34 | 35 | ||
35 | #define BTRFS_SUBVOL_NAME_MAX 4039 | 36 | #define BTRFS_SUBVOL_NAME_MAX 4039 |
36 | struct btrfs_ioctl_vol_args_v2 { | 37 | struct btrfs_ioctl_vol_args_v2 { |
@@ -200,4 +201,6 @@ struct btrfs_ioctl_space_args { | |||
200 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) | 201 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) |
201 | #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ | 202 | #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ |
202 | struct btrfs_ioctl_vol_args_v2) | 203 | struct btrfs_ioctl_vol_args_v2) |
204 | #define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64) | ||
205 | #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) | ||
203 | #endif | 206 | #endif |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index f50e931fc217..29e30d832ec9 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -910,6 +910,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
910 | u64 to_reserve = 0; | 910 | u64 to_reserve = 0; |
911 | u64 index = 0; | 911 | u64 index = 0; |
912 | u64 objectid; | 912 | u64 objectid; |
913 | u64 root_flags; | ||
913 | 914 | ||
914 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); | 915 | new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); |
915 | if (!new_root_item) { | 916 | if (!new_root_item) { |
@@ -967,6 +968,13 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
967 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); | 968 | btrfs_set_root_last_snapshot(&root->root_item, trans->transid); |
968 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | 969 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); |
969 | 970 | ||
971 | root_flags = btrfs_root_flags(new_root_item); | ||
972 | if (pending->readonly) | ||
973 | root_flags |= BTRFS_ROOT_SUBVOL_RDONLY; | ||
974 | else | ||
975 | root_flags &= ~BTRFS_ROOT_SUBVOL_RDONLY; | ||
976 | btrfs_set_root_flags(new_root_item, root_flags); | ||
977 | |||
970 | old = btrfs_lock_root_node(root); | 978 | old = btrfs_lock_root_node(root); |
971 | btrfs_cow_block(trans, root, old, NULL, 0, &old); | 979 | btrfs_cow_block(trans, root, old, NULL, 0, &old); |
972 | btrfs_set_lock_blocking(old); | 980 | btrfs_set_lock_blocking(old); |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index f104b57ad4ef..229a594cacd5 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -62,6 +62,7 @@ struct btrfs_pending_snapshot { | |||
62 | struct btrfs_block_rsv block_rsv; | 62 | struct btrfs_block_rsv block_rsv; |
63 | /* extra metadata reseration for relocation */ | 63 | /* extra metadata reseration for relocation */ |
64 | int error; | 64 | int error; |
65 | bool readonly; | ||
65 | struct list_head list; | 66 | struct list_head list; |
66 | }; | 67 | }; |
67 | 68 | ||
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index 698fdd2c739c..a5776531dc2b 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c | |||
@@ -316,6 +316,15 @@ ssize_t btrfs_getxattr(struct dentry *dentry, const char *name, | |||
316 | int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 316 | int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
317 | size_t size, int flags) | 317 | size_t size, int flags) |
318 | { | 318 | { |
319 | struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; | ||
320 | |||
321 | /* | ||
322 | * The permission on security.* and system.* is not checked | ||
323 | * in permission(). | ||
324 | */ | ||
325 | if (btrfs_root_readonly(root)) | ||
326 | return -EROFS; | ||
327 | |||
319 | /* | 328 | /* |
320 | * If this is a request for a synthetic attribute in the system.* | 329 | * If this is a request for a synthetic attribute in the system.* |
321 | * namespace use the generic infrastructure to resolve a handler | 330 | * namespace use the generic infrastructure to resolve a handler |
@@ -336,6 +345,15 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, | |||
336 | 345 | ||
337 | int btrfs_removexattr(struct dentry *dentry, const char *name) | 346 | int btrfs_removexattr(struct dentry *dentry, const char *name) |
338 | { | 347 | { |
348 | struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; | ||
349 | |||
350 | /* | ||
351 | * The permission on security.* and system.* is not checked | ||
352 | * in permission(). | ||
353 | */ | ||
354 | if (btrfs_root_readonly(root)) | ||
355 | return -EROFS; | ||
356 | |||
339 | /* | 357 | /* |
340 | * If this is a request for a synthetic attribute in the system.* | 358 | * If this is a request for a synthetic attribute in the system.* |
341 | * namespace use the generic infrastructure to resolve a handler | 359 | * namespace use the generic infrastructure to resolve a handler |