aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/namei.c63
1 files changed, 32 insertions, 31 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 941c8e8228c..7346e99d928 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -106,7 +106,7 @@
* any extra contention...
*/
-static int link_path_walk(const char *name, struct nameidata *nd);
+static int __link_path_walk(const char *name, struct nameidata *nd);
/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
@@ -563,6 +563,37 @@ walk_init_root(const char *name, struct nameidata *nd)
return 1;
}
+/*
+ * Wrapper to retry pathname resolution whenever the underlying
+ * file system returns an ESTALE.
+ *
+ * Retry the whole path once, forcing real lookup requests
+ * instead of relying on the dcache.
+ */
+static __always_inline int link_path_walk(const char *name, struct nameidata *nd)
+{
+ struct path save = nd->path;
+ int result;
+
+ /* make sure the stuff we saved doesn't go away */
+ dget(save.dentry);
+ mntget(save.mnt);
+
+ result = __link_path_walk(name, nd);
+ if (result == -ESTALE) {
+ /* nd->path had been dropped */
+ nd->path = save;
+ dget(nd->path.dentry);
+ mntget(nd->path.mnt);
+ nd->flags |= LOOKUP_REVAL;
+ result = __link_path_walk(name, nd);
+ }
+
+ path_put(&save);
+
+ return result;
+}
+
static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
{
int res = 0;
@@ -1020,36 +1051,6 @@ return_err:
return err;
}
-/*
- * Wrapper to retry pathname resolution whenever the underlying
- * file system returns an ESTALE.
- *
- * Retry the whole path once, forcing real lookup requests
- * instead of relying on the dcache.
- */
-static int link_path_walk(const char *name, struct nameidata *nd)
-{
- struct nameidata save = *nd;
- int result;
-
- /* make sure the stuff we saved doesn't go away */
- dget(save.path.dentry);
- mntget(save.path.mnt);
-
- result = __link_path_walk(name, nd);
- if (result == -ESTALE) {
- *nd = save;
- dget(nd->path.dentry);
- mntget(nd->path.mnt);
- nd->flags |= LOOKUP_REVAL;
- result = __link_path_walk(name, nd);
- }
-
- path_put(&save.path);
-
- return result;
-}
-
static int path_walk(const char *name, struct nameidata *nd)
{
current->total_link_count = 0;