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

This patchset is the second version of the patchset to add ESTALE
handling to several syscalls. The previous version is here:

    http://lwn.net/Articles/496103/

I spoke with Al Viro about my previous set and he pointed out something
I had not considered. getname() has side effects when auditing is
enabled, so if we end up calling it multiple times for the same names,
we'll make a mess of the audit handling.

This patchset is a revised version that should fix that by ensuring that
we only call getname() once per __user path, per syscall. In order to do
that, I had to break up some of the nice user_path_* wrappers.

I've tried to keep this patchset pretty granular. Some of these patches
could be combined if that's desirable. It's probably too late for 3.5
here, but I'd like to see this considered for 3.6 if possible.

Jeff Layton (15):
  vfs: add a retry_estale helper function to handle retries on ESTALE
  vfs: add a kern_path_at function
  vfs: make fstatat retry on ESTALE errors from getattr call
  vfs: fix readlinkat to retry on ESTALE
  vfs: remove user_path_at_empty
  vfs: turn "empty" arg in getname_flags into a bool
  vfs: add new "reval" argument to kern_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: make rmdir retry on ESTALE errors
  vfs: make do_unlinkat retry on ESTALE errors
  vfs: fix renameat to retry on ESTALE errors
  vfs: remove user_path_parent

 drivers/base/devtmpfs.c |    7 +-
 fs/namei.c              |  407 ++++++++++++++++++++++++++++-------------------
 fs/stat.c               |   44 ++++--
 include/linux/fs.h      |   24 +++-
 include/linux/namei.h   |    4 +-
 net/unix/af_unix.c      |    3 +-
 6 files changed, 310 insertions(+), 179 deletions(-)

-- 
1.7.7.6


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

* [PATCH v2 01/15] vfs: add a retry_estale helper function to handle retries on ESTALE
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 02/15] vfs: add a kern_path_at function Jeff Layton
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, 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 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/include/linux/fs.h b/include/linux/fs.h
index 25c40b9..0b8003b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2026,6 +2026,27 @@ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
 extern int filp_close(struct file *, fl_owner_t id);
 extern char * getname(const char __user *);
 
+/**
+ * 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.7.6


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

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

This will function like user_path_at, but does not do the getname and
putname, leaving that to the caller.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c            |   27 +++++++++++++++++++--------
 include/linux/namei.h |    1 +
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index f9e883c..c63242f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1886,20 +1886,31 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
 	return __lookup_hash(&this, base, NULL);
 }
 
+int kern_path_at(int dfd, const char *name, unsigned flags, struct path *path)
+{
+	struct nameidata nd;
+	int err;
+
+	BUG_ON(flags & LOOKUP_PARENT);
+
+	err = do_path_lookup(dfd, name, flags, &nd);
+	if (!err)
+		*path = nd.path;
+
+	return err;
+}
+
 int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
 		 struct path *path, int *empty)
 {
-	struct nameidata nd;
 	char *tmp = getname_flags(name, flags, empty);
-	int err = PTR_ERR(tmp);
-	if (!IS_ERR(tmp)) {
-
-		BUG_ON(flags & LOOKUP_PARENT);
+	int err;
 
-		err = do_path_lookup(dfd, tmp, flags, &nd);
+	if (IS_ERR(tmp)) {
+		err = PTR_ERR(tmp);
+	} else {
+		err = kern_path_at(dfd, tmp, flags, path);
 		putname(tmp);
-		if (!err)
-			*path = nd.path;
 	}
 	return err;
 }
diff --git a/include/linux/namei.h b/include/linux/namei.h
index ffc0213..cd95fcb 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -66,6 +66,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
 #define LOOKUP_ROOT		0x2000
 #define LOOKUP_EMPTY		0x4000
 
+extern int kern_path_at(int, const char *, unsigned, struct path *);
 extern int user_path_at(int, const char __user *, unsigned, struct path *);
 extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty);
 
-- 
1.7.7.6


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

* [PATCH v2 03/15] vfs: make fstatat retry on ESTALE errors from getattr call
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 01/15] vfs: add a retry_estale helper function to handle retries on ESTALE Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 02/15] vfs: add a kern_path_at function Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 04/15] vfs: fix readlinkat to retry on ESTALE Jeff Layton
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c         |    2 +-
 fs/stat.c          |   21 ++++++++++++++++-----
 include/linux/fs.h |    3 ++-
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index c63242f..516be34 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -116,7 +116,7 @@
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  * PATH_MAX includes the nul terminator --RR.
  */
