linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls
@ 2012-09-07 14:18 Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 01/20] vfs: add a retry_estale helper function to handle retries on ESTALE Jeff Layton
                   ` (19 more replies)
  0 siblings, 20 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

This patchset is a respin of the one I sent on August 8th. The main
reason is to respin this series on top of my getname/putname overhaul,
which simplifies the set greatly and doesn't require so many getname
callers.

This series depends on the "getname" series that I sent earlier today.

This set (and the prerequiste patches) are also available via the
"estale" branch of my git tree:

    git://git.samba.org/jlayton/linux.git estale

I'd like to see this go in for 3.7 if at all possible.

The original cover letter text follows:

ESTALE errors are a source of pain for many users, primarily those who
are doing work on NFS. When userspace provides a path to a syscall, then
there's really little excuse for returning ESTALE. If userspace gave us
a path that we had to lookup in order to do the call, then it's not
particularly helpful to return ESTALE just because that path went stale
before we could do the actual operation.

We can and should do better here. The kernel should instead catch that
error and retry the lookup and call, while forcing a revalidation of all
dentries involved.

Unfortunately fixing this requires touching the syscalls themselves, or
at least their immediate helper functions. Not all syscalls can be
retried -- only those that take a pathname as an argument.

With this patchset, I've decided to take the relatively less
controversial approach of just having the kernel retry once when it gets
an ESTALE error. I still think that it's not as strong as it should be,
but it should improve the situation in many common cases.

I've also tried to engineer this in such a way that if we do decide that
we need to retry more than once, then it should be easy to change that
later. This should cover all of the syscalls in fs/stat.c and
fs/namei.c, and most of fs/open.c.

Once these are merged, I'll look at adding similar handling to other
path-based syscalls in a later set. A quick look shows that we have
about 50-odd path-based syscalls that will need similar handling, so
this is just a start.

Jeff Layton (20):
  vfs: add a retry_estale helper function to handle retries on ESTALE
  vfs: make fstatat retry on ESTALE errors from getattr call
  vfs: fix readlinkat to retry on ESTALE
  vfs: add new "reval" argument to kern_path_create and
    user_path_create
  vfs: fix mknodat to retry on ESTALE errors
  vfs: fix mkdir to retry on ESTALE errors
  vfs: fix symlinkat to retry on ESTALE errors
  vfs: fix linkat to retry on ESTALE errors
  vfs: add a reval argument to user_path_parent
  vfs: make rmdir retry on ESTALE errors
  vfs: make do_unlinkat retry on ESTALE errors
  vfs: fix renameat to retry on ESTALE errors
  vfs: have do_sys_truncate retry once on an ESTALE error
  vfs: have faccessat retry once on an ESTALE error
  vfs: have chdir retry lookup and call once on ESTALE error
  vfs: make chroot retry once on ESTALE error
  vfs: make fchmodat retry once on ESTALE errors
  vfs: make fchownat retry once on ESTALE errors
  vfs: convert do_filp_open to use retry_estale helper
  vfs: convert do_file_open_root to use retry_estale helper

 arch/powerpc/platforms/cell/spufs/syscalls.c |   2 +-
 drivers/base/devtmpfs.c                      |   7 +-
 fs/namei.c                                   | 265 ++++++++++++++++-----------
 fs/ocfs2/refcounttree.c                      |   3 +-
 fs/open.c                                    | 252 +++++++++++++------------
 fs/stat.c                                    |  32 +++-
 include/linux/fs.h                           |  21 +++
 include/linux/namei.h                        |   4 +-
 net/unix/af_unix.c                           |   2 +-
 9 files changed, 352 insertions(+), 236 deletions(-)

-- 
1.7.11.4


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

* [PATCH v6 01/20] vfs: add a retry_estale helper function to handle retries on ESTALE
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 02/20] vfs: make fstatat retry on ESTALE errors from getattr call Jeff Layton
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

This function is expected to be called from path-based syscalls to help
them decide whether to try the lookup and call again in the event that
they got an -ESTALE return back on an earier try.

Currently, we only retry the call once on an ESTALE error, but in the
event that we decide that that's not enough in the future, we should be
able to change the logic in this helper without too much effort.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 include/linux/fs.h | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/include/linux/fs.h b/include/linux/fs.h
index a3c2c17..78e8639 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2221,6 +2221,27 @@ extern int finish_open(struct file *file, struct dentry *dentry,
 			int *opened);
 extern int finish_no_open(struct file *file, struct dentry *dentry);
 
+/**
+ * retry_estale - determine whether the caller should retry an operation
+ *
+ * @error: the error we'll be returning
+ * @try: number of retries already performed
+ *
+ * Check to see if the error code was -ESTALE, and then determine whether
+ * to retry the call based on the number of retries so far. Currently, we only
+ * retry the call once.
+ *
+ * Returns true if the caller should try again.
+ */
+static inline bool
+retry_estale(const long error, const unsigned int try)
+{
+	if (likely(error != -ESTALE))
+		return false;
+
+	return !try;
+}
+
 /* fs/ioctl.c */
 
 extern int ioctl_preallocate(struct file *filp, void __user *argp);
-- 
1.7.11.4


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

* [PATCH v6 02/20] vfs: make fstatat retry on ESTALE errors from getattr call
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 01/20] vfs: add a retry_estale helper function to handle retries on ESTALE Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 03/20] vfs: fix readlinkat to retry on ESTALE Jeff Layton
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/stat.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/fs/stat.c b/fs/stat.c
index b6ff118..d90258d 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -74,7 +74,8 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
 {
 	struct path path;
 	int error = -EINVAL;
-	int lookup_flags = 0;
+	unsigned int try = 0;
+	unsigned int lookup_flags = 0;
 
 	if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
 		      AT_EMPTY_PATH)) != 0)
@@ -85,12 +86,15 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
 	if (flag & AT_EMPTY_PATH)
 		lookup_flags |= LOOKUP_EMPTY;
 
-	error = user_path_at(dfd, filename, lookup_flags, &path);
-	if (error)
-		goto out;
+	do {
+		error = user_path_at(dfd, filename, lookup_flags, &path);
+		if (error)
+			break;
 
-	error = vfs_getattr(path.mnt, path.dentry, stat);
-	path_put(&path);
+		error = vfs_getattr(path.mnt, path.dentry, stat);
+		path_put(&path);
+		lookup_flags |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
 out:
 	return error;
 }
-- 
1.7.11.4


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

* [PATCH v6 03/20] vfs: fix readlinkat to retry on ESTALE
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 01/20] vfs: add a retry_estale helper function to handle retries on ESTALE Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 02/20] vfs: make fstatat retry on ESTALE errors from getattr call Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 04/20] vfs: add new "reval" argument to kern_path_create and user_path_create Jeff Layton
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/stat.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/fs/stat.c b/fs/stat.c
index d90258d..9719df1 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -300,14 +300,21 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
 	struct path path;
 	int error;
 	int empty = 0;
+	unsigned int try = 0;
+	unsigned int lookup_flags = LOOKUP_EMPTY;
 
 	if (bufsiz <= 0)
 		return -EINVAL;
 
-	error = user_path_at_empty(dfd, pathname, LOOKUP_EMPTY, &path, &empty);
-	if (!error) {
-		struct inode *inode = path.dentry->d_inode;
+	do {
+		struct inode *inode;
+
+		error = user_path_at_empty(dfd, pathname, lookup_flags,
+					   &path, &empty);
+		if (error)
+			break;
 
+		inode = path.dentry->d_inode;
 		error = empty ? -ENOENT : -EINVAL;
 		if (inode->i_op->readlink) {
 			error = security_inode_readlink(path.dentry);
@@ -318,7 +325,8 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
 			}
 		}
 		path_put(&path);
-	}
+		lookup_flags |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
 	return error;
 }
 
-- 
1.7.11.4


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

* [PATCH v6 04/20] vfs: add new "reval" argument to kern_path_create and user_path_create
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (2 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 03/20] vfs: fix readlinkat to retry on ESTALE Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 05/20] vfs: fix mknodat to retry on ESTALE errors Jeff Layton
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

...for now, all of the callers pass in "false". Eventually, we'll set
that to "true" when we retry the lookup after getting back an ESTALE on
a call.

While we're at it, change the is_dir arg to a bool since that's how it's
used currently.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 arch/powerpc/platforms/cell/spufs/syscalls.c |  2 +-
 drivers/base/devtmpfs.c                      |  7 ++++---
 fs/namei.c                                   | 23 +++++++++++++++--------
 fs/ocfs2/refcounttree.c                      |  3 ++-
 include/linux/namei.h                        |  4 ++--
 net/unix/af_unix.c                           |  2 +-
 6 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
index 5b7d8ff..cb4acc7 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -66,7 +66,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
 	struct dentry *dentry;
 	int ret;
 
-	dentry = user_path_create(AT_FDCWD, pathname, &path, 1);
+	dentry = user_path_create(AT_FDCWD, pathname, &path, true, false);
 	ret = PTR_ERR(dentry);
 	if (!IS_ERR(dentry)) {
 		ret = spufs_create(&path, dentry, flags, mode, neighbor);
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index deb4a45..2124437 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -148,7 +148,7 @@ static int dev_mkdir(const char *name, umode_t mode)
 	struct path path;
 	int err;
 
-	dentry = kern_path_create(AT_FDCWD, name, &path, 1);
+	dentry = kern_path_create(AT_FDCWD, name, &path, true, false);
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
 
@@ -193,10 +193,11 @@ static int handle_create(const char *nodename, umode_t mode, struct device *dev)
 	struct path path;
 	int err;
 
-	dentry = kern_path_create(AT_FDCWD, nodename, &path, 0);
+	dentry = kern_path_create(AT_FDCWD, nodename, &path, false, false);
 	if (dentry == ERR_PTR(-ENOENT)) {
 		create_path(nodename);
-		dentry = kern_path_create(AT_FDCWD, nodename, &path, 0);
+		dentry = kern_path_create(AT_FDCWD, nodename, &path,
+								false, false);
 	}
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
diff --git a/fs/namei.c b/fs/namei.c
index 6f9040c..d71be0b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3038,12 +3038,18 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
 	return file;
 }
 
-struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir)
+struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, bool is_dir, bool reval)
 {
 	struct dentry *dentry = ERR_PTR(-EEXIST);
 	struct nameidata nd;
 	int err2;
-	int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
+	int error;
+	unsigned int lookup_flags = LOOKUP_PARENT;
+
+	if (reval)
+		lookup_flags |= LOOKUP_REVAL;
+
+	error = do_path_lookup(dfd, pathname, lookup_flags, &nd);
 	if (error)
 		return ERR_PTR(error);
 
@@ -3107,13 +3113,14 @@ void done_path_create(struct path *path, struct dentry *dentry)
 }
 EXPORT_SYMBOL(done_path_create);
 
-struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)
+struct dentry *user_path_create(int dfd, const char __user *pathname,
+				struct path *path, bool is_dir, bool reval)
 {
 	struct getname_info *tmp = getname(pathname);
 	struct dentry *res;
 	if (IS_ERR(tmp))
 		return ERR_CAST(tmp);
-	res = kern_path_create(dfd, tmp->name, path, is_dir);
+	res = kern_path_create(dfd, tmp->name, path, is_dir, reval);
 	putname(tmp);
 	return res;
 }
@@ -3174,7 +3181,7 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
 	if (error)
 		return error;
 
-	dentry = user_path_create(dfd, filename, &path, 0);
+	dentry = user_path_create(dfd, filename, &path, false, false);
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
 
@@ -3236,7 +3243,7 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
 	struct path path;
 	int error;
 
-	dentry = user_path_create(dfd, pathname, &path, 1);
+	dentry = user_path_create(dfd, pathname, &path, true, false);
 	if (IS_ERR(dentry))
 		return PTR_ERR(dentry);
 
@@ -3512,7 +3519,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
 	if (IS_ERR(from))
 		return PTR_ERR(from);
 
-	dentry = user_path_create(newdfd, newname, &path, 0);
+	dentry = user_path_create(newdfd, newname, &path, false, false);
 	error = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		goto out_putname;
@@ -3612,7 +3619,7 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
 	if (error)
 		return error;
 
-	new_dentry = user_path_create(newdfd, newname, &new_path, 0);
+	new_dentry = user_path_create(newdfd, newname, &new_path, false, false);
 	error = PTR_ERR(new_dentry);
 	if (IS_ERR(new_dentry))
 		goto out;
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 30a0550..645e225 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -4453,7 +4453,8 @@ int ocfs2_reflink_ioctl(struct inode *inode,
 		return error;
 	}
 
-	new_dentry = user_path_create(AT_FDCWD, newname, &new_path, 0);
+	new_dentry = user_path_create(AT_FDCWD, newname, &new_path,
+					false, false);
 	error = PTR_ERR(new_dentry);
 	if (IS_ERR(new_dentry)) {
 		mlog_errno(error);
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 4bf19d8..2202740 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -65,8 +65,8 @@ extern int user_path_at_empty(int, const char __user *, unsigned, struct path *,
 
 extern int kern_path(const char *, unsigned, struct path *);
 
-extern struct dentry *kern_path_create(int, const char *, struct path *, int);
-extern struct dentry *user_path_create(int, const char __user *, struct path *, int);
+extern struct dentry *kern_path_create(int, const char *, struct path *, bool, bool);
+extern struct dentry *user_path_create(int, const char __user *, struct path *, bool, bool);
 extern void done_path_create(struct path *, struct dentry *);
 extern struct dentry *kern_path_locked(const char *, struct path *);
 extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index c5ee4ff..f15b0ff 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -832,7 +832,7 @@ static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
 	 * Get the parent directory, calculate the hash for last
 	 * component.
 	 */
-	dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
+	dentry = kern_path_create(AT_FDCWD, sun_path, &path, false, false);
 	err = PTR_ERR(dentry);
 	if (IS_ERR(dentry))
 		return err;
-- 
1.7.11.4


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

* [PATCH v6 05/20] vfs: fix mknodat to retry on ESTALE errors
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (3 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 04/20] vfs: add new "reval" argument to kern_path_create and user_path_create Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 06/20] vfs: fix mkdir " Jeff Layton
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c | 43 +++++++++++++++++++++++++------------------
 1 file changed, 25 insertions(+), 18 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index d71be0b..11fc388 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3176,34 +3176,41 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
 	struct dentry *dentry;
 	struct path path;
 	int error;
+	unsigned int try = 0;
 
 	error = may_mknod(mode);
 	if (error)
 		return error;
 
-	dentry = user_path_create(dfd, filename, &path, false, false);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
+	do {
+		dentry = user_path_create(dfd, filename, &path, false, try);
+		if (IS_ERR(dentry))
+			return PTR_ERR(dentry);
 
-	if (!IS_POSIXACL(path.dentry->d_inode))
-		mode &= ~current_umask();
-	error = security_path_mknod(&path, dentry, mode, dev);
-	if (error)
-		goto out;
-	switch (mode & S_IFMT) {
-		case 0: case S_IFREG:
-			error = vfs_create(path.dentry->d_inode,dentry,mode,true);
+		if (!IS_POSIXACL(path.dentry->d_inode))
+			mode &= ~current_umask();
+		error = security_path_mknod(&path, dentry, mode, dev);
+		if (error)
+			goto out;
+		switch (mode & S_IFMT) {
+		case 0:
+		case S_IFREG:
+			error = vfs_create(path.dentry->d_inode, dentry,
+					mode, true);
 			break;
-		case S_IFCHR: case S_IFBLK:
-			error = vfs_mknod(path.dentry->d_inode,dentry,mode,
+		case S_IFCHR:
+		case S_IFBLK:
+			error = vfs_mknod(path.dentry->d_inode, dentry, mode,
 					new_decode_dev(dev));
 			break;
-		case S_IFIFO: case S_IFSOCK:
-			error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
-			break;
-	}
+		case S_IFIFO:
+		case S_IFSOCK:
+			error = vfs_mknod(path.dentry->d_inode, dentry,
+					mode, 0);
+		}
 out:
-	done_path_create(&path, dentry);
+		done_path_create(&path, dentry);
+	} while (retry_estale(error, try++));
 	return error;
 }
 
-- 
1.7.11.4


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

* [PATCH v6 06/20] vfs: fix mkdir to retry on ESTALE errors
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (4 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 05/20] vfs: fix mknodat to retry on ESTALE errors Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 07/20] vfs: fix symlinkat " Jeff Layton
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 11fc388..9068375 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3249,17 +3249,20 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
 	struct dentry *dentry;
 	struct path path;
 	int error;
+	unsigned int try = 0;
 
-	dentry = user_path_create(dfd, pathname, &path, true, false);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
+	do {
+		dentry = user_path_create(dfd, pathname, &path, true, false);
+		if (IS_ERR(dentry))
+			return PTR_ERR(dentry);
 
-	if (!IS_POSIXACL(path.dentry->d_inode))
-		mode &= ~current_umask();
-	error = security_path_mkdir(&path, dentry, mode);
-	if (!error)
-		error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
-	done_path_create(&path, dentry);
+		if (!IS_POSIXACL(path.dentry->d_inode))
+			mode &= ~current_umask();
+		error = security_path_mkdir(&path, dentry, mode);
+		if (!error)
+			error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
+		done_path_create(&path, dentry);
+	} while (retry_estale(error, try++));
 	return error;
 }
 
-- 
1.7.11.4


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

* [PATCH v6 07/20] vfs: fix symlinkat to retry on ESTALE errors
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (5 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 06/20] vfs: fix mkdir " Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 08/20] vfs: fix linkat " Jeff Layton
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 9068375..ac731fc 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3524,21 +3524,25 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
 	struct getname_info *from;
 	struct dentry *dentry;
 	struct path path;
+	unsigned int try = 0;
 
 	from = getname(oldname);
 	if (IS_ERR(from))
 		return PTR_ERR(from);
 
-	dentry = user_path_create(newdfd, newname, &path, false, false);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		goto out_putname;
+	do {
+		dentry = user_path_create(newdfd, newname, &path, false, false);
+		if (IS_ERR(dentry)) {
+			error = PTR_ERR(dentry);
+			break;
+		}
 
-	error = security_path_symlink(&path, dentry, from->name);
-	if (!error)
-		error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
-	done_path_create(&path, dentry);
-out_putname:
+		error = security_path_symlink(&path, dentry, from->name);
+		if (!error)
+			error = vfs_symlink(path.dentry->d_inode, dentry,
+						from->name);
+		done_path_create(&path, dentry);
+	} while (retry_estale(error, try++));
 	putname(from);
 	return error;
 }
-- 
1.7.11.4


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

* [PATCH v6 08/20] vfs: fix linkat to retry on ESTALE errors
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (6 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 07/20] vfs: fix symlinkat " Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 09/20] vfs: add a reval argument to user_path_parent Jeff Layton
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c | 46 ++++++++++++++++++++++++++--------------------
 1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index ac731fc..e05d6ee 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3612,6 +3612,7 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
 	struct path old_path, new_path;
 	int how = 0;
 	int error;
+	unsigned int try = 0;
 
 	if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
 		return -EINVAL;
@@ -3629,30 +3630,35 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
 	if (flags & AT_SYMLINK_FOLLOW)
 		how |= LOOKUP_FOLLOW;
 
-	error = user_path_at(olddfd, oldname, how, &old_path);
-	if (error)
-		return error;
+	do {
+		error = user_path_at(olddfd, oldname, how, &old_path);
+		if (error)
+			break;
 
-	new_dentry = user_path_create(newdfd, newname, &new_path, false, false);
-	error = PTR_ERR(new_dentry);
-	if (IS_ERR(new_dentry))
-		goto out;
+		new_dentry = user_path_create(newdfd, newname, &new_path,
+						false, false);
+		error = PTR_ERR(new_dentry);
+		if (IS_ERR(new_dentry))
+			goto out;
 
-	error = -EXDEV;
-	if (old_path.mnt != new_path.mnt)
-		goto out_dput;
-	error = may_linkat(&old_path);
-	if (unlikely(error))
-		goto out_dput;
-	error = security_path_link(old_path.dentry, &new_path, new_dentry);
-	if (error)
-		goto out_dput;
-	error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
+		error = -EXDEV;
+		if (old_path.mnt != new_path.mnt)
+			goto out_dput;
+		error = may_linkat(&old_path);
+		if (unlikely(error))
+			goto out_dput;
+		error = security_path_link(old_path.dentry, &new_path,
+						new_dentry);
+		if (error)
+			goto out_dput;
+		error = vfs_link(old_path.dentry, new_path.dentry->d_inode,
+						new_dentry);
 out_dput:
-	done_path_create(&new_path, new_dentry);
+		done_path_create(&new_path, new_dentry);
 out:
-	path_put(&old_path);
-
+		path_put(&old_path);
+		how |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
 	return error;
 }
 
-- 
1.7.11.4


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

* [PATCH v6 09/20] vfs: add a reval argument to user_path_parent
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (7 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 08/20] vfs: fix linkat " Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 10/20] vfs: make rmdir retry on ESTALE errors Jeff Layton
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

...so we can tell it when to set LOOKUP_REVAL.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index e05d6ee..51841ec 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2183,15 +2183,20 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
  *     path-walking is complete.
  */
 static struct getname_info *
-user_path_parent(int dfd, const char __user *path, struct nameidata *nd)
+user_path_parent(int dfd, const char __user *path, struct nameidata *nd,
+		 unsigned int reval)
 {
 	struct getname_info *s = getname(path);
 	int error;
+	unsigned int flags = LOOKUP_PARENT;
+
+	if (reval)
+		flags |= LOOKUP_REVAL;
 
 	if (IS_ERR(s))
 		return s;
 
-	error = ginfo_lookup(dfd, s, LOOKUP_PARENT, nd);
+	error = ginfo_lookup(dfd, s, flags, nd);
 	if (error) {
 		putname(s);
 		return ERR_PTR(error);
@@ -3339,7 +3344,7 @@ static long do_rmdir(int dfd, const char __user *pathname)
 	struct dentry *dentry;
 	struct nameidata nd;
 
-	name = user_path_parent(dfd, pathname, &nd);
+	name = user_path_parent(dfd, pathname, &nd, 0);
 	if (IS_ERR(name))
 		return PTR_ERR(name);
 
@@ -3435,7 +3440,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
 	struct nameidata nd;
 	struct inode *inode = NULL;
 
-	name = user_path_parent(dfd, pathname, &nd);
+	name = user_path_parent(dfd, pathname, &nd, 0);
 	if (IS_ERR(name))
 		return PTR_ERR(name);
 
@@ -3830,13 +3835,13 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
 	struct getname_info *to;
 	int error;
 
-	from = user_path_parent(olddfd, oldname, &oldnd);
+	from = user_path_parent(olddfd, oldname, &oldnd, 0);
 	if (IS_ERR(from)) {
 		error = PTR_ERR(from);
 		goto exit;
 	}
 
-	to = user_path_parent(newdfd, newname, &newnd);
+	to = user_path_parent(newdfd, newname, &newnd, 0);
 	if (IS_ERR(to)) {
 		error = PTR_ERR(to);
 		goto exit1;
-- 
1.7.11.4


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

* [PATCH v6 10/20] vfs: make rmdir retry on ESTALE errors
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (8 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 09/20] vfs: add a reval argument to user_path_parent Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 11/20] vfs: make do_unlinkat " Jeff Layton
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c | 81 ++++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 44 insertions(+), 37 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 51841ec..a9dd63f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3343,49 +3343,56 @@ static long do_rmdir(int dfd, const char __user *pathname)
 	struct getname_info *name;
 	struct dentry *dentry;
 	struct nameidata nd;
+	unsigned int try = 0;
+	unsigned int lookup_flags = LOOKUP_PARENT;
 
-	name = user_path_parent(dfd, pathname, &nd, 0);
-	if (IS_ERR(name))
-		return PTR_ERR(name);
-
-	switch(nd.last_type) {
-	case LAST_DOTDOT:
-		error = -ENOTEMPTY;
-		goto exit1;
-	case LAST_DOT:
-		error = -EINVAL;
-		goto exit1;
-	case LAST_ROOT:
-		error = -EBUSY;
-		goto exit1;
-	}
+	do {
+		name = user_path_parent(dfd, pathname, &nd, try);
+		if (IS_ERR(name))
+			return PTR_ERR(name);
+
+		switch (nd.last_type) {
+		case LAST_DOTDOT:
+			error = -ENOTEMPTY;
+			goto exit1;
+		case LAST_DOT:
+			error = -EINVAL;
+			goto exit1;
+		case LAST_ROOT:
+			error = -EBUSY;
+			goto exit1;
+		}
 
-	nd.flags &= ~LOOKUP_PARENT;
-	error = mnt_want_write(nd.path.mnt);
-	if (error)
-		goto exit1;
+		nd.flags &= ~LOOKUP_PARENT;
+		error = mnt_want_write(nd.path.mnt);
+		if (error)
+			goto exit1;
 
-	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
-	dentry = lookup_hash(&nd);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		goto exit2;
-	if (!dentry->d_inode) {
-		error = -ENOENT;
-		goto exit3;
-	}
-	error = security_path_rmdir(&nd.path, dentry);
-	if (error)
-		goto exit3;
-	error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
+		mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex,
+					I_MUTEX_PARENT);
+		dentry = lookup_hash(&nd);
+		if (IS_ERR(dentry)) {
+			error = PTR_ERR(dentry);
+			goto exit2;
+		}
+		if (!dentry->d_inode) {
+			error = -ENOENT;
+			goto exit3;
+		}
+		error = security_path_rmdir(&nd.path, dentry);
+		if (error)
+			goto exit3;
+		error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
 exit3:
-	dput(dentry);
+		dput(dentry);
 exit2:
-	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
-	mnt_drop_write(nd.path.mnt);
+		mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+		mnt_drop_write(nd.path.mnt);
 exit1:
-	path_put(&nd.path);
-	putname(name);
+		path_put(&nd.path);
+		lookup_flags |= LOOKUP_REVAL;
+		putname(name);
+	} while (retry_estale(error, try++));
 	return error;
 }
 
-- 
1.7.11.4


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

* [PATCH v6 11/20] vfs: make do_unlinkat retry on ESTALE errors
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (9 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 10/20] vfs: make rmdir retry on ESTALE errors Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 12/20] vfs: fix renameat to " Jeff Layton
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/fs/namei.c b/fs/namei.c
index a9dd63f..77c2b1055 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3446,8 +3446,11 @@ static long do_unlinkat(int dfd, const char __user *pathname)
 	struct dentry *dentry;
 	struct nameidata nd;
 	struct inode *inode = NULL;
+	unsigned int try = 0;
+	unsigned int lookup_flags = LOOKUP_PARENT;
 
-	name = user_path_parent(dfd, pathname, &nd, 0);
+retry:
+	name = user_path_parent(dfd, pathname, &nd, try);
 	if (IS_ERR(name))
 		return PTR_ERR(name);
 
@@ -3485,6 +3488,10 @@ exit2:
 exit1:
 	path_put(&nd.path);
 	putname(name);
+	if (retry_estale(error, try++)) {
+		lookup_flags |= LOOKUP_REVAL;
+		goto retry;
+	}
 	return error;
 
 slashes:
-- 
1.7.11.4


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

* [PATCH v6 12/20] vfs: fix renameat to retry on ESTALE errors
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (10 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 11/20] vfs: make do_unlinkat " Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 13/20] vfs: have do_sys_truncate retry once on an ESTALE error Jeff Layton
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

...as always, rename is the messiest of the bunch. We have to track
whether to retry or not via a separate flag since the error handling
is already quite complex.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 77c2b1055..010d428 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3847,15 +3847,18 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
 	struct nameidata oldnd, newnd;
 	struct getname_info *from;
 	struct getname_info *to;
+	unsigned int try = 0;
+	bool should_retry = false;
 	int error;
 
-	from = user_path_parent(olddfd, oldname, &oldnd, 0);
+retry:
+	from = user_path_parent(olddfd, oldname, &oldnd, try);
 	if (IS_ERR(from)) {
 		error = PTR_ERR(from);
 		goto exit;
 	}
 
-	to = user_path_parent(newdfd, newname, &newnd, 0);
+	to = user_path_parent(newdfd, newname, &newnd, try);
 	if (IS_ERR(to)) {
 		error = PTR_ERR(to);
 		goto exit1;
@@ -3927,11 +3930,17 @@ exit3:
 	unlock_rename(new_dir, old_dir);
 	mnt_drop_write(oldnd.path.mnt);
 exit2:
+	if (retry_estale(error, try++))
+		should_retry = true;
 	path_put(&newnd.path);
 	putname(to);
 exit1:
 	path_put(&oldnd.path);
 	putname(from);
+	if (should_retry) {
+		should_retry = false;
+		goto retry;
+	}
 exit:
 	return error;
 }
-- 
1.7.11.4


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

* [PATCH v6 13/20] vfs: have do_sys_truncate retry once on an ESTALE error
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (11 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 12/20] vfs: fix renameat to " Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 14/20] vfs: have faccessat " Jeff Layton
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/open.c | 86 +++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 45 insertions(+), 41 deletions(-)

diff --git a/fs/open.c b/fs/open.c
index d0f225e..5dcee00 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -66,62 +66,66 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
 	struct path path;
 	struct inode *inode;
 	int error;
+	unsigned int lookup_flags = LOOKUP_FOLLOW;
+	unsigned int try = 0;
 
-	error = -EINVAL;
 	if (length < 0)	/* sorry, but loff_t says... */
-		goto out;
+		return -EINVAL;
 
-	error = user_path(pathname, &path);
-	if (error)
-		goto out;
-	inode = path.dentry->d_inode;
+	do {
+		error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+		if (error)
+			break;
+		inode = path.dentry->d_inode;
 
-	/* For directories it's -EISDIR, for other non-regulars - -EINVAL */
-	error = -EISDIR;
-	if (S_ISDIR(inode->i_mode))
-		goto dput_and_out;
+		/* For dirs, -EISDIR. For other non-regulars, -EINVAL */
+		error = -EISDIR;
+		if (S_ISDIR(inode->i_mode))
+			goto dput_and_out;
 
-	error = -EINVAL;
-	if (!S_ISREG(inode->i_mode))
-		goto dput_and_out;
+		error = -EINVAL;
+		if (!S_ISREG(inode->i_mode))
+			goto dput_and_out;
 
-	error = mnt_want_write(path.mnt);
-	if (error)
-		goto dput_and_out;
+		error = mnt_want_write(path.mnt);
+		if (error)
+			goto dput_and_out;
 
-	error = inode_permission(inode, MAY_WRITE);
-	if (error)
-		goto mnt_drop_write_and_out;
+		error = inode_permission(inode, MAY_WRITE);
+		if (error)
+			goto mnt_drop_write_and_out;
 
-	error = -EPERM;
-	if (IS_APPEND(inode))
-		goto mnt_drop_write_and_out;
+		error = -EPERM;
+		if (IS_APPEND(inode))
+			goto mnt_drop_write_and_out;
 
-	error = get_write_access(inode);
-	if (error)
-		goto mnt_drop_write_and_out;
+		error = get_write_access(inode);
+		if (error)
+			goto mnt_drop_write_and_out;
 
-	/*
-	 * Make sure that there are no leases.  get_write_access() protects
-	 * against the truncate racing with a lease-granting setlease().
-	 */
-	error = break_lease(inode, O_WRONLY);
-	if (error)
-		goto put_write_and_out;
+		/*
+		 * Make sure that there are no leases. get_write_access()
+		 * protects against the truncate racing with a lease-granting
+		 * setlease().
+		 */
+		error = break_lease(inode, O_WRONLY);
+		if (error)
+			goto put_write_and_out;
 
-	error = locks_verify_truncate(inode, NULL, length);
-	if (!error)
-		error = security_path_truncate(&path);
-	if (!error)
-		error = do_truncate(path.dentry, length, 0, NULL);
+		error = locks_verify_truncate(inode, NULL, length);
+		if (!error)
+			error = security_path_truncate(&path);
+		if (!error)
+			error = do_truncate(path.dentry, length, 0, NULL);
 
 put_write_and_out:
-	put_write_access(inode);
+		put_write_access(inode);
 mnt_drop_write_and_out:
-	mnt_drop_write(path.mnt);
+		mnt_drop_write(path.mnt);
 dput_and_out:
-	path_put(&path);
-out:
+		path_put(&path);
+		lookup_flags |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
 	return error;
 }
 
-- 
1.7.11.4


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

* [PATCH v6 14/20] vfs: have faccessat retry once on an ESTALE error
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (12 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 13/20] vfs: have do_sys_truncate retry once on an ESTALE error Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 15/20] vfs: have chdir retry lookup and call once on " Jeff Layton
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/open.c | 64 +++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 34 insertions(+), 30 deletions(-)

diff --git a/fs/open.c b/fs/open.c
index 5dcee00..a5a5c9a 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -312,6 +312,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
 	struct path path;
 	struct inode *inode;
 	int res;
+	unsigned int lookup_flags = LOOKUP_FOLLOW;
+	unsigned int try = 0;
 
 	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
 		return -EINVAL;
@@ -335,42 +337,44 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
 
 	old_cred = override_creds(override_cred);
 
-	res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
-	if (res)
-		goto out;
+	do {
+		res = user_path_at(dfd, filename, lookup_flags, &path);
+		if (res)
+			break;
 
-	inode = path.dentry->d_inode;
+		inode = path.dentry->d_inode;
+
+		if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
+			/*
+			 * MAY_EXEC on regular files is denied if the fs is
+			 * mounted with the "noexec" flag.
+			 */
+			res = -EACCES;
+			if (path.mnt->mnt_flags & MNT_NOEXEC)
+				goto out_path_release;
+		}
 
-	if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
+		res = inode_permission(inode, mode | MAY_ACCESS);
+		/* SuS v2 requires we report a read only fs too */
+		if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
+			goto out_path_release;
 		/*
-		 * MAY_EXEC on regular files is denied if the fs is mounted
-		 * with the "noexec" flag.
+		 * This is a rare case where using __mnt_is_readonly()
+		 * is OK without a mnt_want/drop_write() pair.  Since
+		 * no actual write to the fs is performed here, we do
+		 * not need to telegraph to that to anyone.
+		 *
+		 * By doing this, we accept that this access is
+		 * inherently racy and know that the fs may change
+		 * state before we even see this result.
 		 */
-		res = -EACCES;
-		if (path.mnt->mnt_flags & MNT_NOEXEC)
-			goto out_path_release;
-	}
-
-	res = inode_permission(inode, mode | MAY_ACCESS);
-	/* SuS v2 requires we report a read only fs too */
-	if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
-		goto out_path_release;
-	/*
-	 * This is a rare case where using __mnt_is_readonly()
-	 * is OK without a mnt_want/drop_write() pair.  Since
-	 * no actual write to the fs is performed here, we do
-	 * not need to telegraph to that to anyone.
-	 *
-	 * By doing this, we accept that this access is
-	 * inherently racy and know that the fs may change
-	 * state before we even see this result.
-	 */
-	if (__mnt_is_readonly(path.mnt))
-		res = -EROFS;
+		if (__mnt_is_readonly(path.mnt))
+			res = -EROFS;
 
 out_path_release:
-	path_put(&path);
-out:
+		path_put(&path);
+		lookup_flags |= LOOKUP_REVAL;
+	} while (retry_estale(res, try++));
 	revert_creds(old_cred);
 	put_cred(override_cred);
 	return res;
-- 
1.7.11.4


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

* [PATCH v6 15/20] vfs: have chdir retry lookup and call once on ESTALE error
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (13 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 14/20] vfs: have faccessat " Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 16/20] vfs: make chroot retry " Jeff Layton
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/open.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/fs/open.c b/fs/open.c
index a5a5c9a..81ba325 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -389,20 +389,21 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
 {
 	struct path path;
 	int error;
+	int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+	unsigned int try = 0;
 
-	error = user_path_dir(filename, &path);
-	if (error)
-		goto out;
-
-	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
-	if (error)
-		goto dput_and_out;
-
-	set_fs_pwd(current->fs, &path);
+	do {
+		error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
+		if (error)
+			break;
 
-dput_and_out:
-	path_put(&path);
-out:
+		error = inode_permission(path.dentry->d_inode,
+					 MAY_EXEC | MAY_CHDIR);
+		if (!error)
+			set_fs_pwd(current->fs, &path);
+		path_put(&path);
+		lookup_flags |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
 	return error;
 }
 
-- 
1.7.11.4


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

* [PATCH v6 16/20] vfs: make chroot retry once on ESTALE error
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (14 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 15/20] vfs: have chdir retry lookup and call once on " Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 17/20] vfs: make fchmodat retry once on ESTALE errors Jeff Layton
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/open.c | 37 +++++++++++++++++++++----------------
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/fs/open.c b/fs/open.c
index 81ba325..a015cb8 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -437,27 +437,32 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
 {
 	struct path path;
 	int error;
+	int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+	unsigned int try = 0;
 
-	error = user_path_dir(filename, &path);
-	if (error)
-		goto out;
+	do {
+		error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
+		if (error)
+			break;
 
-	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
-	if (error)
-		goto dput_and_out;
+		error = inode_permission(path.dentry->d_inode,
+					 MAY_EXEC | MAY_CHDIR);
+		if (error)
+			goto dput_and_out;
 
-	error = -EPERM;
-	if (!capable(CAP_SYS_CHROOT))
-		goto dput_and_out;
-	error = security_path_chroot(&path);
-	if (error)
-		goto dput_and_out;
+		error = -EPERM;
+		if (!capable(CAP_SYS_CHROOT))
+			goto dput_and_out;
+		error = security_path_chroot(&path);
+		if (error)
+			goto dput_and_out;
 
-	set_fs_root(current->fs, &path);
-	error = 0;
+		set_fs_root(current->fs, &path);
+		error = 0;
 dput_and_out:
-	path_put(&path);
-out:
+		path_put(&path);
+		lookup_flags |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
 	return error;
 }
 
-- 
1.7.11.4


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

* [PATCH v6 17/20] vfs: make fchmodat retry once on ESTALE errors
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (15 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 16/20] vfs: make chroot retry " Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 18/20] vfs: make fchownat " Jeff Layton
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/open.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/fs/open.c b/fs/open.c
index a015cb8..232cbfb 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -506,12 +506,17 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode
 {
 	struct path path;
 	int error;
+	unsigned int try = 0;
+	int lookup_flags = LOOKUP_FOLLOW;
 
-	error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
-	if (!error) {
+	do {
+		error = user_path_at(dfd, filename, lookup_flags, &path);
+		if (error)
+			break;
 		error = chmod_common(&path, mode);
 		path_put(&path);
-	}
+		lookup_flags |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
 	return error;
 }
 
-- 
1.7.11.4


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

* [PATCH v6 18/20] vfs: make fchownat retry once on ESTALE errors
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (16 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 17/20] vfs: make fchmodat retry once on ESTALE errors Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 19/20] vfs: convert do_filp_open to use retry_estale helper Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 20/20] vfs: convert do_file_open_root " Jeff Layton
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/open.c | 29 +++++++++++++++++------------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/fs/open.c b/fs/open.c
index 232cbfb..1bdfd9a 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -567,24 +567,29 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
 	struct path path;
 	int error = -EINVAL;
 	int lookup_flags;
+	unsigned int try = 0;
 
 	if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
-		goto out;
+		return error;
 
 	lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
 	if (flag & AT_EMPTY_PATH)
 		lookup_flags |= LOOKUP_EMPTY;
-	error = user_path_at(dfd, filename, lookup_flags, &path);
-	if (error)
-		goto out;
-	error = mnt_want_write(path.mnt);
-	if (error)
-		goto out_release;
-	error = chown_common(&path, user, group);
-	mnt_drop_write(path.mnt);
-out_release:
-	path_put(&path);
-out:
+
+	do {
+		error = user_path_at(dfd, filename, lookup_flags, &path);
+		if (error)
+			break;
+
+		error = mnt_want_write(path.mnt);
+		if (!error) {
+			error = chown_common(&path, user, group);
+			mnt_drop_write(path.mnt);
+		}
+
+		path_put(&path);
+		lookup_flags |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
 	return error;
 }
 
-- 
1.7.11.4


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

* [PATCH v6 19/20] vfs: convert do_filp_open to use retry_estale helper
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (17 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 18/20] vfs: make fchownat " Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  2012-09-07 14:18 ` [PATCH v6 20/20] vfs: convert do_file_open_root " Jeff Layton
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/namei.c b/fs/namei.c
index 010d428..66b24fa 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3011,11 +3011,12 @@ struct file *do_filp_open(int dfd, struct getname_info *ginfo,
 {
 	struct nameidata nd;
 	struct file *filp;
+	unsigned int try = 0;
 
 	filp = path_openat(dfd, ginfo, &nd, op, flags | LOOKUP_RCU);
 	if (unlikely(filp == ERR_PTR(-ECHILD)))
 		filp = path_openat(dfd, ginfo, &nd, op, flags);
-	if (unlikely(filp == ERR_PTR(-ESTALE)))
+	while (retry_estale(PTR_ERR(filp), try++))
 		filp = path_openat(dfd, ginfo, &nd, op, flags | LOOKUP_REVAL);
 	return filp;
 }
-- 
1.7.11.4


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

* [PATCH v6 20/20] vfs: convert do_file_open_root to use retry_estale helper
  2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (18 preceding siblings ...)
  2012-09-07 14:18 ` [PATCH v6 19/20] vfs: convert do_filp_open to use retry_estale helper Jeff Layton
@ 2012-09-07 14:18 ` Jeff Layton
  19 siblings, 0 replies; 21+ messages in thread
From: Jeff Layton @ 2012-09-07 14:18 UTC (permalink / raw)
  To: viro
  Cc: linux-fsdevel, linux-nfs, linux-kernel, michael.brantley, hch,
	miklos, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/namei.c b/fs/namei.c
index 66b24fa..870352d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3027,6 +3027,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
 	struct nameidata nd;
 	struct file *file;
 	struct getname_info ginfo = { .name = name };
+	unsigned int try = 0;
 
 	nd.root.mnt = mnt;
 	nd.root.dentry = dentry;
@@ -3039,7 +3040,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
 	file = path_openat(-1, &ginfo, &nd, op, flags | LOOKUP_RCU);
 	if (unlikely(file == ERR_PTR(-ECHILD)))
 		file = path_openat(-1, &ginfo, &nd, op, flags);
-	if (unlikely(file == ERR_PTR(-ESTALE)))
+	while (retry_estale(PTR_ERR(file), try++))
 		file = path_openat(-1, &ginfo, &nd, op, flags | LOOKUP_REVAL);
 	return file;
 }
