All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/6] ovl: concurrent copy up
@ 2017-01-17  4:34 Amir Goldstein
  2017-01-17  4:34 ` [PATCH v4 1/6] vfs: create vfs helper vfs_tmpfile() Amir Goldstein
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Amir Goldstein @ 2017-01-17  4:34 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Al Viro, linux-unionfs, linux-fsdevel

Miklos,

Here is v4. Only change from v3 is in patch 1.
Since I only saw your replies for patches 1,2,6,
I assume the the rest are ok?

Patches 1 is the vfs_tmpfile() helper.

Patches 2-4 implement copy up of regular file with the helper.

Patch 5 is the waitqueue patch you sent me.

Patch 6 puts the pieces together for concurrent copy up.

Tested concurrent copy up with this simple test:
$ touch /lower/{empty,4g}
$ truncate -s 4g /lower/4g
$ touch /mnt/4g &  # takes a while
$ touch /mnt/empty # exits immediately
$ touch /mnt/4g    # blocks until %1 completes and can be interrupted

Tested vfs_tmpfile() with generic/004 and generic/389.

Tested with the new overlay/021 which exercises concurrent copy up
using 8 processes on 4 directories and 4K files.

v4:
- Remove redundant dir argument from vfs_tmpfile()

v3:
- Move more code into vfs_tmpfile() helper
- Address Miklos' review comments on patch 6

v2:
- Withdraw the workdir = upperdir hack

v1:
- Initial version

Amir Goldstein (6):
  vfs: create vfs helper vfs_tmpfile()
  ovl: check if upperdir fs supports O_TMPFILE
  ovl: rearrange code in ovl_copy_up_locked()
  ovl: copy up regular file using O_TMPFILE
  ovl: introduce copy up waitqueue
  ovl: concurrent copy up of regular files

 fs/namei.c               | 68 +++++++++++++++++++++++--------------
 fs/overlayfs/copy_up.c   | 88 +++++++++++++++++++++++++++++++++++-------------
 fs/overlayfs/overlayfs.h | 11 ++++++
 fs/overlayfs/ovl_entry.h |  3 ++
 fs/overlayfs/super.c     | 11 ++++++
 fs/overlayfs/util.c      | 30 +++++++++++++++++
 include/linux/fs.h       |  3 ++
 7 files changed, 165 insertions(+), 49 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v4 1/6] vfs: create vfs helper vfs_tmpfile()
  2017-01-17  4:34 [PATCH v4 0/6] ovl: concurrent copy up Amir Goldstein
@ 2017-01-17  4:34 ` Amir Goldstein
  2017-03-06 14:59   ` J. R. Okajima
  2017-01-17  4:34 ` [PATCH v4 2/6] ovl: check if upperdir fs supports O_TMPFILE Amir Goldstein
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Amir Goldstein @ 2017-01-17  4:34 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Al Viro, linux-unionfs, linux-fsdevel

Factor out some common vfs bits from do_tmpfile()
to be used by overlayfs for concurrent copy up.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
cc: Al Viro <viro@zeniv.linux.org.uk>
---
 fs/namei.c         | 68 ++++++++++++++++++++++++++++++++++--------------------
 include/linux/fs.h |  3 +++
 2 files changed, 46 insertions(+), 25 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index ad74877..7d87699 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3353,13 +3353,50 @@ static int do_last(struct nameidata *nd,
 	return error;
 }
 
+struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, int open_flag)
+{
+	static const struct qstr name = QSTR_INIT("/", 1);
+	struct dentry *child = NULL;
+	struct inode *dir = dentry->d_inode;
+	struct inode *inode;
+	int error;
+
+	/* we want directory to be writable */
+	error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+	if (error)
+		goto out_err;
+	error = -EOPNOTSUPP;
+	if (!dir->i_op->tmpfile)
+		goto out_err;
+	error = -ENOMEM;
+	child = d_alloc(dentry, &name);
+	if (unlikely(!child))
+		goto out_err;
+	error = dir->i_op->tmpfile(dir, child, mode);
+	if (error)
+		goto out_err;
+	error = -ENOENT;
+	inode = child->d_inode;
+	if (unlikely(!inode))
+		goto out_err;
+	if (!(open_flag & O_EXCL)) {
+		spin_lock(&inode->i_lock);
+		inode->i_state |= I_LINKABLE;
+		spin_unlock(&inode->i_lock);
+	}
+	return child;
+
+out_err:
+	dput(child);
+	return ERR_PTR(error);
+}
+EXPORT_SYMBOL(vfs_tmpfile);
+
 static int do_tmpfile(struct nameidata *nd, unsigned flags,
 		const struct open_flags *op,
 		struct file *file, int *opened)
 {
-	static const struct qstr name = QSTR_INIT("/", 1);
 	struct dentry *child;
-	struct inode *dir;
 	struct path path;
 	int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path);
 	if (unlikely(error))