-static char *getname_flags(const char __user *filename, int flags, int *empty)
+char *getname_flags(const char __user *filename, int flags, int *empty)
 {
 	char *result = __getname(), *err;
 	int len;
diff --git a/fs/stat.c b/fs/stat.c
index 0cef336..60a8813 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -72,9 +72,11 @@ EXPORT_SYMBOL(vfs_fstat);
 int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
 		int flag)
 {
+	char *name;
 	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 +87,21 @@ 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)
+	name = getname_flags(filename, lookup_flags, NULL);
+	if (IS_ERR(name)) {
+		error = PTR_ERR(name);
 		goto out;
+	}
+	do {
+		error = kern_path_at(dfd, name, 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++));
+	putname(name);
 out:
 	return error;
 }
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 0b8003b..2f92b93 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2024,7 +2024,8 @@ extern struct file *file_open_root(struct dentry *, struct vfsmount *,
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
 				 const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
-extern char * getname(const char __user *);
+extern char *getname_flags(const char __user *, int, int *);
+extern char *getname(const char __user *);
 
 /**
  * retry_estale - determine whether the caller should retry an operation
-- 
1.7.7.6


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

* [PATCH v2 04/15] vfs: fix readlinkat to retry on ESTALE
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (2 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 03/15] vfs: make fstatat retry on ESTALE errors from getattr call Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 05/15] vfs: remove user_path_at_empty Jeff Layton
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

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

diff --git a/fs/stat.c b/fs/stat.c
index 60a8813..671106d 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -307,14 +307,25 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
 	struct path path;
 	int error;
 	int empty = 0;
+	char *name;
+	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;
+	name = getname_flags(pathname, lookup_flags, &empty);
+	if (IS_ERR(name))
+		return PTR_ERR(name);
+
+	do {
+		struct inode *inode;
+
+		error = kern_path_at(dfd, name, lookup_flags, &path);
+		if (error)
+			break;
 
+		inode = path.dentry->d_inode;
 		error = empty ? -ENOENT : -EINVAL;
 		if (inode->i_op->readlink) {
 			error = security_inode_readlink(path.dentry);
@@ -325,7 +336,9 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
 			}
 		}
 		path_put(&path);
-	}
+		lookup_flags |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
+	putname(name);
 	return error;
 }
 
-- 
1.7.7.6


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

* [PATCH v2 05/15] vfs: remove user_path_at_empty
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (3 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 04/15] vfs: fix readlinkat to retry on ESTALE Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 06/15] vfs: turn "empty" arg in getname_flags into a bool Jeff Layton
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

...there are no more callers.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c            |   12 +++---------
 include/linux/namei.h |    1 -
 2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 516be34..f13ba02 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1900,10 +1900,10 @@ int kern_path_at(int dfd, const char *name, unsigned flags, struct path *path)
 	return err;
 }
 
-int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
-		 struct path *path, int *empty)
+int user_path_at(int dfd, const char __user *name, unsigned flags,
+		 struct path *path)
 {
-	char *tmp = getname_flags(name, flags, empty);
+	char *tmp = getname_flags(name, flags, NULL);
 	int err;
 
 	if (IS_ERR(tmp)) {
@@ -1915,12 +1915,6 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
 	return err;
 }
 
-int user_path_at(int dfd, const char __user *name, unsigned flags,
-		 struct path *path)
-{
-	return user_path_at_empty(dfd, name, flags, path, NULL);
-}
-
 static int user_path_parent(int dfd, const char __user *path,
 			struct nameidata *nd, char **name)
 {
diff --git a/include/linux/namei.h b/include/linux/namei.h
index cd95fcb..1ea93d5 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -68,7 +68,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
 
 extern int kern_path_at(int, const char *, unsigned, struct path *);
 extern int user_path_at(int, const char __user *, unsigned, struct path *);
-extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty);
 
 #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
 #define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path)
-- 
1.7.7.6


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

* [PATCH v2 06/15] vfs: turn "empty" arg in getname_flags into a bool
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (4 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 05/15] vfs: remove user_path_at_empty Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 07/15] vfs: add new "reval" argument to kern_path_create Jeff Layton
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

...it's just used as a flag.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c         |    4 ++--
 fs/stat.c          |    2 +-
 include/linux/fs.h |    2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index f13ba02..1c3b922 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -116,7 +116,7 @@
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  * PATH_MAX includes the nul terminator --RR.
  */
-char *getname_flags(const char __user *filename, int flags, int *empty)
+char *getname_flags(const char __user *filename, int flags, bool *empty)
 {
 	char *result = __getname(), *err;
 	int len;
@@ -132,7 +132,7 @@ char *getname_flags(const char __user *filename, int flags, int *empty)
 	/* The empty path is special. */
 	if (unlikely(!len)) {
 		if (empty)
-			*empty = 1;
+			*empty = true;
 		err = ERR_PTR(-ENOENT);
 		if (!(flags & LOOKUP_EMPTY))
 			goto error;
diff --git a/fs/stat.c b/fs/stat.c
index 671106d..5e0050d 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -306,7 +306,7 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
 {
 	struct path path;
 	int error;
-	int empty = 0;
+	bool empty = false;
 	char *name;
 	unsigned int try = 0;
 	unsigned int lookup_flags = LOOKUP_EMPTY;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2f92b93..6a33ce4 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2024,7 +2024,7 @@ extern struct file *file_open_root(struct dentry *, struct vfsmount *,
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
 				 const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
-extern char *getname_flags(const char __user *, int, int *);
+extern char *getname_flags(const char __user *, int, bool *);
 extern char *getname(const char __user *);
 
 /**
-- 
1.7.7.6


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

* [PATCH v2 07/15] vfs: add new "reval" argument to kern_path_create
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (5 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 06/15] vfs: turn "empty" arg in getname_flags into a bool Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 08/15] vfs: fix mknodat to retry on ESTALE errors Jeff Layton
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, 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>
---
 drivers/base/devtmpfs.c |    7 ++++---
 fs/namei.c              |   12 +++++++++---
 include/linux/namei.h   |    2 +-
 net/unix/af_unix.c      |    3 ++-
 4 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 8493536..c9c8c76 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);
 
@@ -195,10 +195,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 1c3b922..7025001 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2468,11 +2468,17 @@ 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 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);
 
@@ -2526,7 +2532,7 @@ struct dentry *user_path_create(int dfd, const char __user *pathname, struct pat
 	struct dentry *res;
 	if (IS_ERR(tmp))
 		return ERR_CAST(tmp);
-	res = kern_path_create(dfd, tmp, path, is_dir);
+	res = kern_path_create(dfd, tmp, path, (bool)is_dir, false);
 	putname(tmp);
 	return res;
 }
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 1ea93d5..9e135e3 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -76,7 +76,7 @@ extern int user_path_at(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 *kern_path_create(int, const char *, struct path *, bool, bool);
 extern struct dentry *user_path_create(int, const char __user *, struct path *, int);
 extern int kern_path_parent(const char *, struct nameidata *);
 extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 641f2e4..d94caa9 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -866,7 +866,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 		 * 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))
 			goto out_mknod_parent;
-- 
1.7.7.6


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

* [PATCH v2 08/15] vfs: fix mknodat to retry on ESTALE errors
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (6 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 07/15] vfs: add new "reval" argument to kern_path_create Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 09/15] vfs: fix mkdir " Jeff Layton
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 fs/namei.c |   68 +++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 40 insertions(+), 28 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 7025001..c3fbd44 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2589,44 +2589,56 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
 	struct dentry *dentry;
 	struct path path;
 	int error;
+	char *name;
+	unsigned int try = 0;
 
 	if (S_ISDIR(mode))
 		return -EPERM;
 
-	dentry = user_path_create(dfd, filename, &path, 0);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
+	name = getname(filename);
+	if (IS_ERR(name))
+		return PTR_ERR(name);
 
-	if (!IS_POSIXACL(path.dentry->d_inode))
-		mode &= ~current_umask();
-	error = may_mknod(mode);
-	if (error)
-		goto out_dput;
-	error = mnt_want_write(path.mnt);
-	if (error)
-		goto out_dput;
-	error = security_path_mknod(&path, dentry, mode, dev);
-	if (error)
-		goto out_drop_write;
-	switch (mode & S_IFMT) {
-		case 0: case S_IFREG:
-			error = vfs_create(path.dentry->d_inode,dentry,mode,NULL);
+	do {
+		dentry = kern_path_create(dfd, name, &path, false, try);
+		if (IS_ERR(dentry))
+			return PTR_ERR(dentry);
+
+		if (!IS_POSIXACL(path.dentry->d_inode))
+			mode &= ~current_umask();
+		error = may_mknod(mode);
+		if (error)
+			goto out_dput;
+		error = mnt_want_write(path.mnt);
+		if (error)
+			goto out_dput;
+		error = security_path_mknod(&path, dentry, mode, dev);
+		if (error)
+			goto out_drop_write;
+		switch (mode & S_IFMT) {
+		case 0:
+		case S_IFREG:
+			error = vfs_create(path.dentry->d_inode, dentry,
+					mode, NULL);
 			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_drop_write:
-	mnt_drop_write(path.mnt);
+		mnt_drop_write(path.mnt);
 out_dput:
-	dput(dentry);
-	mutex_unlock(&path.dentry->d_inode->i_mutex);
-	path_put(&path);
-
+		dput(dentry);
+		mutex_unlock(&path.dentry->d_inode->i_mutex);
+		path_put(&path);
+	} while (retry_estale(error, try++));
+	putname(name);
 	return error;
 }
 
-- 
1.7.7.6


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

* [PATCH v2 09/15] vfs: fix mkdir to retry on ESTALE errors
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (7 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 08/15] vfs: fix mknodat to retry on ESTALE errors Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 10/15] vfs: fix symlinkat " Jeff Layton
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

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

diff --git a/fs/namei.c b/fs/namei.c
index c3fbd44..812b978 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2677,26 +2677,35 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
 	struct dentry *dentry;
 	struct path path;
 	int error;
+	char *name;
+	unsigned int try = 0;
 
-	dentry = user_path_create(dfd, pathname, &path, 1);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
-
-	if (!IS_POSIXACL(path.dentry->d_inode))
-		mode &= ~current_umask();
-	error = mnt_want_write(path.mnt);
-	if (error)
-		goto out_dput;
-	error = security_path_mkdir(&path, dentry, mode);
-	if (error)
-		goto out_drop_write;
-	error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
+	name = getname(pathname);
+	if (IS_ERR(name))
+		return PTR_ERR(name);
+	do {
+		dentry = kern_path_create(dfd, name, &path, true, try);
+		if (IS_ERR(dentry)) {
+			error = PTR_ERR(dentry);
+			break;
+		}
+		if (!IS_POSIXACL(path.dentry->d_inode))
+			mode &= ~current_umask();
+		error = mnt_want_write(path.mnt);
+		if (error)
+			goto out_dput;
+		error = security_path_mkdir(&path, dentry, mode);
+		if (error)
+			goto out_drop_write;
+		error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
 out_drop_write:
-	mnt_drop_write(path.mnt);
+		mnt_drop_write(path.mnt);
 out_dput:
-	dput(dentry);
-	mutex_unlock(&path.dentry->d_inode->i_mutex);
-	path_put(&path);
+		dput(dentry);
+		mutex_unlock(&path.dentry->d_inode->i_mutex);
+		path_put(&path);
+	} while (retry_estale(error, try++));
+	putname(name);
 	return error;
 }
 
-- 
1.7.7.6


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

* [PATCH v2 10/15] vfs: fix symlinkat to retry on ESTALE errors
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (8 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 09/15] vfs: fix mkdir " Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 11/15] vfs: fix linkat " Jeff Layton
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

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

diff --git a/fs/namei.c b/fs/namei.c
index 812b978..5c8ceb9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2966,33 +2966,42 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
 		int, newdfd, const char __user *, newname)
 {
 	int error;
-	char *from;
+	char *from, *to;
 	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, 0);
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		goto out_putname;
+	to = getname(newname);
+	if (IS_ERR(to)) {
+		putname(from);
+		return PTR_ERR(to);
+	}
 
-	error = mnt_want_write(path.mnt);
-	if (error)
-		goto out_dput;
-	error = security_path_symlink(&path, dentry, from);
-	if (error)
-		goto out_drop_write;
-	error = vfs_symlink(path.dentry->d_inode, dentry, from);
+	do {
+		dentry = kern_path_create(newdfd, to, &path, 0, try);
+		error = PTR_ERR(dentry);
+		if (IS_ERR(dentry))
+			break;
+
+		error = mnt_want_write(path.mnt);
+		if (error)
+			goto out_dput;
+		error = security_path_symlink(&path, dentry, from);
+		if (error)
+			goto out_drop_write;
+		error = vfs_symlink(path.dentry->d_inode, dentry, from);
 out_drop_write:
-	mnt_drop_write(path.mnt);
+		mnt_drop_write(path.mnt);
 out_dput:
-	dput(dentry);
-	mutex_unlock(&path.dentry->d_inode->i_mutex);
-	path_put(&path);
-out_putname:
+		dput(dentry);
+		mutex_unlock(&path.dentry->d_inode->i_mutex);
+		path_put(&path);
+	} while (retry_estale(error, try++));
+	putname(to);
 	putname(from);
 	return error;
 }
-- 
1.7.7.6


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

* [PATCH v2 11/15] vfs: fix linkat to retry on ESTALE errors
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (9 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 10/15] vfs: fix symlinkat " Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 12/15] vfs: make rmdir " Jeff Layton
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

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

diff --git a/fs/namei.c b/fs/namei.c
index 5c8ceb9..402f469 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3071,6 +3071,8 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
 	struct path old_path, new_path;
 	int how = 0;
 	int error;
+	char *old, *new;
+	unsigned int try = 0;
 
 	if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
 		return -EINVAL;
@@ -3088,34 +3090,51 @@ 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;
+	old = getname_flags(oldname, how, NULL);
+	if (IS_ERR(old))
+		return PTR_ERR(old);
 
-	new_dentry = user_path_create(newdfd, newname, &new_path, 0);
-	error = PTR_ERR(new_dentry);
-	if (IS_ERR(new_dentry))
-		goto out;
+	new = getname(newname);
+	if (IS_ERR(new)) {
+		putname(old);
+		return PTR_ERR(new);
+	}
 
-	error = -EXDEV;
-	if (old_path.mnt != new_path.mnt)
-		goto out_dput;
-	error = mnt_want_write(new_path.mnt);
-	if (error)
-		goto out_dput;
-	error = security_path_link(old_path.dentry, &new_path, new_dentry);
-	if (error)
-		goto out_drop_write;
-	error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
+	do {
+		error = kern_path_at(olddfd, old, how, &old_path);
+		if (error)
+			break;
+
+		new_dentry = kern_path_create(newdfd, new, &new_path, 0, try);
+		error = PTR_ERR(new_dentry);
+		if (IS_ERR(new_dentry)) {
+			path_put(&old_path);
+			break;
+		}
+
+		error = -EXDEV;
+		if (old_path.mnt != new_path.mnt)
+			goto out_dput;
+		error = mnt_want_write(new_path.mnt);
+		if (error)
+			goto out_dput;
+		error = security_path_link(old_path.dentry, &new_path,
+					new_dentry);
+		if (error)
+			goto out_drop_write;
+		error = vfs_link(old_path.dentry, new_path.dentry->d_inode,
+				new_dentry);
 out_drop_write:
-	mnt_drop_write(new_path.mnt);
+		mnt_drop_write(new_path.mnt);
 out_dput:
-	dput(new_dentry);
-	mutex_unlock(&new_path.dentry->d_inode->i_mutex);
-	path_put(&new_path);
-out:
-	path_put(&old_path);
-
+		dput(new_dentry);
+		mutex_unlock(&new_path.dentry->d_inode->i_mutex);
+		path_put(&new_path);
+		path_put(&old_path);
+		how |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
+	putname(new);
+	putname(old);
 	return error;
 }
 
-- 
1.7.7.6


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

* [PATCH v2 12/15] vfs: make rmdir retry on ESTALE errors
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (10 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 11/15] vfs: fix linkat " Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 13/15] vfs: make do_unlinkat " Jeff Layton
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

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

diff --git a/fs/namei.c b/fs/namei.c
index 402f469..a11fcc7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2778,52 +2778,62 @@ out:
 static long do_rmdir(int dfd, const char __user *pathname)
 {
 	int error = 0;
-	char * name;
+	char *name;
 	struct dentry *dentry;
 	struct nameidata nd;
+	unsigned int try = 0;
+	unsigned int lookup_flags = LOOKUP_PARENT;
 
-	error = user_path_parent(dfd, pathname, &nd, &name);
-	if (error)
-		return error;
+	name = getname(pathname);
+	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 {
+		error = do_path_lookup(dfd, name, lookup_flags, &nd);
+		if (error)
+			break;
 
-	nd.flags &= ~LOOKUP_PARENT;
+		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;
+		}
 
-	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 = mnt_want_write(nd.path.mnt);
-	if (error)
-		goto exit3;
-	error = security_path_rmdir(&nd.path, dentry);
-	if (error)
-		goto exit4;
-	error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
+		nd.flags &= ~LOOKUP_PARENT;
+
+		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 = mnt_want_write(nd.path.mnt);
+		if (error)
+			goto exit3;
+		error = security_path_rmdir(&nd.path, dentry);
+		if (error)
+			goto exit4;
+		error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
 exit4:
-	mnt_drop_write(nd.path.mnt);
+		mnt_drop_write(nd.path.mnt);
 exit3:
-	dput(dentry);
+		dput(dentry);
 exit2:
-	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+		mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
 exit1:
-	path_put(&nd.path);
+		path_put(&nd.path);
+		lookup_flags |= LOOKUP_REVAL;
+	} while (retry_estale(error, try++));
 	putname(name);
 	return error;
 }
-- 
1.7.7.6


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

* [PATCH v2 13/15] vfs: make do_unlinkat retry on ESTALE errors
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (11 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 12/15] vfs: make rmdir " Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 14/15] vfs: fix renameat to " Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 15/15] vfs: remove user_path_parent Jeff Layton
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

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

diff --git a/fs/namei.c b/fs/namei.c
index a11fcc7..486a60a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2888,8 +2888,14 @@ 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;
 
-	error = user_path_parent(dfd, pathname, &nd, &name);
+	name = getname(pathname);
+	if (IS_ERR(name))
+		return PTR_ERR(name);
+retry:
+	error = do_path_lookup(dfd, name, lookup_flags, &nd);
 	if (error)
 		return error;
 
@@ -2927,6 +2933,10 @@ exit3:
 		iput(inode);	/* truncate the inode here */
 exit1:
 	path_put(&nd.path);
+	if (retry_estale(error, try++)) {
+		lookup_flags |= LOOKUP_REVAL;
+		goto retry;
+	}
 	putname(name);
 	return error;
 
-- 
1.7.7.6


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

* [PATCH v2 14/15] vfs: fix renameat to retry on ESTALE errors
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (12 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 13/15] vfs: make do_unlinkat " Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  2012-05-22 14:12 ` [PATCH v2 15/15] vfs: remove user_path_parent Jeff Layton
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, 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 |   31 ++++++++++++++++++++++++++-----
 1 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index 486a60a..4d2b810 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3325,12 +3325,25 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
 	char *from;
 	char *to;
 	int error;
+	unsigned int try = 0;
+	bool should_retry = false;
+	unsigned int lookup_flags = LOOKUP_PARENT;
 
-	error = user_path_parent(olddfd, oldname, &oldnd, &from);
-	if (error)
+	from = getname(oldname);
+	if (IS_ERR(from))
+		return PTR_ERR(from);
+
+	to = getname(newname);
+	if (IS_ERR(to)) {
+		error = PTR_ERR(to);
 		goto exit;
+	}
+retry:
+	error = do_path_lookup(olddfd, from, lookup_flags, &oldnd);
+	if (error)
+		goto exit0;
 
-	error = user_path_parent(newdfd, newname, &newnd, &to);
+	error = do_path_lookup(newdfd, to, lookup_flags, &newnd);
 	if (error)
 		goto exit1;
 
@@ -3399,13 +3412,21 @@ exit4:
 	dput(old_dentry);
 exit3:
 	unlock_rename(new_dir, old_dir);
+	if (retry_estale(error, try++))
+		should_retry = true;
 exit2:
 	path_put(&newnd.path);
-	putname(to);
 exit1:
 	path_put(&oldnd.path);
-	putname(from);
+	if (should_retry) {
+		should_retry = false;
+		lookup_flags |= LOOKUP_REVAL;
+		goto retry;
+	}
+exit0:
+	putname(to);
 exit:
+	putname(from);
 	return error;
 }
 
-- 
1.7.7.6


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

* [PATCH v2 15/15] vfs: remove user_path_parent
  2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
                   ` (13 preceding siblings ...)
  2012-05-22 14:12 ` [PATCH v2 14/15] vfs: fix renameat to " Jeff Layton
@ 2012-05-22 14:12 ` Jeff Layton
  14 siblings, 0 replies; 16+ messages in thread
From: Jeff Layton @ 2012-05-22 14:12 UTC (permalink / raw)
  To: viro
  Cc: inux-fsdevel, linux-nfs, linux-kernel, miklos, hch,
	michael.brantley, pstaubach

...there are no more callers.

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

diff --git a/fs/namei.c b/fs/namei.c
index 4d2b810..991306b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1915,24 +1915,6 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
 	return err;
 }
 
-static int user_path_parent(int dfd, const char __user *path,
-			struct nameidata *nd, char **name)
-{
-	char *s = getname(path);
-	int error;
-
-	if (IS_ERR(s))
-		return PTR_ERR(s);
-
-	error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd);
-	if (error)
-		putname(s);
-	else
-		*name = s;
-
-	return error;
-}
-
 /*
  * It's inline, so penalty for filesystems that don't use sticky bit is
  * minimal.
-- 
1.7.7.6


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

end of thread, other threads:[~2012-05-22 14:12 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-05-22 14:12 [PATCH v2 00/15] vfs: add the ability to retry on ESTALE to several syscalls Jeff Layton
2012-05-22 14:12 ` [PATCH v2 01/15] vfs: add a retry_estale helper function to handle retries on ESTALE Jeff Layton
2012-05-22 14:12 ` [PATCH v2 02/15] vfs: add a kern_path_at function Jeff Layton
2012-05-22 14:12 ` [PATCH v2 03/15] vfs: make fstatat retry on ESTALE errors from getattr call Jeff Layton
2012-05-22 14:12 ` [PATCH v2 04/15] vfs: fix readlinkat to retry on ESTALE Jeff Layton
2012-05-22 14:12 ` [PATCH v2 05/15] vfs: remove user_path_at_empty Jeff Layton
2012-05-22 14:12 ` [PATCH v2 06/15] vfs: turn "empty" arg in getname_flags into a bool Jeff Layton
2012-05-22 14:12 ` [PATCH v2 07/15] vfs: add new "reval" argument to kern_path_create Jeff Layton
2012-05-22 14:12 ` [PATCH v2 08/15] vfs: fix mknodat to retry on ESTALE errors Jeff Layton
2012-05-22 14:12 ` [PATCH v2 09/15] vfs: fix mkdir " Jeff Layton
2012-05-22 14:12 ` [PATCH v2 10/15] vfs: fix symlinkat " Jeff Layton
2012-05-22 14:12 ` [PATCH v2 11/15] vfs: fix linkat " Jeff Layton
2012-05-22 14:12 ` [PATCH v2 12/15] vfs: make rmdir " Jeff Layton
2012-05-22 14:12 ` [PATCH v2 13/15] vfs: make do_unlinkat " Jeff Layton
2012-05-22 14:12 ` [PATCH v2 14/15] vfs: fix renameat to " Jeff Layton
2012-05-22 14:12 ` [PATCH v2 15/15] vfs: remove user_path_parent 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).