diff options
Diffstat (limited to 'fs/autofs4/root.c')
-rw-r--r-- | fs/autofs4/root.c | 91 |
1 files changed, 57 insertions, 34 deletions
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); |