@@ -3367,25 +3404,12 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
 	error = mnt_want_write(path.mnt);
 	if (unlikely(error))
 		goto out;
-	dir = path.dentry->d_inode;
-	/* we want directory to be writable */
-	error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
-	if (error)
-		goto out2;
-	if (!dir->i_op->tmpfile) {
-		error = -EOPNOTSUPP;
-		goto out2;
-	}
-	child = d_alloc(path.dentry, &name);
-	if (unlikely(!child)) {
-		error = -ENOMEM;
+	child = vfs_tmpfile(path.dentry, op->mode, op->open_flag);
+	error = PTR_ERR(child);
+	if (unlikely(IS_ERR(child)))
 		goto out2;
-	}
 	dput(path.dentry);
 	path.dentry = child;
-	error = dir->i_op->tmpfile(dir, child, op->mode);
-	if (error)
-		goto out2;
 	audit_inode(nd->name, child, 0);
 	/* Don't check for other permissions, the inode was just created */
 	error = may_open(&path, 0, op->open_flag);
@@ -3396,14 +3420,8 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
 	if (error)
 		goto out2;
 	error = open_check_o_direct(file);
-	if (error) {
+	if (error)
 		fput(file);
-	} else if (!(op->open_flag & O_EXCL)) {
-		struct inode *inode = file_inode(file);
-		spin_lock(&inode->i_lock);
-		inode->i_state |= I_LINKABLE;
-		spin_unlock(&inode->i_lock);
-	}
 out2:
 	mnt_drop_write(path.mnt);
 out:
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2ba0743..4a7f3cc 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1561,6 +1561,9 @@ extern int vfs_unlink(struct inode *, struct dentry *, struct inode **);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int);
 extern int vfs_whiteout(struct inode *, struct dentry *);
 
