|
@@ -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;
|