aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h7
-rw-r--r--fs/btrfs/extent-tree.c3
-rw-r--r--fs/btrfs/inode.c8
-rw-r--r--fs/btrfs/ioctl.c199
-rw-r--r--fs/btrfs/ioctl.h3
-rw-r--r--fs/btrfs/transaction.c8
-rw-r--r--fs/btrfs/transaction.h1
-rw-r--r--fs/btrfs/xattr.c18
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
604struct btrfs_root_item { 606struct 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);
1898BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, 1900BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
1899 last_snapshot, 64); 1901 last_snapshot, 64);
1900 1902
1903static 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
1903BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); 1910BTRFS_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)
3686static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) 3686static 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
7227static int btrfs_permission(struct inode *inode, int mask) 7231static 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
362static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, 365static 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)
509static noinline int btrfs_mksubvol(struct path *parent, 514static 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 }
961out: 967out:
@@ -963,58 +969,139 @@ out:
963} 969}
964 970
965static noinline int btrfs_ioctl_snap_create(struct file *file, 971static 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) 990static 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;
1014out: 1024out:
1015 kfree(vol_args); 1025 kfree(vol_args);
1016 kfree(vol_args_v2); 1026 return ret;
1027}
1028
1029static 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
1051static 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);
1100out_reset:
1101 if (ret)
1102 btrfs_set_root_flags(&root->root_item, root_flags);
1103out:
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
36struct btrfs_ioctl_vol_args_v2 { 37struct 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,
316int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, 316int 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
337int btrfs_removexattr(struct dentry *dentry, const char *name) 346int 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