+extern struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode,
+				  int open_flag);
+
 /*
  * VFS file helper functions.
  */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 2/6] ovl: check if upperdir fs supports O_TMPFILE
  2017-01-17  4:34 [PATCH v4 0/6] ovl: concurrent copy up Amir Goldstein
  2017-01-17  4:34 ` [PATCH v4 1/6] vfs: create vfs helper vfs_tmpfile() Amir Goldstein
@ 2017-01-17  4:34 ` Amir Goldstein
  2017-01-17  4:34 ` [PATCH v4 3/6] ovl: rearrange code in ovl_copy_up_locked() Amir Goldstein
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2017-01-17  4:34 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Al Viro, linux-unionfs, linux-fsdevel

This is needed for choosing between concurrent copyup
using O_TMPFILE and legacy copyup using workdir+rename.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/overlayfs/overlayfs.h |  9 +++++++++
 fs/overlayfs/ovl_entry.h |  1 +
 fs/overlayfs/super.c     | 10 ++++++++++
 3 files changed, 20 insertions(+)

diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 8af450b..3822a90 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -127,6 +127,15 @@ static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry)
 	return err;
 }
 
+static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode)
+{
+	struct dentry *ret = vfs_tmpfile(dentry, mode, 0);
+	int err = IS_ERR(ret) ? PTR_ERR(ret) : 0;
+
+	pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err);
+	return ret;
+}
+
 static inline struct inode *ovl_inode_real(struct inode *inode, bool *is_upper)
 {
 	unsigned long x = (unsigned long) READ_ONCE(inode->i_private);
diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
index d14bca1..65f24000 100644
--- a/fs/overlayfs/ovl_entry.h
+++ b/fs/overlayfs/ovl_entry.h
@@ -27,6 +27,7 @@ struct ovl_fs {
 	struct ovl_config config;
 	/* creds of process who forced instantiation of super block */
 	const struct cred *creator_cred;
+	bool tmpfile;
 };
 
 /* private information held for every overlayfs dentry */
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 20f48ab..ff05065 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -825,6 +825,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 		 * creation of workdir in previous step.
 		 */
 		if (ufs->workdir) {
+			struct dentry *temp;
+
 			err = ovl_check_d_type_supported(&workpath);
 			if (err < 0)
 				goto out_put_workdir;
@@ -836,6 +838,14 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 			 */
 			if (!err)
 				pr_warn("overlayfs: upper fs needs to support d_type.\n");
+
+			/* Check if upper/work fs supports O_TMPFILE */
+			temp = ovl_do_tmpfile(ufs->workdir, S_IFREG | 0);
+			ufs->tmpfile = !IS_ERR(temp);
+			if (ufs->tmpfile)
+				dput(temp);
+			else
+				pr_warn("overlayfs: upper fs does not support tmpfile.\n");
 		}
 	}
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 3/6] ovl: rearrange code in ovl_copy_up_locked()
  2017-01-17  4:34 [PATCH v4 0/6] ovl: concurrent copy up Amir Goldstein
  2017-01-17  4:34 ` [PATCH v4 1/6] vfs: create vfs helper vfs_tmpfile() Amir Goldstein
  2017-01-17  4:34 ` [PATCH v4 2/6] ovl: check if upperdir fs supports O_TMPFILE Amir Goldstein
@ 2017-01-17  4:34 ` Amir Goldstein
  2017-01-17  4:34 ` [PATCH v4 4/6] ovl: copy up regular file using O_TMPFILE Amir Goldstein
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2017-01-17  4:34 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Al Viro, linux-unionfs, linux-fsdevel

As preparation to implementing copy up with O_TMPFILE,
name the variable for dentry before final rename 'temp' and
assign it to 'newdentry' only after rename.

Also lookup upper dentry before looking up temp dentry and
move ovl_set_timestamps() into ovl_copy_up_locked(), because
that is going to be more convenient for upcoming change.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/overlayfs/copy_up.c | 49 +++++++++++++++++++++++++------------------------
 1 file changed, 25 insertions(+), 24 deletions(-)

diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index f57043d..01e3327 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -232,12 +232,14 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
 
 static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 			      struct dentry *dentry, struct path *lowerpath,
-			      struct kstat *stat, const char *link)
+			      struct kstat *stat, const char *link,
+			      struct kstat *pstat)
 {
 	struct inode *wdir = workdir->d_inode;
 	struct inode *udir = upperdir->d_inode;
 	struct dentry *newdentry = NULL;
 	struct dentry *upper = NULL;
+	struct dentry *temp = NULL;
 	int err;
 	const struct cred *old_creds = NULL;
 	struct cred *new_creds = NULL;
@@ -248,25 +250,25 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 		.link = link
 	};
 
-	newdentry = ovl_lookup_temp(workdir, dentry);
-	err = PTR_ERR(newdentry);
-	if (IS_ERR(newdentry))
-		goto out;
-
 	upper = lookup_one_len(dentry->d_name.name, upperdir,
 			       dentry->d_name.len);
 	err = PTR_ERR(upper);
 	if (IS_ERR(upper))
-		goto out1;
+		goto out;
 
 	err = security_inode_copy_up(dentry, &new_creds);
 	if (err < 0)
-		goto out2;
+		goto out1;
 
 	if (new_creds)
 		old_creds = override_creds(new_creds);
 
-	err = ovl_create_real(wdir, newdentry, &cattr, NULL, true);
+	temp = ovl_lookup_temp(workdir, dentry);
+	err = PTR_ERR(temp);
+	if (IS_ERR(temp))
+		goto out1;
+
+	err = ovl_create_real(wdir, temp, &cattr, NULL, true);
 
 	if (new_creds) {
 		revert_creds(old_creds);
@@ -281,39 +283,42 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 
 		ovl_path_upper(dentry, &upperpath);
 		BUG_ON(upperpath.dentry != NULL);
-		upperpath.dentry = newdentry;
+		upperpath.dentry = temp;
 
 		err = ovl_copy_up_data(lowerpath, &upperpath, stat->size);
 		if (err)
 			goto out_cleanup;
 	}
 
-	err = ovl_copy_xattr(lowerpath->dentry, newdentry);
+	err = ovl_copy_xattr(lowerpath->dentry, temp);
 	if (err)
 		goto out_cleanup;
 
-	inode_lock(newdentry->d_inode);
-	err = ovl_set_attr(newdentry, stat);
-	inode_unlock(newdentry->d_inode);
+	inode_lock(temp->d_inode);
+	err = ovl_set_attr(temp, stat);
+	inode_unlock(temp->d_inode);
 	if (err)
 		goto out_cleanup;
 
-	err = ovl_do_rename(wdir, newdentry, udir, upper, 0);
+	err = ovl_do_rename(wdir, temp, udir, upper, 0);
 	if (err)
 		goto out_cleanup;
 
+	newdentry = dget(temp);
 	ovl_dentry_update(dentry, newdentry);
 	ovl_inode_update(d_inode(dentry), d_inode(newdentry));
-	newdentry = NULL;
+
+	/* Restore timestamps on parent (best effort) */
+	ovl_set_timestamps(upperdir, pstat);
 out2:
-	dput(upper);
+	dput(temp);
 out1:
-	dput(newdentry);
+	dput(upper);
 out:
 	return err;
 
 out_cleanup:
-	ovl_cleanup(wdir, newdentry);
+	ovl_cleanup(wdir, temp);
 	goto out2;
 }
 
@@ -368,11 +373,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
 	}
 
 	err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath,
-				 stat, link);
-	if (!err) {
-		/* Restore timestamps on parent (best effort) */
-		ovl_set_timestamps(upperdir, &pstat);
-	}
+				 stat, link, &pstat);
 out_unlock:
 	unlock_rename(workdir, upperdir);
 	do_delayed_call(&done);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 4/6] ovl: copy up regular file using O_TMPFILE
  2017-01-17  4:34 [PATCH v4 0/6] ovl: concurrent copy up Amir Goldstein
                   ` (2 preceding siblings ...)
  2017-01-17  4:34 ` [PATCH v4 3/6] ovl: rearrange code in ovl_copy_up_locked() Amir Goldstein
@ 2017-01-17  4:34 ` Amir Goldstein
  2017-01-17  4:34 ` [PATCH v4 5/6] ovl: introduce copy up waitqueue Amir Goldstein
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2017-01-17  4:34 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Al Viro, linux-unionfs, linux-fsdevel

In preparation for concurrent copy up, implement copy up
of regular file as O_TMPFILE that is linked to upperdir
instead of a file in workdir that is moved to upperdir.

Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/overlayfs/copy_up.c | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 01e3327..6e39e90 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -20,6 +20,7 @@
 #include <linux/fdtable.h>
 #include <linux/ratelimit.h>
 #include "overlayfs.h"
+#include "ovl_entry.h"
 
 #define OVL_COPY_UP_CHUNK_SIZE (1 << 20)
 
@@ -233,7 +234,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
 static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 			      struct dentry *dentry, struct path *lowerpath,
 			      struct kstat *stat, const char *link,
-			      struct kstat *pstat)
+			      struct kstat *pstat, bool tmpfile)
 {
 	struct inode *wdir = workdir->d_inode;
 	struct inode *udir = upperdir->d_inode;
@@ -263,12 +264,17 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 	if (new_creds)
 		old_creds = override_creds(new_creds);
 
-	temp = ovl_lookup_temp(workdir, dentry);
+	if (tmpfile)
+		temp = ovl_do_tmpfile(upperdir, stat->mode);
+	else
+		temp = ovl_lookup_temp(workdir, dentry);
 	err = PTR_ERR(temp);
 	if (IS_ERR(temp))
 		goto out1;
 
-	err = ovl_create_real(wdir, temp, &cattr, NULL, true);
+	err = 0;
+	if (!tmpfile)
+		err = ovl_create_real(wdir, temp, &cattr, NULL, true);
 
 	if (new_creds) {
 		revert_creds(old_creds);
@@ -300,11 +306,14 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 	if (err)
 		goto out_cleanup;
 
-	err = ovl_do_rename(wdir, temp, udir, upper, 0);
+	if (tmpfile)
+		err = ovl_do_link(temp, udir, upper, true);
+	else
+		err = ovl_do_rename(wdir, temp, udir, upper, 0);
 	if (err)
 		goto out_cleanup;
 
-	newdentry = dget(temp);
+	newdentry = dget(tmpfile ? upper : temp);
 	ovl_dentry_update(dentry, newdentry);
 	ovl_inode_update(d_inode(dentry), d_inode(newdentry));
 
@@ -318,7 +327,8 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 	return err;
 
 out_cleanup:
-	ovl_cleanup(wdir, temp);
+	if (!tmpfile)
+		ovl_cleanup(wdir, temp);
 	goto out2;
 }
 
@@ -342,6 +352,9 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
 	struct dentry *lowerdentry = lowerpath->dentry;
 	struct dentry *upperdir;
 	const char *link = NULL;
+	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
+	/* Should we copyup with O_TMPFILE or with workdir? */
+	bool tmpfile = S_ISREG(stat->mode) && ofs->tmpfile;
 
 	if (WARN_ON(!workdir))
 		return -EROFS;
@@ -373,7 +386,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
 	}
 
 	err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath,
-				 stat, link, &pstat);
+				 stat, link, &pstat, tmpfile);
 out_unlock:
 	unlock_rename(workdir, upperdir);
 	do_delayed_call(&done);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 5/6] ovl: introduce copy up waitqueue
  2017-01-17  4:34 [PATCH v4 0/6] ovl: concurrent copy up Amir Goldstein
                   ` (3 preceding siblings ...)
  2017-01-17  4:34 ` [PATCH v4 4/6] ovl: copy up regular file using O_TMPFILE Amir Goldstein
@ 2017-01-17  4:34 ` Amir Goldstein
  2017-01-17  4:34 ` [PATCH v4 6/6] ovl: concurrent copy up of regular files Amir Goldstein
  2017-01-30 16:18 ` [PATCH v4 0/6] ovl: concurrent copy up Miklos Szeredi
  6 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2017-01-17  4:34 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Al Viro, linux-unionfs, linux-fsdevel

