diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2010-12-20 03:04:08 -0500 |
---|---|---|
committer | Li Zefan <lizf@cn.fujitsu.com> | 2010-12-22 19:49:17 -0500 |
commit | b83cc9693f39689490970c19f6c5b866f6719a70 (patch) | |
tree | b86d09884015fce195a4ac5ff1e8ec5f6ec00677 | |
parent | fa0d2b9bd717340e0bc4850a80ac0eb344e9a7fb (diff) |
Btrfs: Add readonly snapshots support
Usage:
Set BTRFS_SUBVOL_RDONLY of btrfs_ioctl_vol_arg_v2->flags, and call
ioctl(BTRFS_I0CTL_SNAP_CREATE_V2).
Implementation:
- Set readonly bit of btrfs_root_item->flags.
- Add readonly checks in btrfs_permission (inode_permission),
btrfs_setattr, btrfs_set/remove_xattr and some ioctls.
Changelog for v3:
- Eliminate btrfs_root->readonly, but check btrfs_root->root_item.flags.
- Rename BTRFS_ROOT_SNAP_RDONLY to BTRFS_ROOT_SUBVOL_RDONLY.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
-rw-r--r-- | fs/btrfs/ctree.h | 7 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 8 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 42 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 1 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 8 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 1 | ||||
-rw-r--r-- | fs/btrfs/xattr.c | 18 |
7 files changed, 75 insertions, 10 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index af52f6d7a4d8..4403e5643d43 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -597,6 +597,8 @@ struct btrfs_dir_item { | |||
597 | u8 type; | 597 | u8 type; |
598 | } __attribute__ ((__packed__)); | 598 | } __attribute__ ((__packed__)); |
599 | 599 | ||
600 | #define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) | ||
601 | |||
600 | struct btrfs_root_item { | 602 | struct btrfs_root_item { |
601 | struct btrfs_inode_item inode; | 603 | struct btrfs_inode_item inode; |
602 | __le64 generation; | 604 | __le64 generation; |
@@ -1893,6 +1895,11 @@ BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); | |||
1893 | BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, | 1895 | BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, |
1894 | last_snapshot, 64); | 1896 | last_snapshot, 64); |
1895 | 1897 | ||
1898 | static inline bool btrfs_root_readonly(struct btrfs_root *root) | ||
1899 | { | ||
1900 | return root->root_item.flags & BTRFS_ROOT_SUBVOL_RDONLY; | ||
1901 | } | ||
1902 | |||
1896 | /* struct btrfs_super_block */ | 1903 | /* struct btrfs_super_block */ |
1897 | 1904 | ||
1898 | BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); | 1905 | BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5f9194438f7c..956f1eb913b1 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -3671,8 +3671,12 @@ static int btrfs_setattr_size(struct inode *inode, struct iattr *attr) | |||
3671 | static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | 3671 | static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) |
3672 | { | 3672 | { |
3673 | struct inode *inode = dentry->d_inode; | 3673 | struct inode *inode = dentry->d_inode; |
3674 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
3674 | int err; | 3675 | int err; |
3675 | 3676 | ||
3677 | if (btrfs_root_readonly(root)) | ||
3678 | return -EROFS; | ||
3679 | |||
3676 | err = inode_change_ok(inode, attr); | 3680 | err = inode_change_ok(inode, attr); |
3677 | if (err) | 3681 | if (err) |
3678 | return err; | 3682 | return err; |
@@ -7206,6 +7210,10 @@ static int btrfs_set_page_dirty(struct page *page) | |||
7206 | 7210 | ||
7207 | static int btrfs_permission(struct inode *inode, int mask) | 7211 | static int btrfs_permission(struct inode *inode, int mask) |
7208 | { | 7212 | { |
7213 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
7214 | |||
7215 | if (btrfs_root_readonly(root) && (mask & MAY_WRITE)) | ||
7216 | return -EROFS; | ||
7209 | if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) | 7217 | if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) |
7210 | return -EACCES; | 7218 | return -EACCES; |
7211 | return generic_permission(inode, mask, btrfs_check_acl); | 7219 | return generic_permission(inode, mask, btrfs_check_acl); |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 02554e19d974..f066ccb5dddf 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: |
@@ -957,7 +963,8 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
957 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 963 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
958 | 964 | ||
959 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, | 965 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
960 | vol_args->fd, subvol, NULL); | 966 | vol_args->fd, subvol, |
967 | NULL, false); | ||
961 | 968 | ||
962 | kfree(vol_args); | 969 | kfree(vol_args); |
963 | return ret; | 970 | return ret; |
@@ -970,22 +977,27 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, | |||
970 | int ret; | 977 | int ret; |
971 | u64 transid = 0; | 978 | u64 transid = 0; |
972 | u64 *ptr = NULL; | 979 | u64 *ptr = NULL; |
980 | bool readonly = false; | ||
973 | 981 | ||
974 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 982 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
975 | if (IS_ERR(vol_args)) | 983 | if (IS_ERR(vol_args)) |
976 | return PTR_ERR(vol_args); | 984 | return PTR_ERR(vol_args); |
977 | vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; | 985 | vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; |
978 | 986 | ||
979 | if (vol_args->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) { | 987 | if (vol_args->flags & |
980 | ret = -EINVAL; | 988 | ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY)) { |
989 | ret = -EOPNOTSUPP; | ||
981 | goto out; | 990 | goto out; |
982 | } | 991 | } |
983 | 992 | ||
984 | if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC) | 993 | if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC) |
985 | ptr = &transid; | 994 | ptr = &transid; |
995 | if (vol_args->flags & BTRFS_SUBVOL_RDONLY) | ||
996 | readonly = true; | ||
986 | 997 | ||
987 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, | 998 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
988 | vol_args->fd, subvol, ptr); | 999 | vol_args->fd, subvol, |
1000 | ptr, readonly); | ||
989 | 1001 | ||
990 | if (ret == 0 && ptr && | 1002 | if (ret == 0 && ptr && |
991 | copy_to_user(arg + | 1003 | copy_to_user(arg + |
@@ -1505,6 +1517,9 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) | |||
1505 | struct btrfs_ioctl_defrag_range_args *range; | 1517 | struct btrfs_ioctl_defrag_range_args *range; |
1506 | int ret; | 1518 | int ret; |
1507 | 1519 | ||
1520 | if (btrfs_root_readonly(root)) | ||
1521 | return -EROFS; | ||
1522 | |||
1508 | ret = mnt_want_write(file->f_path.mnt); | 1523 | ret = mnt_want_write(file->f_path.mnt); |
1509 | if (ret) | 1524 | if (ret) |
1510 | return ret; | 1525 | return ret; |
@@ -1633,6 +1648,9 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1633 | if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) | 1648 | if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) |
1634 | return -EINVAL; | 1649 | return -EINVAL; |
1635 | 1650 | ||
1651 | if (btrfs_root_readonly(root)) | ||
1652 | return -EROFS; | ||
1653 | |||
1636 | ret = mnt_want_write(file->f_path.mnt); | 1654 | ret = mnt_want_write(file->f_path.mnt); |
1637 | if (ret) | 1655 | if (ret) |
1638 | return ret; | 1656 | return ret; |
@@ -1954,6 +1972,10 @@ static long btrfs_ioctl_trans_start(struct file *file) | |||
1954 | if (file->private_data) | 1972 | if (file->private_data) |
1955 | goto out; | 1973 | goto out; |
1956 | 1974 | ||
1975 | ret = -EROFS; | ||
1976 | if (btrfs_root_readonly(root)) | ||
1977 | goto out; | ||
1978 | |||
1957 | ret = mnt_want_write(file->f_path.mnt); | 1979 | ret = mnt_want_write(file->f_path.mnt); |
1958 | if (ret) | 1980 | if (ret) |
1959 | goto out; | 1981 | goto out; |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index c344d12c646b..52ae489974be 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 { |
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 |