-- 
1.7.11.4


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

end of thread, other threads:[~2012-09-07 14:26 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-07 14:18 [PATCH v6 00/20] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
2012-09-07 14:18 ` [PATCH v6 01/20] vfs: add a retry_estale helper function to handle retries on ESTALE Jeff Layton
2012-09-07 14:18 ` [PATCH v6 02/20] vfs: make fstatat retry on ESTALE errors from getattr call Jeff Layton
2012-09-07 14:18 ` [PATCH v6 03/20] vfs: fix readlinkat to retry on ESTALE Jeff Layton
2012-09-07 14:18 ` [PATCH v6 04/20] vfs: add new "reval" argument to kern_path_create and user_path_create Jeff Layton
2012-09-07 14:18 ` [PATCH v6 05/20] vfs: fix mknodat to retry on ESTALE errors Jeff Layton
2012-09-07 14:18 ` [PATCH v6 06/20] vfs: fix mkdir " Jeff Layton
2012-09-07 14:18 ` [PATCH v6 07/20] vfs: fix symlinkat " Jeff Layton
2012-09-07 14:18 ` [PATCH v6 08/20] vfs: fix linkat " Jeff Layton
2012-09-07 14:18 ` [PATCH v6 09/20] vfs: add a reval argument to user_path_parent Jeff Layton
2012-09-07 14:18 ` [PATCH v6 10/20] vfs: make rmdir retry on ESTALE errors Jeff Layton
2012-09-07 14:18 ` [PATCH v6 11/20] vfs: make do_unlinkat " Jeff Layton
2012-09-07 14:18 ` [PATCH v6 12/20] vfs: fix renameat to " Jeff Layton
2012-09-07 14:18 ` [PATCH v6 13/20] vfs: have do_sys_truncate retry once on an ESTALE error Jeff Layton
2012-09-07 14:18 ` [PATCH v6 14/20] vfs: have faccessat " Jeff Layton
2012-09-07 14:18 ` [PATCH v6 15/20] vfs: have chdir retry lookup and call once on " Jeff Layton
2012-09-07 14:18 ` [PATCH v6 16/20] vfs: make chroot retry " Jeff Layton
2012-09-07 14:18 ` [PATCH v6 17/20] vfs: make fchmodat retry once on ESTALE errors Jeff Layton
2012-09-07 14:18 ` [PATCH v6 18/20] vfs: make fchownat " Jeff Layton
2012-09-07 14:18 ` [PATCH v6 19/20] vfs: convert do_filp_open to use retry_estale helper Jeff Layton
2012-09-07 14:18 ` [PATCH v6 20/20] vfs: convert do_file_open_root " Jeff Layton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).