The overlay sb 'copyup_wq' and overlay inode 'copying' condition
variable are about to replace the upper sb rename_lock, as finer
grained synchronization objects for concurrent copy up.

Suggested-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/overlayfs/overlayfs.h |  2 ++
 fs/overlayfs/ovl_entry.h |  2 ++
 fs/overlayfs/super.c     |  1 +
 fs/overlayfs/util.c      | 30 ++++++++++++++++++++++++++++++
 4 files changed, 35 insertions(+)

diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 3822a90..741dc0b 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -178,6 +178,8 @@ void ovl_dentry_version_inc(struct dentry *dentry);
 u64 ovl_dentry_version_get(struct dentry *dentry);
 bool ovl_is_whiteout(struct dentry *dentry);
 struct file *ovl_path_open(struct path *path, int flags);
+int ovl_copy_up_start(struct dentry *dentry);
+void ovl_copy_up_end(struct dentry *dentry);
 
 /* namei.c */
 int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
index 65f24000..59614fa 100644
--- a/fs/overlayfs/ovl_entry.h
+++ b/fs/overlayfs/ovl_entry.h
@@ -28,6 +28,7 @@ struct ovl_fs {
 	/* creds of process who forced instantiation of super block */
 	const struct cred *creator_cred;
 	bool tmpfile;
+	wait_queue_head_t copyup_wq;
 };
 
 /* private information held for every overlayfs dentry */
