aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2010-10-29 15:41:32 -0400
committerChris Mason <chris.mason@oracle.com>2010-10-29 21:41:57 -0400
commit72fd032e94240d001b1d22f2c1dfd2592b02e44e (patch)
tree7671ea5585f79a8cecc9708e869aa37e24eb74de /fs
parent462045928bda777c86919a396a42991fcf235378 (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.c107
-rw-r--r--fs/btrfs/ioctl.h11
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
225static noinline int create_subvol(struct btrfs_root *root, 225static 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));
340fail: 341fail:
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
347static int create_snapshot(struct btrfs_root *root, struct dentry *dentry) 353static 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 */
413static noinline int btrfs_mksubvol(struct path *parent, 427static 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
802static noinline int btrfs_ioctl_snap_create(struct file *file, 818static 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 }
848out: 862out:
863 return ret;
864}
865
866static 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
28struct btrfs_ioctl_vol_args { 28struct 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
34struct 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
34struct btrfs_ioctl_ino_lookup_args { 41struct 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