diff options
Diffstat (limited to 'fs/nfs/namespace.c')
-rw-r--r-- | fs/nfs/namespace.c | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index db6aa3673cf3..78c0ebb0b07c 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -49,11 +49,17 @@ char *nfs_path(const char *base, | |||
49 | const struct dentry *dentry, | 49 | const struct dentry *dentry, |
50 | char *buffer, ssize_t buflen) | 50 | char *buffer, ssize_t buflen) |
51 | { | 51 | { |
52 | char *end = buffer+buflen; | 52 | char *end; |
53 | int namelen; | 53 | int namelen; |
54 | unsigned seq; | ||
54 | 55 | ||
56 | rename_retry: | ||
57 | end = buffer+buflen; | ||
55 | *--end = '\0'; | 58 | *--end = '\0'; |
56 | buflen--; | 59 | buflen--; |
60 | |||
61 | seq = read_seqbegin(&rename_lock); | ||
62 | rcu_read_lock(); | ||
57 | spin_lock(&dcache_lock); | 63 | spin_lock(&dcache_lock); |
58 | while (!IS_ROOT(dentry) && dentry != droot) { | 64 | while (!IS_ROOT(dentry) && dentry != droot) { |
59 | namelen = dentry->d_name.len; | 65 | namelen = dentry->d_name.len; |
@@ -66,6 +72,9 @@ char *nfs_path(const char *base, | |||
66 | dentry = dentry->d_parent; | 72 | dentry = dentry->d_parent; |
67 | } | 73 | } |
68 | spin_unlock(&dcache_lock); | 74 | spin_unlock(&dcache_lock); |
75 | rcu_read_unlock(); | ||
76 | if (read_seqretry(&rename_lock, seq)) | ||
77 | goto rename_retry; | ||
69 | if (*end != '/') { | 78 | if (*end != '/') { |
70 | if (--buflen < 0) | 79 | if (--buflen < 0) |
71 | goto Elong; | 80 | goto Elong; |
@@ -83,6 +92,9 @@ char *nfs_path(const char *base, | |||
83 | return end; | 92 | return end; |
84 | Elong_unlock: | 93 | Elong_unlock: |
85 | spin_unlock(&dcache_lock); | 94 | spin_unlock(&dcache_lock); |
95 | rcu_read_unlock(); | ||
96 | if (read_seqretry(&rename_lock, seq)) | ||
97 | goto rename_retry; | ||
86 | Elong: | 98 | Elong: |
87 | return ERR_PTR(-ENAMETOOLONG); | 99 | return ERR_PTR(-ENAMETOOLONG); |
88 | } | 100 | } |