@@ -39,6 +40,7 @@ struct ovl_entry {
 			u64 version;
 			const char *redirect;
 			bool opaque;
+			bool copying;
 		};
 		struct rcu_head rcu;
 	};
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index ff05065..6792bb7 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -708,6 +708,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 	if (!ufs)
 		goto out;
 
+	init_waitqueue_head(&ufs->copyup_wq);
 	ufs->config.redirect_dir = ovl_redirect_dir_def;
 	err = ovl_parse_opt((char *) data, &ufs->config);
 	if (err)
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 952286f..01157d6 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -263,3 +263,33 @@ struct file *ovl_path_open(struct path *path, int flags)
 {
 	return dentry_open(path, flags | O_NOATIME, current_cred());
 }
+
+int ovl_copy_up_start(struct dentry *dentry)
+{
+	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
+	struct ovl_entry *oe = dentry->d_fsdata;
+	int err;
+
+	spin_lock(&ofs->copyup_wq.lock);
+	err = wait_event_interruptible_locked(ofs->copyup_wq, !oe->copying);
+	if (!err) {
+		if (oe->__upperdentry)
+			err = 1; /* Already copied up */
+		else
+			oe->copying = true;
+	}
+	spin_unlock(&ofs->copyup_wq.lock);
+
+	return err;
+}
+
+void ovl_copy_up_end(struct dentry *dentry)
+{
+	struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
+	struct ovl_entry *oe = dentry->d_fsdata;
+
+	spin_lock(&ofs->copyup_wq.lock);
+	oe->copying = false;
+	wake_up_locked(&ofs->copyup_wq);
+	spin_unlock(&ofs->copyup_wq.lock);
+}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v4 6/6] ovl: concurrent copy up of regular files
  2017-01-17  4:34 [PATCH v4 0/6] ovl: concurrent copy up Amir Goldstein
                   ` (4 preceding siblings ...)
  2017-01-17  4:34 ` [PATCH v4 5/6] ovl: introduce copy up waitqueue Amir Goldstein
