diff options
author | Sage Weil <sage@newdream.net> | 2010-10-29 15:41:32 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-10-29 21:41:57 -0400 |
commit | 72fd032e94240d001b1d22f2c1dfd2592b02e44e (patch) | |
tree | 7671ea5585f79a8cecc9708e869aa37e24eb74de /fs | |
parent | 462045928bda777c86919a396a42991fcf235378 (diff) |
Btrfs: add SNAP_CREATE_ASYNC ioctl
Create a snap without waiting for it to commit to disk. The ioctl is
ordered such that subsequent operations will not be contained by the
created snapshot, and the commit is initiated, but the ioctl does not
wait for the snapshot to commit to disk.
We return the specific transid to userspace so that an application can wait
for this specific snapshot creation to commit via the WAIT_SYNC ioctl.
Signed-off-by: Sage Weil <sage@newdream.net>
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ioctl.c | 107 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 11 |
2 files changed, 93 insertions, 25 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index dc5a19ed07f..e8a26a3aac3 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -224,7 +224,8 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg) | |||
224 | 224 | ||
225 | static noinline int create_subvol(struct btrfs_root *root, | 225 | static noinline int create_subvol(struct btrfs_root *root, |
226 | struct dentry *dentry, | 226 | struct dentry *dentry, |
227 | char *name, int namelen) | 227 | char *name, int namelen, |
228 | u64 *async_transid) | ||
228 | { | 229 | { |
229 | struct btrfs_trans_handle *trans; | 230 | struct btrfs_trans_handle *trans; |
230 | struct btrfs_key key; | 231 | struct btrfs_key key; |
@@ -338,13 +339,19 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
338 | 339 | ||
339 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); | 340 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); |
340 | fail: | 341 | fail: |
341 | err = btrfs_commit_transaction(trans, root); | 342 | if (async_transid) { |
343 | *async_transid = trans->transid; | ||
344 | err = btrfs_commit_transaction_async(trans, root, 1); | ||
345 | } else { | ||
346 | err = btrfs_commit_transaction(trans, root); | ||
347 | } | ||
342 | if (err && !ret) | 348 | if (err && !ret) |
343 | ret = err; | 349 | ret = err; |
344 | return ret; | 350 | return ret; |
345 | } | 351 | } |
346 | 352 | ||
347 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry) | 353 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, |
354 | char *name, int namelen, u64 *async_transid) | ||
348 | { | 355 | { |
349 | struct inode *inode; | 356 | struct inode *inode; |
350 | struct btrfs_pending_snapshot *pending_snapshot; | 357 | struct btrfs_pending_snapshot *pending_snapshot; |
@@ -373,7 +380,14 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry) | |||
373 | 380 | ||
374 | list_add(&pending_snapshot->list, | 381 | list_add(&pending_snapshot->list, |
375 | &trans->transaction->pending_snapshots); | 382 | &trans->transaction->pending_snapshots); |
376 | ret = btrfs_commit_transaction(trans, root->fs_info->extent_root); | 383 | if (async_transid) { |
384 | *async_transid = trans->transid; | ||
385 | ret = btrfs_commit_transaction_async(trans, | ||
386 | root->fs_info->extent_root, 1); | ||
387 | } else { | ||
388 | ret = btrfs_commit_transaction(trans, | ||
389 | root->fs_info->extent_root); | ||
390 | } | ||
377 | BUG_ON(ret); | 391 | BUG_ON(ret); |
378 | 392 | ||
379 | ret = pending_snapshot->error; | 393 | ret = pending_snapshot->error; |
@@ -412,7 +426,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | |||
412 | */ | 426 | */ |
413 | static noinline int btrfs_mksubvol(struct path *parent, | 427 | static noinline int btrfs_mksubvol(struct path *parent, |
414 | char *name, int namelen, | 428 | char *name, int namelen, |
415 | struct btrfs_root *snap_src) | 429 | struct btrfs_root *snap_src, |
430 | u64 *async_transid) | ||
416 | { | 431 | { |
417 | struct inode *dir = parent->dentry->d_inode; | 432 | struct inode *dir = parent->dentry->d_inode; |
418 | struct dentry *dentry; | 433 | struct dentry *dentry; |
@@ -443,10 +458,11 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
443 | goto out_up_read; | 458 | goto out_up_read; |
444 | 459 | ||
445 | if (snap_src) { | 460 | if (snap_src) { |
446 | error = create_snapshot(snap_src, dentry); | 461 | error = create_snapshot(snap_src, dentry, |
462 | name, namelen, async_transid); | ||
447 | } else { | 463 | } else { |
448 | error = create_subvol(BTRFS_I(dir)->root, dentry, | 464 | error = create_subvol(BTRFS_I(dir)->root, dentry, |
449 | name, namelen); | 465 | name, namelen, async_transid); |
450 | } | 466 | } |
451 | if (!error) | 467 | if (!error) |
452 | fsnotify_mkdir(dir, dentry); | 468 | fsnotify_mkdir(dir, dentry); |
@@ -799,11 +815,13 @@ out_unlock: | |||
799 | return ret; | 815 | return ret; |
800 | } | 816 | } |
801 | 817 | ||
802 | static noinline int btrfs_ioctl_snap_create(struct file *file, | 818 | static noinline int btrfs_ioctl_snap_create_transid(struct file *file, |
803 | void __user *arg, int subvol) | 819 | char *name, |
820 | unsigned long fd, | ||
821 | int subvol, | ||
822 | u64 *transid) | ||
804 | { | 823 | { |
805 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | 824 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; |
806 | struct btrfs_ioctl_vol_args *vol_args; | ||
807 | struct file *src_file; | 825 | struct file *src_file; |
808 | int namelen; | 826 | int namelen; |
809 | int ret = 0; | 827 | int ret = 0; |
@@ -811,23 +829,18 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
811 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 829 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
812 | return -EROFS; | 830 | return -EROFS; |
813 | 831 | ||
814 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 832 | namelen = strlen(name); |
815 | if (IS_ERR(vol_args)) | 833 | if (strchr(name, '/')) { |
816 | return PTR_ERR(vol_args); | ||
817 | |||
818 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | ||
819 | namelen = strlen(vol_args->name); | ||
820 | if (strchr(vol_args->name, '/')) { | ||
821 | ret = -EINVAL; | 834 | ret = -EINVAL; |
822 | goto out; | 835 | goto out; |
823 | } | 836 | } |
824 | 837 | ||
825 | if (subvol) { | 838 | if (subvol) { |
826 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, | 839 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
827 | NULL); | 840 | NULL, transid); |
828 | } else { | 841 | } else { |
829 | struct inode *src_inode; | 842 | struct inode *src_inode; |
830 | src_file = fget(vol_args->fd); | 843 | src_file = fget(fd); |
831 | if (!src_file) { | 844 | if (!src_file) { |
832 | ret = -EINVAL; | 845 | ret = -EINVAL; |
833 | goto out; | 846 | goto out; |
@@ -841,12 +854,56 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
841 | fput(src_file); | 854 | fput(src_file); |
842 | goto out; | 855 | goto out; |
843 | } | 856 | } |
844 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, | 857 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
845 | BTRFS_I(src_inode)->root); | 858 | BTRFS_I(src_inode)->root, |
859 | transid); | ||
846 | fput(src_file); | 860 | fput(src_file); |
847 | } | 861 | } |
848 | out: | 862 | out: |
863 | return ret; | ||
864 | } | ||
865 | |||
866 | static noinline int btrfs_ioctl_snap_create(struct file *file, | ||
867 | void __user *arg, int subvol, | ||
868 | int async) | ||
869 | { | ||
870 | struct btrfs_ioctl_vol_args *vol_args = NULL; | ||
871 | struct btrfs_ioctl_async_vol_args *async_vol_args = NULL; | ||
872 | char *name; | ||
873 | u64 fd; | ||
874 | u64 transid = 0; | ||
875 | int ret; | ||
876 | |||
877 | if (async) { | ||
878 | async_vol_args = memdup_user(arg, sizeof(*async_vol_args)); | ||
879 | if (IS_ERR(async_vol_args)) | ||
880 | return PTR_ERR(async_vol_args); | ||
881 | |||
882 | name = async_vol_args->name; | ||
883 | fd = async_vol_args->fd; | ||
884 | async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0'; | ||
885 | } else { | ||
886 | vol_args = memdup_user(arg, sizeof(*vol_args)); | ||
887 | if (IS_ERR(vol_args)) | ||
888 | return PTR_ERR(vol_args); | ||
889 | name = vol_args->name; | ||
890 | fd = vol_args->fd; | ||
891 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | ||
892 | } | ||
893 | |||
894 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | ||
895 | subvol, &transid); | ||
896 | |||
897 | if (!ret && async) { | ||
898 | if (copy_to_user(arg + | ||
899 | offsetof(struct btrfs_ioctl_async_vol_args, | ||
900 | transid), &transid, sizeof(transid))) | ||
901 | return -EFAULT; | ||
902 | } | ||
903 | |||
849 | kfree(vol_args); | 904 | kfree(vol_args); |
905 | kfree(async_vol_args); | ||
906 | |||
850 | return ret; | 907 | return ret; |
851 | } | 908 | } |
852 | 909 | ||
@@ -2072,9 +2129,11 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2072 | case FS_IOC_GETVERSION: | 2129 | case FS_IOC_GETVERSION: |
2073 | return btrfs_ioctl_getversion(file, argp); | 2130 | return btrfs_ioctl_getversion(file, argp); |
2074 | case BTRFS_IOC_SNAP_CREATE: | 2131 | case BTRFS_IOC_SNAP_CREATE: |
2075 | return btrfs_ioctl_snap_create(file, argp, 0); | 2132 | return btrfs_ioctl_snap_create(file, argp, 0, 0); |
2133 | case BTRFS_IOC_SNAP_CREATE_ASYNC: | ||
2134 | return btrfs_ioctl_snap_create(file, argp, 0, 1); | ||
2076 | case BTRFS_IOC_SUBVOL_CREATE: | 2135 | case BTRFS_IOC_SUBVOL_CREATE: |
2077 | return btrfs_ioctl_snap_create(file, argp, 1); | 2136 | return btrfs_ioctl_snap_create(file, argp, 1, 0); |
2078 | case BTRFS_IOC_SNAP_DESTROY: | 2137 | case BTRFS_IOC_SNAP_DESTROY: |
2079 | return btrfs_ioctl_snap_destroy(file, argp); | 2138 | return btrfs_ioctl_snap_destroy(file, argp); |
2080 | case BTRFS_IOC_DEFAULT_SUBVOL: | 2139 | case BTRFS_IOC_DEFAULT_SUBVOL: |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 16e1442523b..17c99ebdf96 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
@@ -22,14 +22,21 @@ | |||
22 | 22 | ||
23 | #define BTRFS_IOCTL_MAGIC 0x94 | 23 | #define BTRFS_IOCTL_MAGIC 0x94 |
24 | #define BTRFS_VOL_NAME_MAX 255 | 24 | #define BTRFS_VOL_NAME_MAX 255 |
25 | #define BTRFS_PATH_NAME_MAX 4087 | ||
26 | 25 | ||
27 | /* this should be 4k */ | 26 | /* this should be 4k */ |
27 | #define BTRFS_PATH_NAME_MAX 4087 | ||
28 | struct btrfs_ioctl_vol_args { | 28 | struct btrfs_ioctl_vol_args { |
29 | __s64 fd; | 29 | __s64 fd; |
30 | char name[BTRFS_PATH_NAME_MAX + 1]; | 30 | char name[BTRFS_PATH_NAME_MAX + 1]; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | #define BTRFS_SNAPSHOT_NAME_MAX 4079 | ||
34 | struct btrfs_ioctl_async_vol_args { | ||
35 | __s64 fd; | ||
36 | __u64 transid; | ||
37 | char name[BTRFS_SNAPSHOT_NAME_MAX + 1]; | ||
38 | }; | ||
39 | |||
33 | #define BTRFS_INO_LOOKUP_PATH_MAX 4080 | 40 | #define BTRFS_INO_LOOKUP_PATH_MAX 4080 |
34 | struct btrfs_ioctl_ino_lookup_args { | 41 | struct btrfs_ioctl_ino_lookup_args { |
35 | __u64 treeid; | 42 | __u64 treeid; |
@@ -180,4 +187,6 @@ struct btrfs_ioctl_space_args { | |||
180 | struct btrfs_ioctl_space_args) | 187 | struct btrfs_ioctl_space_args) |
181 | #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) | 188 | #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) |
182 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) | 189 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) |
190 | #define BTRFS_IOC_SNAP_CREATE_ASYNC _IOW(BTRFS_IOCTL_MAGIC, 23, \ | ||
191 | struct btrfs_ioctl_async_vol_args) | ||
183 | #endif | 192 | #endif |