diff mbox

[zesty,1/2] aufs: for v4.5, use vfs_clone_file_range() in copy-up

Message ID 20170814124432.19537-2-seth.forshee@canonical.com
State New
Headers show

Commit Message

Seth Forshee Aug. 14, 2017, 12:44 p.m. UTC
From: "J. R. Okajima" <hooanon05g@gmail.com>

BugLink: http://bugs.launchpad.net/bugs/1709749

In mainline, ioctl(FICLONE) is introduced by the commit
	04b38d6 2015-12-07 vfs: pull btrfs clone API to vfs layer
so are vfs_clone_file_ranage() and f_op->clone_file_ranage().
Compared to copy_file_range(2), cloning doesn't return with the partial
success. Using this method in aufs copy-up, the speed will be improved.

But unfortunately this method is supported by nfs4.2, btrfs and cifs
only (currently). Additionally, linux nfs server 4.2 implementation
simply calls vfs_clone_file_ranage(), which means if the backend fs
doesn't support this operation, it returns EOPNOTSUPP.

So the benefit is rather limited, but it must be a good thing.

Signed-off-by: J. R. Okajima <hooanon05g@gmail.com>
(backported from commit b4d3dcc92a13d53952fe6e9a640201ef87475302
 https://github.com/sfjro/aufs4-standalone.git)
[saf: Resolved conflicts based primarily on resolution found in
 fd18affa818115edad7e1b7472f26ac4d73e73a1]
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
 fs/aufs/cpup.c  | 25 ++++++++++++++++++++++---
 fs/aufs/vfsub.h | 16 ++++++++++++++++
 2 files changed, 38 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/fs/aufs/cpup.c b/fs/aufs/cpup.c
index 7112866b30ba..48e4d8511553 100644
--- a/fs/aufs/cpup.c
+++ b/fs/aufs/cpup.c
@@ -393,7 +393,7 @@  static int au_cp_regular(struct au_cp_generic *cpg)
 			.label = &&out_src
 		}
 	};
-	struct super_block *sb;
+	struct super_block *sb, *h_src_sb;
 	struct inode *h_src_inode;
 	struct task_struct *tsk = current;
 
@@ -411,9 +411,28 @@  static int au_cp_regular(struct au_cp_generic *cpg)
 
 	/* try stopping to update while we copyup */
 	h_src_inode = d_inode(file[SRC].dentry);
-	if (!au_test_nfs(h_src_inode->i_sb))
+	h_src_sb = h_src_inode->i_sb;
+	if (!au_test_nfs(h_src_sb))
 		IMustLock(h_src_inode);
-	err = au_copy_file(file[DST].file, file[SRC].file, cpg->len);
+
+	if (h_src_sb != file_inode(file[DST].file)->i_sb
+	    || !file[DST].file->f_op->clone_file_range)
+		err = au_copy_file(file[DST].file, file[SRC].file, cpg->len);
+	else {
+		if (!au_test_nfs(h_src_sb)) {
+			inode_unlock(h_src_inode);
+			err = vfsub_clone_file_range(file[SRC].file,
+						     file[DST].file, cpg->len);
+			inode_lock(h_src_inode);
+		} else
+			err = vfsub_clone_file_range(file[SRC].file,
+						     file[DST].file, cpg->len);
+		if (unlikely(err == -EOPNOTSUPP && au_test_nfs(h_src_sb)))
+			/* the backend fs on NFS may not support cloning */
+			err = au_copy_file(file[DST].file, file[SRC].file,
+					   cpg->len);
+		AuTraceErr(err);
+	}
 
 	/* i wonder if we had O_NO_DELAY_FPUT flag */
 	if (tsk->flags & PF_KTHREAD)
diff --git a/fs/aufs/vfsub.h b/fs/aufs/vfsub.h
index 8fae3d491ddf..71d2bc47d5c9 100644
--- a/fs/aufs/vfsub.h
+++ b/fs/aufs/vfsub.h
@@ -266,6 +266,22 @@  int vfsub_trunc(struct path *h_path, loff_t length, unsigned int attr,
 		struct file *h_file);
 int vfsub_fsync(struct file *file, struct path *path, int datasync);
 
+/*
+ * re-use branch fs's ioctl(FICLONE) while aufs itself doesn't support such
+ * ioctl.
+ */
+static inline int vfsub_clone_file_range(struct file *src, struct file *dst,
+					 u64 len)
+{
+	int err;
+
+	lockdep_off();
+	err = vfs_clone_file_range(src, 0, dst, 0, len);
+	lockdep_on();
+
+	return err;
+}
+
 /* ---------------------------------------------------------------------- */
 
 static inline loff_t vfsub_llseek(struct file *file, loff_t offset, int origin)