@ 2017-01-17  4:34 ` Amir Goldstein
  2017-01-30 16:18 ` [PATCH v4 0/6] ovl: concurrent copy up Miklos Szeredi
  6 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2017-01-17  4:34 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Al Viro, linux-unionfs, linux-fsdevel

Now that copy up of regular file is done using O_TMPFILE,
we don't need to hold rename_lock throughout copy up.

Use the copy up waitqueue to synchronize concurrent copy up
of the same file. Different regular files can be copied up
concurrently.

The upper dir inode_lock is taken instead of rename_lock,
because it is needed for lookup and later for linking the
temp file, but it is released while copying up data.

Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/overlayfs/copy_up.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 6e39e90..a53b1a3 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -291,7 +291,14 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 		BUG_ON(upperpath.dentry != NULL);
 		upperpath.dentry = temp;
 
+		if (tmpfile)
+			inode_unlock(udir);
+
 		err = ovl_copy_up_data(lowerpath, &upperpath, stat->size);
+
+		if (tmpfile)
+			inode_lock_nested(udir, I_MUTEX_PARENT);
+
 		if (err)
 			goto out_cleanup;
 	}
@@ -374,6 +381,24 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
 			return PTR_ERR(link);
 	}
 
+	if (tmpfile) {
+		err = ovl_copy_up_start(dentry);
+		/* err < 0: interrupted, err > 0: raced with another copy-up */
+		if (unlikely(err)) {
+			pr_debug("ovl_copy_up_start(%pd2) = %i\n", dentry, err);
+			if (err > 0)
+				err = 0;
+			goto out_done;
+		}
+
+		inode_lock_nested(upperdir->d_inode, I_MUTEX_PARENT);
+		err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath,
+					 stat, link, &pstat, tmpfile);
+		inode_unlock(upperdir->d_inode);
+		ovl_copy_up_end(dentry);
+		goto out_done;
+	}
+
 	err = -EIO;
 	if (lock_rename(workdir, upperdir) != NULL) {
 		pr_err("overlayfs: failed to lock workdir+upperdir\n");
@@ -389,6 +414,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
 				 stat, link, &pstat, tmpfile);
 out_unlock:
 	unlock_rename(workdir, upperdir);
+out_done:
 	do_delayed_call(&done);
 
 	return err;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 0/6] ovl: concurrent copy up
  2017-01-17  4:34 [PATCH v4 0/6] ovl: concurrent copy up Amir Goldstein
                   ` (5 preceding siblings ...)
  2017-01-17  4:34 ` [PATCH v4 6/6] ovl: concurrent copy up of regular files Amir Goldstein
