diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-07 11:56:33 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-07 11:56:33 -0500 |
commit | b4a45f5fe8078bfc10837dbd5b98735058bc4698 (patch) | |
tree | df6f13a27610a3ec7eb4a661448cd779a8f84c79 /fs/autofs4 | |
parent | 01539ba2a706ab7d35fc0667dff919ade7f87d63 (diff) | |
parent | b3e19d924b6eaf2ca7d22cba99a517c5171007b6 (diff) |
Merge branch 'vfs-scale-working' of git://git.kernel.org/pub/scm/linux/kernel/git/npiggin/linux-npiggin
* 'vfs-scale-working' of git://git.kernel.org/pub/scm/linux/kernel/git/npiggin/linux-npiggin: (57 commits)
fs: scale mntget/mntput
fs: rename vfsmount counter helpers
fs: implement faster dentry memcmp
fs: prefetch inode data in dcache lookup
fs: improve scalability of pseudo filesystems
fs: dcache per-inode inode alias locking
fs: dcache per-bucket dcache hash locking
bit_spinlock: add required includes
kernel: add bl_list
xfs: provide simple rcu-walk ACL implementation
btrfs: provide simple rcu-walk ACL implementation
ext2,3,4: provide simple rcu-walk ACL implementation
fs: provide simple rcu-walk generic_check_acl implementation
fs: provide rcu-walk aware permission i_ops
fs: rcu-walk aware d_revalidate method
fs: cache optimise dentry and inode for rcu-walk
fs: dcache reduce branches in lookup path
fs: dcache remove d_mounted
fs: fs_struct use seqlock
fs: rcu-walk for path lookup
...
Diffstat (limited to 'fs/autofs4')
-rw-r--r-- | fs/autofs4/autofs_i.h | 21 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 141 | ||||
-rw-r--r-- | fs/autofs4/inode.c | 2 | ||||
-rw-r--r-- | fs/autofs4/root.c | 91 | ||||
-rw-r--r-- | fs/autofs4/waitq.c | 23 |
5 files changed, 164 insertions, 114 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 3d283abf67d7..0fffe1c24cec 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/auto_fs4.h> | 16 | #include <linux/auto_fs4.h> |
17 | #include <linux/auto_dev-ioctl.h> | 17 | #include <linux/auto_dev-ioctl.h> |
18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
19 | #include <linux/spinlock.h> | ||
19 | #include <linux/list.h> | 20 | #include <linux/list.h> |
20 | 21 | ||
21 | /* This is the range of ioctl() numbers we claim as ours */ | 22 | /* This is the range of ioctl() numbers we claim as ours */ |
@@ -60,6 +61,8 @@ do { \ | |||
60 | current->pid, __func__, ##args); \ | 61 | current->pid, __func__, ##args); \ |
61 | } while (0) | 62 | } while (0) |
62 | 63 | ||
64 | extern spinlock_t autofs4_lock; | ||
65 | |||
63 | /* Unified info structure. This is pointed to by both the dentry and | 66 | /* Unified info structure. This is pointed to by both the dentry and |
64 | inode structures. Each file in the filesystem has an instance of this | 67 | inode structures. Each file in the filesystem has an instance of this |
65 | structure. It holds a reference to the dentry, so dentries are never | 68 | structure. It holds a reference to the dentry, so dentries are never |
@@ -254,17 +257,15 @@ static inline int simple_positive(struct dentry *dentry) | |||
254 | return dentry->d_inode && !d_unhashed(dentry); | 257 | return dentry->d_inode && !d_unhashed(dentry); |
255 | } | 258 | } |
256 | 259 | ||
257 | static inline int __simple_empty(struct dentry *dentry) | 260 | static inline void __autofs4_add_expiring(struct dentry *dentry) |
258 | { | 261 | { |
259 | struct dentry *child; | 262 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
260 | int ret = 0; | 263 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
261 | 264 | if (ino) { | |
262 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) | 265 | if (list_empty(&ino->expiring)) |
263 | if (simple_positive(child)) | 266 | list_add(&ino->expiring, &sbi->expiring_list); |
264 | goto out; | 267 | } |
265 | ret = 1; | 268 | return; |
266 | out: | ||
267 | return ret; | ||
268 | } | 269 | } |
269 | 270 | ||
270 | static inline void autofs4_add_expiring(struct dentry *dentry) | 271 | static inline void autofs4_add_expiring(struct dentry *dentry) |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index a796c9417fb1..cc1d01365905 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -91,24 +91,64 @@ done: | |||
91 | } | 91 | } |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * Calculate next entry in top down tree traversal. | 94 | * Calculate and dget next entry in top down tree traversal. |
95 | * From next_mnt in namespace.c - elegant. | ||
96 | */ | 95 | */ |
97 | static struct dentry *next_dentry(struct dentry *p, struct dentry *root) | 96 | static struct dentry *get_next_positive_dentry(struct dentry *prev, |
97 | struct dentry *root) | ||
98 | { | 98 | { |
99 | struct list_head *next = p->d_subdirs.next; | 99 | struct list_head *next; |
100 | struct dentry *p, *ret; | ||
101 | |||
102 | if (prev == NULL) | ||
103 | return dget(prev); | ||
100 | 104 | ||
105 | spin_lock(&autofs4_lock); | ||
106 | relock: | ||
107 | p = prev; | ||
108 | spin_lock(&p->d_lock); | ||
109 | again: | ||
110 | next = p->d_subdirs.next; | ||
101 | if (next == &p->d_subdirs) { | 111 | if (next == &p->d_subdirs) { |
102 | while (1) { | 112 | while (1) { |
103 | if (p == root) | 113 | struct dentry *parent; |
114 | |||
115 | if (p == root) { | ||
116 | spin_unlock(&p->d_lock); | ||
117 | spin_unlock(&autofs4_lock); | ||
118 | dput(prev); | ||
104 | return NULL; | 119 | return NULL; |
120 | } | ||
121 | |||
122 | parent = p->d_parent; | ||
123 | if (!spin_trylock(&parent->d_lock)) { | ||
124 | spin_unlock(&p->d_lock); | ||
125 | cpu_relax(); | ||
126 | goto relock; | ||
127 | } | ||
128 | spin_unlock(&p->d_lock); | ||
105 | next = p->d_u.d_child.next; | 129 | next = p->d_u.d_child.next; |
106 | if (next != &p->d_parent->d_subdirs) | 130 | p = parent; |
131 | if (next != &parent->d_subdirs) | ||
107 | break; | 132 | break; |
108 | p = p->d_parent; | ||
109 | } | 133 | } |
110 | } | 134 | } |
111 | return list_entry(next, struct dentry, d_u.d_child); | 135 | ret = list_entry(next, struct dentry, d_u.d_child); |
136 | |||
137 | spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED); | ||
138 | /* Negative dentry - try next */ | ||
139 | if (!simple_positive(ret)) { | ||
140 | spin_unlock(&ret->d_lock); | ||
141 | p = ret; | ||
142 | goto again; | ||
143 | } | ||
144 | dget_dlock(ret); | ||
145 | spin_unlock(&ret->d_lock); | ||
146 | spin_unlock(&p->d_lock); | ||
147 | spin_unlock(&autofs4_lock); | ||
148 | |||
149 | dput(prev); | ||
150 | |||
151 | return ret; | ||
112 | } | 152 | } |
113 | 153 | ||
114 | /* | 154 | /* |
@@ -158,18 +198,11 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
158 | if (!simple_positive(top)) | 198 | if (!simple_positive(top)) |
159 | return 1; | 199 | return 1; |
160 | 200 | ||
161 | spin_lock(&dcache_lock); | 201 | p = NULL; |
162 | for (p = top; p; p = next_dentry(p, top)) { | 202 | while ((p = get_next_positive_dentry(p, top))) { |
163 | /* Negative dentry - give up */ | ||
164 | if (!simple_positive(p)) | ||
165 | continue; | ||
166 | |||
167 | DPRINTK("dentry %p %.*s", | 203 | DPRINTK("dentry %p %.*s", |
168 | p, (int) p->d_name.len, p->d_name.name); | 204 | p, (int) p->d_name.len, p->d_name.name); |
169 | 205 | ||
170 | p = dget(p); | ||
171 | spin_unlock(&dcache_lock); | ||
172 | |||
173 | /* | 206 | /* |
174 | * Is someone visiting anywhere in the subtree ? | 207 | * Is someone visiting anywhere in the subtree ? |
175 | * If there's no mount we need to check the usage | 208 | * If there's no mount we need to check the usage |
@@ -198,16 +231,13 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
198 | else | 231 | else |
199 | ino_count++; | 232 | ino_count++; |
200 | 233 | ||
201 | if (atomic_read(&p->d_count) > ino_count) { | 234 | if (p->d_count > ino_count) { |
202 | top_ino->last_used = jiffies; | 235 | top_ino->last_used = jiffies; |
203 | dput(p); | 236 | dput(p); |
204 | return 1; | 237 | return 1; |
205 | } | 238 | } |
206 | } | 239 | } |
207 | dput(p); | ||
208 | spin_lock(&dcache_lock); | ||
209 | } | 240 | } |
210 | spin_unlock(&dcache_lock); | ||
211 | 241 | ||
212 | /* Timeout of a tree mount is ultimately determined by its top dentry */ | 242 | /* Timeout of a tree mount is ultimately determined by its top dentry */ |
213 | if (!autofs4_can_expire(top, timeout, do_now)) | 243 | if (!autofs4_can_expire(top, timeout, do_now)) |
@@ -226,32 +256,21 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, | |||
226 | DPRINTK("parent %p %.*s", | 256 | DPRINTK("parent %p %.*s", |
227 | parent, (int)parent->d_name.len, parent->d_name.name); | 257 | parent, (int)parent->d_name.len, parent->d_name.name); |
228 | 258 | ||
229 | spin_lock(&dcache_lock); | 259 | p = NULL; |
230 | for (p = parent; p; p = next_dentry(p, parent)) { | 260 | while ((p = get_next_positive_dentry(p, parent))) { |
231 | /* Negative dentry - give up */ | ||
232 | if (!simple_positive(p)) | ||
233 | continue; | ||
234 | |||
235 | DPRINTK("dentry %p %.*s", | 261 | DPRINTK("dentry %p %.*s", |
236 | p, (int) p->d_name.len, p->d_name.name); | 262 | p, (int) p->d_name.len, p->d_name.name); |
237 | 263 | ||
238 | p = dget(p); | ||
239 | spin_unlock(&dcache_lock); | ||
240 | |||
241 | if (d_mountpoint(p)) { | 264 | if (d_mountpoint(p)) { |
242 | /* Can we umount this guy */ | 265 | /* Can we umount this guy */ |
243 | if (autofs4_mount_busy(mnt, p)) | 266 | if (autofs4_mount_busy(mnt, p)) |
244 | goto cont; | 267 | continue; |
245 | 268 | ||
246 | /* Can we expire this guy */ | 269 | /* Can we expire this guy */ |
247 | if (autofs4_can_expire(p, timeout, do_now)) | 270 | if (autofs4_can_expire(p, timeout, do_now)) |
248 | return p; | 271 | return p; |
249 | } | 272 | } |
250 | cont: | ||
251 | dput(p); | ||
252 | spin_lock(&dcache_lock); | ||
253 | } | 273 | } |
254 | spin_unlock(&dcache_lock); | ||
255 | return NULL; | 274 | return NULL; |
256 | } | 275 | } |
257 | 276 | ||
@@ -276,7 +295,9 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
276 | struct autofs_info *ino = autofs4_dentry_ino(root); | 295 | struct autofs_info *ino = autofs4_dentry_ino(root); |
277 | if (d_mountpoint(root)) { | 296 | if (d_mountpoint(root)) { |
278 | ino->flags |= AUTOFS_INF_MOUNTPOINT; | 297 | ino->flags |= AUTOFS_INF_MOUNTPOINT; |
279 | root->d_mounted--; | 298 | spin_lock(&root->d_lock); |
299 | root->d_flags &= ~DCACHE_MOUNTED; | ||
300 | spin_unlock(&root->d_lock); | ||
280 | } | 301 | } |
281 | ino->flags |= AUTOFS_INF_EXPIRING; | 302 | ino->flags |= AUTOFS_INF_EXPIRING; |
282 | init_completion(&ino->expire_complete); | 303 | init_completion(&ino->expire_complete); |
@@ -302,8 +323,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
302 | { | 323 | { |
303 | unsigned long timeout; | 324 | unsigned long timeout; |
304 | struct dentry *root = sb->s_root; | 325 | struct dentry *root = sb->s_root; |
326 | struct dentry *dentry; | ||
305 | struct dentry *expired = NULL; | 327 | struct dentry *expired = NULL; |
306 | struct list_head *next; | ||
307 | int do_now = how & AUTOFS_EXP_IMMEDIATE; | 328 | int do_now = how & AUTOFS_EXP_IMMEDIATE; |
308 | int exp_leaves = how & AUTOFS_EXP_LEAVES; | 329 | int exp_leaves = how & AUTOFS_EXP_LEAVES; |
309 | struct autofs_info *ino; | 330 | struct autofs_info *ino; |
@@ -315,23 +336,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
315 | now = jiffies; | 336 | now = jiffies; |
316 | timeout = sbi->exp_timeout; | 337 | timeout = sbi->exp_timeout; |
317 | 338 | ||
318 | spin_lock(&dcache_lock); | 339 | dentry = NULL; |
319 | next = root->d_subdirs.next; | 340 | while ((dentry = get_next_positive_dentry(dentry, root))) { |
320 | |||
321 | /* On exit from the loop expire is set to a dgot dentry | ||
322 | * to expire or it's NULL */ | ||
323 | while ( next != &root->d_subdirs ) { | ||
324 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | ||
325 | |||
326 | /* Negative dentry - give up */ | ||
327 | if (!simple_positive(dentry)) { | ||
328 | next = next->next; | ||
329 | continue; | ||
330 | } | ||
331 | |||
332 | dentry = dget(dentry); | ||
333 | spin_unlock(&dcache_lock); | ||
334 | |||
335 | spin_lock(&sbi->fs_lock); | 341 | spin_lock(&sbi->fs_lock); |
336 | ino = autofs4_dentry_ino(dentry); | 342 | ino = autofs4_dentry_ino(dentry); |
337 | 343 | ||
@@ -347,7 +353,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
347 | 353 | ||
348 | /* Path walk currently on this dentry? */ | 354 | /* Path walk currently on this dentry? */ |
349 | ino_count = atomic_read(&ino->count) + 2; | 355 | ino_count = atomic_read(&ino->count) + 2; |
350 | if (atomic_read(&dentry->d_count) > ino_count) | 356 | if (dentry->d_count > ino_count) |
351 | goto next; | 357 | goto next; |
352 | 358 | ||
353 | /* Can we umount this guy */ | 359 | /* Can we umount this guy */ |
@@ -369,7 +375,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
369 | if (!exp_leaves) { | 375 | if (!exp_leaves) { |
370 | /* Path walk currently on this dentry? */ | 376 | /* Path walk currently on this dentry? */ |
371 | ino_count = atomic_read(&ino->count) + 1; | 377 | ino_count = atomic_read(&ino->count) + 1; |
372 | if (atomic_read(&dentry->d_count) > ino_count) | 378 | if (dentry->d_count > ino_count) |
373 | goto next; | 379 | goto next; |
374 | 380 | ||
375 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { | 381 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { |
@@ -383,7 +389,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
383 | } else { | 389 | } else { |
384 | /* Path walk currently on this dentry? */ | 390 | /* Path walk currently on this dentry? */ |
385 | ino_count = atomic_read(&ino->count) + 1; | 391 | ino_count = atomic_read(&ino->count) + 1; |
386 | if (atomic_read(&dentry->d_count) > ino_count) | 392 | if (dentry->d_count > ino_count) |
387 | goto next; | 393 | goto next; |
388 | 394 | ||
389 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); | 395 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); |
@@ -394,11 +400,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
394 | } | 400 | } |
395 | next: | 401 | next: |
396 | spin_unlock(&sbi->fs_lock); | 402 | spin_unlock(&sbi->fs_lock); |
397 | dput(dentry); | ||
398 | spin_lock(&dcache_lock); | ||
399 | next = next->next; | ||
400 | } | 403 | } |
401 | spin_unlock(&dcache_lock); | ||
402 | return NULL; | 404 | return NULL; |
403 | 405 | ||
404 | found: | 406 | found: |
@@ -408,9 +410,13 @@ found: | |||
408 | ino->flags |= AUTOFS_INF_EXPIRING; | 410 | ino->flags |= AUTOFS_INF_EXPIRING; |
409 | init_completion(&ino->expire_complete); | 411 | init_completion(&ino->expire_complete); |
410 | spin_unlock(&sbi->fs_lock); | 412 | spin_unlock(&sbi->fs_lock); |
411 | spin_lock(&dcache_lock); | 413 | spin_lock(&autofs4_lock); |
414 | spin_lock(&expired->d_parent->d_lock); | ||
415 | spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED); | ||
412 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); | 416 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); |
413 | spin_unlock(&dcache_lock); | 417 | spin_unlock(&expired->d_lock); |
418 | spin_unlock(&expired->d_parent->d_lock); | ||
419 | spin_unlock(&autofs4_lock); | ||
414 | return expired; | 420 | return expired; |
415 | } | 421 | } |
416 | 422 | ||
@@ -499,7 +505,14 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
499 | 505 | ||
500 | spin_lock(&sbi->fs_lock); | 506 | spin_lock(&sbi->fs_lock); |
501 | if (ino->flags & AUTOFS_INF_MOUNTPOINT) { | 507 | if (ino->flags & AUTOFS_INF_MOUNTPOINT) { |
502 | sb->s_root->d_mounted++; | 508 | spin_lock(&sb->s_root->d_lock); |
509 | /* | ||
510 | * If we haven't been expired away, then reset | ||
511 | * mounted status. | ||
512 | */ | ||
513 | if (mnt->mnt_parent != mnt) | ||
514 | sb->s_root->d_flags |= DCACHE_MOUNTED; | ||
515 | spin_unlock(&sb->s_root->d_lock); | ||
503 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; | 516 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; |
504 | } | 517 | } |
505 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 518 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index ac87e49fa706..a7bdb9dcac84 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -309,7 +309,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
309 | goto fail_iput; | 309 | goto fail_iput; |
310 | pipe = NULL; | 310 | pipe = NULL; |
311 | 311 | ||
312 | root->d_op = &autofs4_sb_dentry_operations; | 312 | d_set_d_op(root, &autofs4_sb_dentry_operations); |
313 | root->d_fsdata = ino; | 313 | root->d_fsdata = ino; |
314 | 314 | ||
315 | /* Can this call block? */ | 315 | /* Can this call block? */ |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index d34896cfb19f..651e4ef563b1 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -23,6 +23,8 @@ | |||
23 | 23 | ||
24 | #include "autofs_i.h" | 24 | #include "autofs_i.h" |
25 | 25 | ||
26 | DEFINE_SPINLOCK(autofs4_lock); | ||
27 | |||
26 | static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); | 28 | static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); |
27 | static int autofs4_dir_unlink(struct inode *,struct dentry *); | 29 | static int autofs4_dir_unlink(struct inode *,struct dentry *); |
28 | static int autofs4_dir_rmdir(struct inode *,struct dentry *); | 30 | static int autofs4_dir_rmdir(struct inode *,struct dentry *); |
@@ -142,12 +144,15 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
142 | * autofs file system so just let the libfs routines handle | 144 | * autofs file system so just let the libfs routines handle |
143 | * it. | 145 | * it. |
144 | */ | 146 | */ |
145 | spin_lock(&dcache_lock); | 147 | spin_lock(&autofs4_lock); |
148 | spin_lock(&dentry->d_lock); | ||
146 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | 149 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
147 | spin_unlock(&dcache_lock); | 150 | spin_unlock(&dentry->d_lock); |
151 | spin_unlock(&autofs4_lock); | ||
148 | return -ENOENT; | 152 | return -ENOENT; |
149 | } | 153 | } |
150 | spin_unlock(&dcache_lock); | 154 | spin_unlock(&dentry->d_lock); |
155 | spin_unlock(&autofs4_lock); | ||
151 | 156 | ||
152 | out: | 157 | out: |
153 | return dcache_dir_open(inode, file); | 158 | return dcache_dir_open(inode, file); |
@@ -252,9 +257,11 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
252 | /* We trigger a mount for almost all flags */ | 257 | /* We trigger a mount for almost all flags */ |
253 | lookup_type = autofs4_need_mount(nd->flags); | 258 | lookup_type = autofs4_need_mount(nd->flags); |
254 | spin_lock(&sbi->fs_lock); | 259 | spin_lock(&sbi->fs_lock); |
255 | spin_lock(&dcache_lock); | 260 | spin_lock(&autofs4_lock); |
261 | spin_lock(&dentry->d_lock); | ||
256 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { | 262 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { |
257 | spin_unlock(&dcache_lock); | 263 | spin_unlock(&dentry->d_lock); |
264 | spin_unlock(&autofs4_lock); | ||
258 | spin_unlock(&sbi->fs_lock); | 265 | spin_unlock(&sbi->fs_lock); |
259 | goto follow; | 266 | goto follow; |
260 | } | 267 | } |
@@ -266,7 +273,8 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
266 | */ | 273 | */ |
267 | if (ino->flags & AUTOFS_INF_PENDING || | 274 | if (ino->flags & AUTOFS_INF_PENDING || |
268 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { | 275 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { |
269 | spin_unlock(&dcache_lock); | 276 | spin_unlock(&dentry->d_lock); |
277 | spin_unlock(&autofs4_lock); | ||
270 | spin_unlock(&sbi->fs_lock); | 278 | spin_unlock(&sbi->fs_lock); |
271 | 279 | ||
272 | status = try_to_fill_dentry(dentry, nd->flags); | 280 | status = try_to_fill_dentry(dentry, nd->flags); |
@@ -275,7 +283,8 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
275 | 283 | ||
276 | goto follow; | 284 | goto follow; |
277 | } | 285 | } |
278 | spin_unlock(&dcache_lock); | 286 | spin_unlock(&dentry->d_lock); |
287 | spin_unlock(&autofs4_lock); | ||
279 | spin_unlock(&sbi->fs_lock); | 288 | spin_unlock(&sbi->fs_lock); |
280 | follow: | 289 | follow: |
281 | /* | 290 | /* |
@@ -306,12 +315,19 @@ out_error: | |||
306 | */ | 315 | */ |
307 | static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | 316 | static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) |
308 | { | 317 | { |
309 | struct inode *dir = dentry->d_parent->d_inode; | 318 | struct inode *dir; |
310 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 319 | struct autofs_sb_info *sbi; |
311 | int oz_mode = autofs4_oz_mode(sbi); | 320 | int oz_mode; |
312 | int flags = nd ? nd->flags : 0; | 321 | int flags = nd ? nd->flags : 0; |
313 | int status = 1; | 322 | int status = 1; |
314 | 323 | ||
324 | if (flags & LOOKUP_RCU) | ||
325 | return -ECHILD; | ||
326 | |||
327 | dir = dentry->d_parent->d_inode; | ||
328 | sbi = autofs4_sbi(dir->i_sb); | ||
329 | oz_mode = autofs4_oz_mode(sbi); | ||
330 | |||
315 | /* Pending dentry */ | 331 | /* Pending dentry */ |
316 | spin_lock(&sbi->fs_lock); | 332 | spin_lock(&sbi->fs_lock); |
317 | if (autofs4_ispending(dentry)) { | 333 | if (autofs4_ispending(dentry)) { |
@@ -346,12 +362,14 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
346 | return 0; | 362 | return 0; |
347 | 363 | ||
348 | /* Check for a non-mountpoint directory with no contents */ | 364 | /* Check for a non-mountpoint directory with no contents */ |
349 | spin_lock(&dcache_lock); | 365 | spin_lock(&autofs4_lock); |
366 | spin_lock(&dentry->d_lock); | ||
350 | if (S_ISDIR(dentry->d_inode->i_mode) && | 367 | if (S_ISDIR(dentry->d_inode->i_mode) && |
351 | !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | 368 | !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
352 | DPRINTK("dentry=%p %.*s, emptydir", | 369 | DPRINTK("dentry=%p %.*s, emptydir", |
353 | dentry, dentry->d_name.len, dentry->d_name.name); | 370 | dentry, dentry->d_name.len, dentry->d_name.name); |
354 | spin_unlock(&dcache_lock); | 371 | spin_unlock(&dentry->d_lock); |
372 | spin_unlock(&autofs4_lock); | ||
355 | 373 | ||
356 | /* The daemon never causes a mount to trigger */ | 374 | /* The daemon never causes a mount to trigger */ |
357 | if (oz_mode) | 375 | if (oz_mode) |
@@ -367,7 +385,8 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
367 | 385 | ||
368 | return status; | 386 | return status; |
369 | } | 387 | } |
370 | spin_unlock(&dcache_lock); | 388 | spin_unlock(&dentry->d_lock); |
389 | spin_unlock(&autofs4_lock); | ||
371 | 390 | ||
372 | return 1; | 391 | return 1; |
373 | } | 392 | } |
@@ -422,7 +441,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
422 | const unsigned char *str = name->name; | 441 | const unsigned char *str = name->name; |
423 | struct list_head *p, *head; | 442 | struct list_head *p, *head; |
424 | 443 | ||
425 | spin_lock(&dcache_lock); | 444 | spin_lock(&autofs4_lock); |
426 | spin_lock(&sbi->lookup_lock); | 445 | spin_lock(&sbi->lookup_lock); |
427 | head = &sbi->active_list; | 446 | head = &sbi->active_list; |
428 | list_for_each(p, head) { | 447 | list_for_each(p, head) { |
@@ -436,7 +455,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
436 | spin_lock(&active->d_lock); | 455 | spin_lock(&active->d_lock); |
437 | 456 | ||
438 | /* Already gone? */ | 457 | /* Already gone? */ |
439 | if (atomic_read(&active->d_count) == 0) | 458 | if (active->d_count == 0) |
440 | goto next; | 459 | goto next; |
441 | 460 | ||
442 | qstr = &active->d_name; | 461 | qstr = &active->d_name; |
@@ -452,17 +471,17 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
452 | goto next; | 471 | goto next; |
453 | 472 | ||
454 | if (d_unhashed(active)) { | 473 | if (d_unhashed(active)) { |
455 | dget(active); | 474 | dget_dlock(active); |
456 | spin_unlock(&active->d_lock); | 475 | spin_unlock(&active->d_lock); |
457 | spin_unlock(&sbi->lookup_lock); | 476 | spin_unlock(&sbi->lookup_lock); |
458 | spin_unlock(&dcache_lock); | 477 | spin_unlock(&autofs4_lock); |
459 | return active; | 478 | return active; |
460 | } | 479 | } |
461 | next: | 480 | next: |
462 | spin_unlock(&active->d_lock); | 481 | spin_unlock(&active->d_lock); |
463 | } | 482 | } |
464 | spin_unlock(&sbi->lookup_lock); | 483 | spin_unlock(&sbi->lookup_lock); |
465 | spin_unlock(&dcache_lock); | 484 | spin_unlock(&autofs4_lock); |
466 | 485 | ||
467 | return NULL; | 486 | return NULL; |
468 | } | 487 | } |
@@ -477,7 +496,7 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) | |||
477 | const unsigned char *str = name->name; | 496 | const unsigned char *str = name->name; |
478 | struct list_head *p, *head; | 497 | struct list_head *p, *head; |
479 | 498 | ||
480 | spin_lock(&dcache_lock); | 499 | spin_lock(&autofs4_lock); |
481 | spin_lock(&sbi->lookup_lock); | 500 | spin_lock(&sbi->lookup_lock); |
482 | head = &sbi->expiring_list; | 501 | head = &sbi->expiring_list; |
483 | list_for_each(p, head) { | 502 | list_for_each(p, head) { |
@@ -507,17 +526,17 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) | |||
507 | goto next; | 526 | goto next; |
508 | 527 | ||
509 | if (d_unhashed(expiring)) { | 528 | if (d_unhashed(expiring)) { |
510 | dget(expiring); | 529 | dget_dlock(expiring); |
511 | spin_unlock(&expiring->d_lock); | 530 | spin_unlock(&expiring->d_lock); |
512 | spin_unlock(&sbi->lookup_lock); | 531 | spin_unlock(&sbi->lookup_lock); |
513 | spin_unlock(&dcache_lock); | 532 | spin_unlock(&autofs4_lock); |
514 | return expiring; | 533 | return expiring; |
515 | } | 534 | } |
516 | next: | 535 | next: |
517 | spin_unlock(&expiring->d_lock); | 536 | spin_unlock(&expiring->d_lock); |
518 | } | 537 | } |
519 | spin_unlock(&sbi->lookup_lock); | 538 | spin_unlock(&sbi->lookup_lock); |
520 | spin_unlock(&dcache_lock); | 539 | spin_unlock(&autofs4_lock); |
521 | 540 | ||
522 | return NULL; | 541 | return NULL; |
523 | } | 542 | } |
@@ -559,7 +578,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
559 | * we check for the hashed dentry and return the newly | 578 | * we check for the hashed dentry and return the newly |
560 | * hashed dentry. | 579 | * hashed dentry. |
561 | */ | 580 | */ |
562 | dentry->d_op = &autofs4_root_dentry_operations; | 581 | d_set_d_op(dentry, &autofs4_root_dentry_operations); |
563 | 582 | ||
564 | /* | 583 | /* |
565 | * And we need to ensure that the same dentry is used for | 584 | * And we need to ensure that the same dentry is used for |
@@ -698,9 +717,9 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
698 | d_add(dentry, inode); | 717 | d_add(dentry, inode); |
699 | 718 | ||
700 | if (dir == dir->i_sb->s_root->d_inode) | 719 | if (dir == dir->i_sb->s_root->d_inode) |
701 | dentry->d_op = &autofs4_root_dentry_operations; | 720 | d_set_d_op(dentry, &autofs4_root_dentry_operations); |
702 | else | 721 | else |
703 | dentry->d_op = &autofs4_dentry_operations; | 722 | d_set_d_op(dentry, &autofs4_dentry_operations); |
704 | 723 | ||
705 | dentry->d_fsdata = ino; | 724 | dentry->d_fsdata = ino; |
706 | ino->dentry = dget(dentry); | 725 | ino->dentry = dget(dentry); |
@@ -753,12 +772,12 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
753 | 772 | ||
754 | dir->i_mtime = CURRENT_TIME; | 773 | dir->i_mtime = CURRENT_TIME; |
755 | 774 | ||
756 | spin_lock(&dcache_lock); | 775 | spin_lock(&autofs4_lock); |
757 | autofs4_add_expiring(dentry); | 776 | autofs4_add_expiring(dentry); |
758 | spin_lock(&dentry->d_lock); | 777 | spin_lock(&dentry->d_lock); |
759 | __d_drop(dentry); | 778 | __d_drop(dentry); |
760 | spin_unlock(&dentry->d_lock); | 779 | spin_unlock(&dentry->d_lock); |
761 | spin_unlock(&dcache_lock); | 780 | spin_unlock(&autofs4_lock); |
762 | 781 | ||
763 | return 0; | 782 | return 0; |
764 | } | 783 | } |
@@ -775,16 +794,20 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
775 | if (!autofs4_oz_mode(sbi)) | 794 | if (!autofs4_oz_mode(sbi)) |
776 | return -EACCES; | 795 | return -EACCES; |
777 | 796 | ||
778 | spin_lock(&dcache_lock); | 797 | spin_lock(&autofs4_lock); |
798 | spin_lock(&sbi->lookup_lock); | ||
799 | spin_lock(&dentry->d_lock); | ||
779 | if (!list_empty(&dentry->d_subdirs)) { | 800 | if (!list_empty(&dentry->d_subdirs)) { |
780 | spin_unlock(&dcache_lock); | 801 | spin_unlock(&dentry->d_lock); |
802 | spin_unlock(&sbi->lookup_lock); | ||
803 | spin_unlock(&autofs4_lock); | ||
781 | return -ENOTEMPTY; | 804 | return -ENOTEMPTY; |
782 | } | 805 | } |
783 | autofs4_add_expiring(dentry); | 806 | __autofs4_add_expiring(dentry); |
784 | spin_lock(&dentry->d_lock); | 807 | spin_unlock(&sbi->lookup_lock); |
785 | __d_drop(dentry); | 808 | __d_drop(dentry); |
786 | spin_unlock(&dentry->d_lock); | 809 | spin_unlock(&dentry->d_lock); |
787 | spin_unlock(&dcache_lock); | 810 | spin_unlock(&autofs4_lock); |
788 | 811 | ||
789 | if (atomic_dec_and_test(&ino->count)) { | 812 | if (atomic_dec_and_test(&ino->count)) { |
790 | p_ino = autofs4_dentry_ino(dentry->d_parent); | 813 | p_ino = autofs4_dentry_ino(dentry->d_parent); |
@@ -829,9 +852,9 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
829 | d_add(dentry, inode); | 852 | d_add(dentry, inode); |
830 | 853 | ||
831 | if (dir == dir->i_sb->s_root->d_inode) | 854 | if (dir == dir->i_sb->s_root->d_inode) |
832 | dentry->d_op = &autofs4_root_dentry_operations; | 855 | d_set_d_op(dentry, &autofs4_root_dentry_operations); |
833 | else | 856 | else |
834 | dentry->d_op = &autofs4_dentry_operations; | 857 | d_set_d_op(dentry, &autofs4_dentry_operations); |
835 | 858 | ||
836 | dentry->d_fsdata = ino; | 859 | dentry->d_fsdata = ino; |
837 | ino->dentry = dget(dentry); | 860 | ino->dentry = dget(dentry); |
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 2341375386f8..c5f8459c905e 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -186,16 +186,26 @@ static int autofs4_getpath(struct autofs_sb_info *sbi, | |||
186 | { | 186 | { |
187 | struct dentry *root = sbi->sb->s_root; | 187 | struct dentry *root = sbi->sb->s_root; |
188 | struct dentry *tmp; | 188 | struct dentry *tmp; |
189 | char *buf = *name; | 189 | char *buf; |
190 | char *p; | 190 | char *p; |
191 | int len = 0; | 191 | int len; |
192 | unsigned seq; | ||
192 | 193 | ||
193 | spin_lock(&dcache_lock); | 194 | rename_retry: |
195 | buf = *name; | ||
196 | len = 0; | ||
197 | |||
198 | seq = read_seqbegin(&rename_lock); | ||
199 | rcu_read_lock(); | ||
200 | spin_lock(&autofs4_lock); | ||
194 | for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) | 201 | for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) |
195 | len += tmp->d_name.len + 1; | 202 | len += tmp->d_name.len + 1; |
196 | 203 | ||
197 | if (!len || --len > NAME_MAX) { | 204 | if (!len || --len > NAME_MAX) { |
198 | spin_unlock(&dcache_lock); | 205 | spin_unlock(&autofs4_lock); |
206 | rcu_read_unlock(); | ||
207 | if (read_seqretry(&rename_lock, seq)) | ||
208 | goto rename_retry; | ||
199 | return 0; | 209 | return 0; |
200 | } | 210 | } |
201 | 211 | ||
@@ -208,7 +218,10 @@ static int autofs4_getpath(struct autofs_sb_info *sbi, | |||
208 | p -= tmp->d_name.len; | 218 | p -= tmp->d_name.len; |
209 | strncpy(p, tmp->d_name.name, tmp->d_name.len); | 219 | strncpy(p, tmp->d_name.name, tmp->d_name.len); |
210 | } | 220 | } |
211 | spin_unlock(&dcache_lock); | 221 | spin_unlock(&autofs4_lock); |
222 | rcu_read_unlock(); | ||
223 | if (read_seqretry(&rename_lock, seq)) | ||
224 | goto rename_retry; | ||
212 | 225 | ||
213 | return len; | 226 | return len; |
214 | } | 227 | } |