Skip to content

Commit 72fd032

Browse files
liewegaschrismason-xx
authored andcommitted
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>
1 parent 4620459 commit 72fd032

File tree

2 files changed

+93
-25
lines changed

2 files changed

+93
-25
lines changed

fs/btrfs/ioctl.c

Lines changed: 83 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
224224

225225
static noinline int create_subvol(struct btrfs_root *root,
226226
struct dentry *dentry,
227-
char *name, int namelen)
227+
char *name, int namelen,
228+
u64 *async_transid)
228229
{
229230
struct btrfs_trans_handle *trans;
230231
struct btrfs_key key;
@@ -338,13 +339,19 @@ static noinline int create_subvol(struct btrfs_root *root,
338339

339340
d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
340341
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+
}
342348
if (err && !ret)
343349
ret = err;
344350
return ret;
345351
}
346352

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)
348355
{
349356
struct inode *inode;
350357
struct btrfs_pending_snapshot *pending_snapshot;
@@ -373,7 +380,14 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry)
373380

374381
list_add(&pending_snapshot->list,
375382
&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+
}
377391
BUG_ON(ret);
378392

379393
ret = pending_snapshot->error;
@@ -412,7 +426,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
412426
*/
413427
static noinline int btrfs_mksubvol(struct path *parent,
414428
char *name, int namelen,
415-
struct btrfs_root *snap_src)
429+
struct btrfs_root *snap_src,
430+
u64 *async_transid)
416431
{
417432
struct inode *dir = parent->dentry->d_inode;
418433
struct dentry *dentry;
@@ -443,10 +458,11 @@ static noinline int btrfs_mksubvol(struct path *parent,
443458
goto out_up_read;
444459

445460
if (snap_src) {
446-
error = create_snapshot(snap_src, dentry);
461+
error = create_snapshot(snap_src, dentry,
462+
name, namelen, async_transid);
447463
} else {
448464
error = create_subvol(BTRFS_I(dir)->root, dentry,
449-
name, namelen);
465+
name, namelen, async_transid);
450466
}
451467
if (!error)
452468
fsnotify_mkdir(dir, dentry);
@@ -799,35 +815,32 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
799815
return ret;
800816
}
801817

802-
static noinline int btrfs_ioctl_snap_create(struct file *file,
803-
void __user *arg, int subvol)
818+
static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
819+
char *name,
820+
unsigned long fd,
821+
int subvol,
822+
u64 *transid)
804823
{
805824
struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
806-
struct btrfs_ioctl_vol_args *vol_args;
807825
struct file *src_file;
808826
int namelen;
809827
int ret = 0;
810828

811829
if (root->fs_info->sb->s_flags & MS_RDONLY)
812830
return -EROFS;
813831

814-
vol_args = memdup_user(arg, sizeof(*vol_args));
815-
if (IS_ERR(vol_args))
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, '/')) {
832+
namelen = strlen(name);
833+
if (strchr(name, '/')) {
821834
ret = -EINVAL;
822835
goto out;
823836
}
824837

825838
if (subvol) {
826-
ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen,
827-
NULL);
839+
ret = btrfs_mksubvol(&file->f_path, name, namelen,
840+
NULL, transid);
828841
} else {
829842
struct inode *src_inode;
830-
src_file = fget(vol_args->fd);
843+
src_file = fget(fd);
831844
if (!src_file) {
832845
ret = -EINVAL;
833846
goto out;
@@ -841,12 +854,56 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
841854
fput(src_file);
842855
goto out;
843856
}
844-
ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen,
845-
BTRFS_I(src_inode)->root);
857+
ret = btrfs_mksubvol(&file->f_path, name, namelen,
858+
BTRFS_I(src_inode)->root,
859+
transid);
846860
fput(src_file);
847861
}
848862
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+
849904
kfree(vol_args);
905+
kfree(async_vol_args);
906+
850907
return ret;
851908
}
852909

@@ -2072,9 +2129,11 @@ long btrfs_ioctl(struct file *file, unsigned int
20722129
case FS_IOC_GETVERSION:
20732130
return btrfs_ioctl_getversion(file, argp);
20742131
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);
20762135
case BTRFS_IOC_SUBVOL_CREATE:
2077-
return btrfs_ioctl_snap_create(file, argp, 1);
2136+
return btrfs_ioctl_snap_create(file, argp, 1, 0);
20782137
case BTRFS_IOC_SNAP_DESTROY:
20792138
return btrfs_ioctl_snap_destroy(file, argp);
20802139
case BTRFS_IOC_DEFAULT_SUBVOL:

fs/btrfs/ioctl.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,21 @@
2222

2323
#define BTRFS_IOCTL_MAGIC 0x94
2424
#define BTRFS_VOL_NAME_MAX 255
25-
#define BTRFS_PATH_NAME_MAX 4087
2625

2726
/* this should be 4k */
27+
#define BTRFS_PATH_NAME_MAX 4087
2828
struct btrfs_ioctl_vol_args {
2929
__s64 fd;
3030
char name[BTRFS_PATH_NAME_MAX + 1];
3131
};
3232

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+
3340
#define BTRFS_INO_LOOKUP_PATH_MAX 4080
3441
struct btrfs_ioctl_ino_lookup_args {
3542
__u64 treeid;
@@ -180,4 +187,6 @@ struct btrfs_ioctl_space_args {
180187
struct btrfs_ioctl_space_args)
181188
#define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64)
182189
#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)
183192
#endif

0 commit comments

Comments
 (0)