@ 2017-01-30 16:18 ` Miklos Szeredi
  6 siblings, 0 replies; 10+ messages in thread
From: Miklos Szeredi @ 2017-01-30 16:18 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: Al Viro, linux-unionfs, linux-fsdevel

On Tue, Jan 17, 2017 at 5:34 AM, Amir Goldstein <amir73il@gmail.com> wrote:
> Miklos,
>
> Here is v4. Only change from v3 is in patch 1.
> Since I only saw your replies for patches 1,2,6,
> I assume the the rest are ok?

Yep, pushed to overlayfs-next.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 1/6] vfs: create vfs helper vfs_tmpfile()
  2017-01-17  4:34 ` [PATCH v4 1/6] vfs: create vfs helper vfs_tmpfile() Amir Goldstein
@ 2017-03-06 14:59   ` J. R. Okajima
  2017-03-06 15:29     ` Amir Goldstein
  0 siblings, 1 reply; 10+ messages in thread
From: J. R. Okajima @ 2017-03-06 14:59 UTC (permalink / raw)
  To: Amir Goldstein; +Cc: Miklos Szeredi, Al Viro, linux-unionfs, linux-fsdevel

Amir Goldstein:
> Factor out some common vfs bits from do_tmpfile()
> to be used by overlayfs for concurrent copy up.

Hmm, just to copy-up.
I have no objection this factoring-out, but do you have any specific
reason for overlayfs NOT to support i_op->tmpfile()?

If you try supporting it in the future, then the parameter open_flag may
become a problem. I guess that you will make ovl_tmpfile() (currently
not exist) to call vfs_tmpfile(), and pass dummy 0 as open_flag as
overlayfs copy-up does. But such dummy parameter will make the created
tmpfile un-linkable by a user I am afraid.


J. R. Okajima

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v4 1/6] vfs: create vfs helper vfs_tmpfile()
  2017-03-06 14:59   ` J. R. Okajima
@ 2017-03-06 15:29     ` Amir Goldstein
  0 siblings, 0 replies; 10+ messages in thread
From: Amir Goldstein @ 2017-03-06 15:29 UTC (permalink / raw)
  To: J. R. Okajima; +Cc: Miklos Szeredi, Al Viro, linux-unionfs, linux-fsdevel

On Mon, Mar 6, 2017 at 4:59 PM, J. R. Okajima <hooanon05g@gmail.com> wrote:
> Amir Goldstein:
>> Factor out some common vfs bits from do_tmpfile()
>> to be used by overlayfs for concurrent copy up.
>
> Hmm, just to copy-up.
> I have no objection this factoring-out, but do you have any specific
> reason for overlayfs NOT to support i_op->tmpfile()?

No reason. Just someone has to do the leg work.

>
> If you try supporting it in the future, then the parameter open_flag may
> become a problem. I guess that you will make ovl_tmpfile() (currently
> not exist) to call vfs_tmpfile(), and pass dummy 0 as open_flag as
> overlayfs copy-up does. But such dummy parameter will make the created
> tmpfile un-linkable by a user I am afraid.
>

I don't think that's going to be a problem.
ovl_link() can probably make sure that I_LINKABLE is propagated to upper
inode before calling vfs_link() for a tmpfile.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-03-06 15:29 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-17  4:34 [PATCH v4 0/6] ovl: concurrent copy up Amir Goldstein
2017-01-17  4:34 ` [PATCH v4 1/6] vfs: create vfs helper vfs_tmpfile() Amir Goldstein
2017-03-06 14:59   ` J. R. Okajima
2017-03-06 15:29     ` Amir Goldstein
2017-01-17  4:34 ` [PATCH v4 2/6] ovl: check if upperdir fs supports O_TMPFILE Amir Goldstein
2017-01-17  4:34 ` [PATCH v4 3/6] ovl: rearrange code in ovl_copy_up_locked() Amir Goldstein
2017-01-17  4:34 ` [PATCH v4 4/6] ovl: copy up regular file using O_TMPFILE Amir Goldstein
2017-01-17  4:34 ` [PATCH v4 5/6] ovl: introduce copy up waitqueue Amir Goldstein
2017-01-17  4:34 ` [PATCH v4 6/6] ovl: concurrent copy up of regular files Amir Goldstein
2017-01-30 16:18 ` [PATCH v4 0/6] ovl: concurrent copy up Miklos Szeredi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.