diff options
-rw-r--r-- | fs/namei.c | 63 |
1 files changed, 32 insertions, 31 deletions
diff --git a/fs/namei.c b/fs/namei.c index 941c8e8228c0..7346e99d9283 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -106,7 +106,7 @@ | |||
106 | * any extra contention... | 106 | * any extra contention... |
107 | */ | 107 | */ |
108 | 108 | ||
109 | static int link_path_walk(const char *name, struct nameidata *nd); | 109 | static int __link_path_walk(const char *name, struct nameidata *nd); |
110 | 110 | ||
111 | /* In order to reduce some races, while at the same time doing additional | 111 | /* In order to reduce some races, while at the same time doing additional |
112 | * checking and hopefully speeding things up, we copy filenames to the | 112 | * checking and hopefully speeding things up, we copy filenames to the |
@@ -563,6 +563,37 @@ walk_init_root(const char *name, struct nameidata *nd) | |||
563 | return 1; | 563 | return 1; |
564 | } | 564 | } |
565 | 565 | ||
566 | /* | ||
567 | * Wrapper to retry pathname resolution whenever the underlying | ||
568 | * file system returns an ESTALE. | ||
569 | * | ||
570 | * Retry the whole path once, forcing real lookup requests | ||
571 | * instead of relying on the dcache. | ||
572 | */ | ||
573 | static __always_inline int link_path_walk(const char *name, struct nameidata *nd) | ||
574 | { | ||
575 | struct path save = nd->path; | ||
576 | int result; | ||
577 | |||
578 | /* make sure the stuff we saved doesn't go away */ | ||
579 | dget(save.dentry); | ||
580 | mntget(save.mnt); | ||
581 | |||
582 | result = __link_path_walk(name, nd); | ||
583 | if (result == -ESTALE) { | ||
584 | /* nd->path had been dropped */ | ||
585 | nd->path = save; | ||
586 | dget(nd->path.dentry); | ||
587 | mntget(nd->path.mnt); | ||
588 | nd->flags |= LOOKUP_REVAL; | ||
589 | result = __link_path_walk(name, nd); | ||
590 | } | ||
591 | |||
592 | path_put(&save); | ||
593 | |||
594 | return result; | ||
595 | } | ||
596 | |||
566 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) | 597 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) |
567 | { | 598 | { |
568 | int res = 0; | 599 | int res = 0; |
@@ -1020,36 +1051,6 @@ return_err: | |||
1020 | return err; | 1051 | return err; |
1021 | } | 1052 | } |
1022 | 1053 | ||
1023 | /* | ||
1024 | * Wrapper to retry pathname resolution whenever the underlying | ||
1025 | * file system returns an ESTALE. | ||
1026 | * | ||
1027 | * Retry the whole path once, forcing real lookup requests | ||
1028 | * instead of relying on the dcache. | ||
1029 | */ | ||
1030 | static int link_path_walk(const char *name, struct nameidata *nd) | ||
1031 | { | ||
1032 | struct nameidata save = *nd; | ||
1033 | int result; | ||
1034 | |||
1035 | /* make sure the stuff we saved doesn't go away */ | ||
1036 | dget(save.path.dentry); | ||
1037 | mntget(save.path.mnt); | ||
1038 | |||
1039 | result = __link_path_walk(name, nd); | ||
1040 | if (result == -ESTALE) { | ||
1041 | *nd = save; | ||
1042 | dget(nd->path.dentry); | ||
1043 | mntget(nd->path.mnt); | ||
1044 | nd->flags |= LOOKUP_REVAL; | ||
1045 | result = __link_path_walk(name, nd); | ||
1046 | } | ||
1047 | |||
1048 | path_put(&save.path); | ||
1049 | |||
1050 | return result; | ||
1051 | } | ||
1052 | |||
1053 | static int path_walk(const char *name, struct nameidata *nd) | 1054 | static int path_walk(const char *name, struct nameidata *nd) |
1054 | { | 1055 | { |
1055 | current->total_link_count = 0; | 1056 | current->total_link_count = 0; |