diff options
Diffstat (limited to 'fs/autofs4')
-rw-r--r-- | fs/autofs4/autofs_i.h | 4 | ||||
-rw-r--r-- | fs/autofs4/inode.c | 9 | ||||
-rw-r--r-- | fs/autofs4/root.c | 171 |
3 files changed, 161 insertions, 23 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 6b4cec3f272f..d85f42fa9206 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -52,6 +52,8 @@ struct autofs_info { | |||
52 | 52 | ||
53 | int flags; | 53 | int flags; |
54 | 54 | ||
55 | struct list_head rehash; | ||
56 | |||
55 | struct autofs_sb_info *sbi; | 57 | struct autofs_sb_info *sbi; |
56 | unsigned long last_used; | 58 | unsigned long last_used; |
57 | atomic_t count; | 59 | atomic_t count; |
@@ -110,6 +112,8 @@ struct autofs_sb_info { | |||
110 | struct mutex wq_mutex; | 112 | struct mutex wq_mutex; |
111 | spinlock_t fs_lock; | 113 | spinlock_t fs_lock; |
112 | struct autofs_wait_queue *queues; /* Wait queue pointer */ | 114 | struct autofs_wait_queue *queues; /* Wait queue pointer */ |
115 | spinlock_t rehash_lock; | ||
116 | struct list_head rehash_list; | ||
113 | }; | 117 | }; |
114 | 118 | ||
115 | static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb) | 119 | static inline struct autofs_sb_info *autofs4_sbi(struct super_block *sb) |
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 5e458e096ef6..26063dc84a2a 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -48,6 +48,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, | |||
48 | ino->dentry = NULL; | 48 | ino->dentry = NULL; |
49 | ino->size = 0; | 49 | ino->size = 0; |
50 | 50 | ||
51 | INIT_LIST_HEAD(&ino->rehash); | ||
52 | |||
51 | ino->last_used = jiffies; | 53 | ino->last_used = jiffies; |
52 | atomic_set(&ino->count, 0); | 54 | atomic_set(&ino->count, 0); |
53 | 55 | ||
@@ -158,14 +160,13 @@ void autofs4_kill_sb(struct super_block *sb) | |||
158 | if (!sbi) | 160 | if (!sbi) |
159 | goto out_kill_sb; | 161 | goto out_kill_sb; |
160 | 162 | ||
161 | sb->s_fs_info = NULL; | 163 | if (!sbi->catatonic) |
162 | |||
163 | if ( !sbi->catatonic ) | ||
164 | autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */ | 164 | autofs4_catatonic_mode(sbi); /* Free wait queues, close pipe */ |
165 | 165 | ||
166 | /* Clean up and release dangling references */ | 166 | /* Clean up and release dangling references */ |
167 | autofs4_force_release(sbi); | 167 | autofs4_force_release(sbi); |
168 | 168 | ||
169 | sb->s_fs_info = NULL; | ||
169 | kfree(sbi); | 170 | kfree(sbi); |
170 | 171 | ||
171 | out_kill_sb: | 172 | out_kill_sb: |
@@ -336,6 +337,8 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
336 | mutex_init(&sbi->wq_mutex); | 337 | mutex_init(&sbi->wq_mutex); |
337 | spin_lock_init(&sbi->fs_lock); | 338 | spin_lock_init(&sbi->fs_lock); |
338 | sbi->queues = NULL; | 339 | sbi->queues = NULL; |
340 | spin_lock_init(&sbi->rehash_lock); | ||
341 | INIT_LIST_HEAD(&sbi->rehash_list); | ||
339 | s->s_blocksize = 1024; | 342 | s->s_blocksize = 1024; |
340 | s->s_blocksize_bits = 10; | 343 | s->s_blocksize_bits = 10; |
341 | s->s_magic = AUTOFS_SUPER_MAGIC; | 344 | s->s_magic = AUTOFS_SUPER_MAGIC; |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 47fee96c2182..47adf270106a 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -263,7 +263,7 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) | |||
263 | */ | 263 | */ |
264 | status = d_invalidate(dentry); | 264 | status = d_invalidate(dentry); |
265 | if (status != -EBUSY) | 265 | if (status != -EBUSY) |
266 | return -ENOENT; | 266 | return -EAGAIN; |
267 | } | 267 | } |
268 | 268 | ||
269 | DPRINTK("dentry=%p %.*s ino=%p", | 269 | DPRINTK("dentry=%p %.*s ino=%p", |
@@ -413,7 +413,16 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
413 | */ | 413 | */ |
414 | status = try_to_fill_dentry(dentry, flags); | 414 | status = try_to_fill_dentry(dentry, flags); |
415 | if (status == 0) | 415 | if (status == 0) |
416 | return 1; | 416 | return 1; |
417 | |||
418 | /* | ||
419 | * A status of EAGAIN here means that the dentry has gone | ||
420 | * away while waiting for an expire to complete. If we are | ||
421 | * racing with expire lookup will wait for it so this must | ||
422 | * be a revalidate and we need to send it to lookup. | ||
423 | */ | ||
424 | if (status == -EAGAIN) | ||
425 | return 0; | ||
417 | 426 | ||
418 | return status; | 427 | return status; |
419 | } | 428 | } |
@@ -459,9 +468,18 @@ void autofs4_dentry_release(struct dentry *de) | |||
459 | de->d_fsdata = NULL; | 468 | de->d_fsdata = NULL; |
460 | 469 | ||
461 | if (inf) { | 470 | if (inf) { |
471 | struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb); | ||
472 | |||
462 | inf->dentry = NULL; | 473 | inf->dentry = NULL; |
463 | inf->inode = NULL; | 474 | inf->inode = NULL; |
464 | 475 | ||
476 | if (sbi) { | ||
477 | spin_lock(&sbi->rehash_lock); | ||
478 | if (!list_empty(&inf->rehash)) | ||
479 | list_del(&inf->rehash); | ||
480 | spin_unlock(&sbi->rehash_lock); | ||
481 | } | ||
482 | |||
465 | autofs4_free_ino(inf); | 483 | autofs4_free_ino(inf); |
466 | } | 484 | } |
467 | } | 485 | } |
@@ -478,10 +496,80 @@ static struct dentry_operations autofs4_dentry_operations = { | |||
478 | .d_release = autofs4_dentry_release, | 496 | .d_release = autofs4_dentry_release, |
479 | }; | 497 | }; |
480 | 498 | ||
499 | static struct dentry *autofs4_lookup_unhashed(struct autofs_sb_info *sbi, struct dentry *parent, struct qstr *name) | ||
500 | { | ||
501 | unsigned int len = name->len; | ||
502 | unsigned int hash = name->hash; | ||
503 | const unsigned char *str = name->name; | ||
504 | struct list_head *p, *head; | ||
505 | |||
506 | spin_lock(&dcache_lock); | ||
507 | spin_lock(&sbi->rehash_lock); | ||
508 | head = &sbi->rehash_list; | ||
509 | list_for_each(p, head) { | ||
510 | struct autofs_info *ino; | ||
511 | struct dentry *dentry; | ||
512 | struct qstr *qstr; | ||
513 | |||
514 | ino = list_entry(p, struct autofs_info, rehash); | ||
515 | dentry = ino->dentry; | ||
516 | |||
517 | spin_lock(&dentry->d_lock); | ||
518 | |||
519 | /* Bad luck, we've already been dentry_iput */ | ||
520 | if (!dentry->d_inode) | ||
521 | goto next; | ||
522 | |||
523 | qstr = &dentry->d_name; | ||
524 | |||
525 | if (dentry->d_name.hash != hash) | ||
526 | goto next; | ||
527 | if (dentry->d_parent != parent) | ||
528 | goto next; | ||
529 | |||
530 | if (qstr->len != len) | ||
531 | goto next; | ||
532 | if (memcmp(qstr->name, str, len)) | ||
533 | goto next; | ||
534 | |||
535 | if (d_unhashed(dentry)) { | ||
536 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
537 | struct inode *inode = dentry->d_inode; | ||
538 | |||
539 | list_del_init(&ino->rehash); | ||
540 | dget(dentry); | ||
541 | /* | ||
542 | * Make the rehashed dentry negative so the VFS | ||
543 | * behaves as it should. | ||
544 | */ | ||
545 | if (inode) { | ||
546 | dentry->d_inode = NULL; | ||
547 | list_del_init(&dentry->d_alias); | ||
548 | spin_unlock(&dentry->d_lock); | ||
549 | spin_unlock(&sbi->rehash_lock); | ||
550 | spin_unlock(&dcache_lock); | ||
551 | iput(inode); | ||
552 | return dentry; | ||
553 | } | ||
554 | spin_unlock(&dentry->d_lock); | ||
555 | spin_unlock(&sbi->rehash_lock); | ||
556 | spin_unlock(&dcache_lock); | ||
557 | return dentry; | ||
558 | } | ||
559 | next: | ||
560 | spin_unlock(&dentry->d_lock); | ||
561 | } | ||
562 | spin_unlock(&sbi->rehash_lock); | ||
563 | spin_unlock(&dcache_lock); | ||
564 | |||
565 | return NULL; | ||
566 | } | ||
567 | |||
481 | /* Lookups in the root directory */ | 568 | /* Lookups in the root directory */ |
482 | static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 569 | static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
483 | { | 570 | { |
484 | struct autofs_sb_info *sbi; | 571 | struct autofs_sb_info *sbi; |
572 | struct dentry *unhashed; | ||
485 | int oz_mode; | 573 | int oz_mode; |
486 | 574 | ||
487 | DPRINTK("name = %.*s", | 575 | DPRINTK("name = %.*s", |
@@ -497,25 +585,46 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
497 | DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", | 585 | DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", |
498 | current->pid, process_group(current), sbi->catatonic, oz_mode); | 586 | current->pid, process_group(current), sbi->catatonic, oz_mode); |
499 | 587 | ||
500 | /* | 588 | unhashed = autofs4_lookup_unhashed(sbi, dentry->d_parent, &dentry->d_name); |
501 | * Mark the dentry incomplete, but add it. This is needed so | 589 | if (!unhashed) { |
502 | * that the VFS layer knows about the dentry, and we can count | 590 | /* |
503 | * on catching any lookups through the revalidate. | 591 | * Mark the dentry incomplete, but add it. This is needed so |
504 | * | 592 | * that the VFS layer knows about the dentry, and we can count |
505 | * Let all the hard work be done by the revalidate function that | 593 | * on catching any lookups through the revalidate. |
506 | * needs to be able to do this anyway.. | 594 | * |
507 | * | 595 | * Let all the hard work be done by the revalidate function that |
508 | * We need to do this before we release the directory semaphore. | 596 | * needs to be able to do this anyway.. |
509 | */ | 597 | * |
510 | dentry->d_op = &autofs4_root_dentry_operations; | 598 | * We need to do this before we release the directory semaphore. |
599 | */ | ||
600 | dentry->d_op = &autofs4_root_dentry_operations; | ||
601 | |||
602 | dentry->d_fsdata = NULL; | ||
603 | d_add(dentry, NULL); | ||
604 | } else { | ||
605 | struct autofs_info *ino = autofs4_dentry_ino(unhashed); | ||
606 | DPRINTK("rehash %p with %p", dentry, unhashed); | ||
607 | /* | ||
608 | * If we are racing with expire the request might not | ||
609 | * be quite complete but the directory has been removed | ||
610 | * so it must have been successful, so just wait for it. | ||
611 | */ | ||
612 | if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) { | ||
613 | DPRINTK("wait for incomplete expire %p name=%.*s", | ||
614 | unhashed, unhashed->d_name.len, | ||
615 | unhashed->d_name.name); | ||
616 | autofs4_wait(sbi, unhashed, NFY_NONE); | ||
617 | DPRINTK("request completed"); | ||
618 | } | ||
619 | d_rehash(unhashed); | ||
620 | dentry = unhashed; | ||
621 | } | ||
511 | 622 | ||
512 | if (!oz_mode) { | 623 | if (!oz_mode) { |
513 | spin_lock(&dentry->d_lock); | 624 | spin_lock(&dentry->d_lock); |
514 | dentry->d_flags |= DCACHE_AUTOFS_PENDING; | 625 | dentry->d_flags |= DCACHE_AUTOFS_PENDING; |
515 | spin_unlock(&dentry->d_lock); | 626 | spin_unlock(&dentry->d_lock); |
516 | } | 627 | } |
517 | dentry->d_fsdata = NULL; | ||
518 | d_add(dentry, NULL); | ||
519 | 628 | ||
520 | if (dentry->d_op && dentry->d_op->d_revalidate) { | 629 | if (dentry->d_op && dentry->d_op->d_revalidate) { |
521 | mutex_unlock(&dir->i_mutex); | 630 | mutex_unlock(&dir->i_mutex); |
@@ -534,6 +643,8 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
534 | if (sigismember (sigset, SIGKILL) || | 643 | if (sigismember (sigset, SIGKILL) || |
535 | sigismember (sigset, SIGQUIT) || | 644 | sigismember (sigset, SIGQUIT) || |
536 | sigismember (sigset, SIGINT)) { | 645 | sigismember (sigset, SIGINT)) { |
646 | if (unhashed) | ||
647 | dput(unhashed); | ||
537 | return ERR_PTR(-ERESTARTNOINTR); | 648 | return ERR_PTR(-ERESTARTNOINTR); |
538 | } | 649 | } |
539 | } | 650 | } |
@@ -548,8 +659,14 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
548 | * doesn't do the right thing for all system calls, but it should | 659 | * doesn't do the right thing for all system calls, but it should |
549 | * be OK for the operations we permit from an autofs. | 660 | * be OK for the operations we permit from an autofs. |
550 | */ | 661 | */ |
551 | if (dentry->d_inode && d_unhashed(dentry)) | 662 | if (dentry->d_inode && d_unhashed(dentry)) { |
663 | if (unhashed) | ||
664 | dput(unhashed); | ||
552 | return ERR_PTR(-ENOENT); | 665 | return ERR_PTR(-ENOENT); |
666 | } | ||
667 | |||
668 | if (unhashed) | ||
669 | return dentry; | ||
553 | 670 | ||
554 | return NULL; | 671 | return NULL; |
555 | } | 672 | } |
@@ -611,9 +728,10 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
611 | * Normal filesystems would do a "d_delete()" to tell the VFS dcache | 728 | * Normal filesystems would do a "d_delete()" to tell the VFS dcache |
612 | * that the file no longer exists. However, doing that means that the | 729 | * that the file no longer exists. However, doing that means that the |
613 | * VFS layer can turn the dentry into a negative dentry. We don't want | 730 | * VFS layer can turn the dentry into a negative dentry. We don't want |
614 | * this, because since the unlink is probably the result of an expire. | 731 | * this, because the unlink is probably the result of an expire. |
615 | * We simply d_drop it, which allows the dentry lookup to remount it | 732 | * We simply d_drop it and add it to a rehash candidates list in the |
616 | * if necessary. | 733 | * super block, which allows the dentry lookup to reuse it retaining |
734 | * the flags, such as expire in progress, in case we're racing with expire. | ||
617 | * | 735 | * |
618 | * If a process is blocked on the dentry waiting for the expire to finish, | 736 | * If a process is blocked on the dentry waiting for the expire to finish, |
619 | * it will invalidate the dentry and try to mount with a new one. | 737 | * it will invalidate the dentry and try to mount with a new one. |
@@ -642,7 +760,14 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
642 | 760 | ||
643 | dir->i_mtime = CURRENT_TIME; | 761 | dir->i_mtime = CURRENT_TIME; |
644 | 762 | ||
645 | d_drop(dentry); | 763 | spin_lock(&dcache_lock); |
764 | spin_lock(&sbi->rehash_lock); | ||
765 | list_add(&ino->rehash, &sbi->rehash_list); | ||
766 | spin_unlock(&sbi->rehash_lock); | ||
767 | spin_lock(&dentry->d_lock); | ||
768 | __d_drop(dentry); | ||
769 | spin_unlock(&dentry->d_lock); | ||
770 | spin_unlock(&dcache_lock); | ||
646 | 771 | ||
647 | return 0; | 772 | return 0; |
648 | } | 773 | } |
@@ -653,6 +778,9 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
653 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 778 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
654 | struct autofs_info *p_ino; | 779 | struct autofs_info *p_ino; |
655 | 780 | ||
781 | DPRINTK("dentry %p, removing %.*s", | ||
782 | dentry, dentry->d_name.len, dentry->d_name.name); | ||
783 | |||
656 | if (!autofs4_oz_mode(sbi)) | 784 | if (!autofs4_oz_mode(sbi)) |
657 | return -EACCES; | 785 | return -EACCES; |
658 | 786 | ||
@@ -661,6 +789,9 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
661 | spin_unlock(&dcache_lock); | 789 | spin_unlock(&dcache_lock); |
662 | return -ENOTEMPTY; | 790 | return -ENOTEMPTY; |
663 | } | 791 | } |
792 | spin_lock(&sbi->rehash_lock); | ||
793 | list_add(&ino->rehash, &sbi->rehash_list); | ||
794 | spin_unlock(&sbi->rehash_lock); | ||
664 | spin_lock(&dentry->d_lock); | 795 | spin_lock(&dentry->d_lock); |
665 | __d_drop(dentry); | 796 | __d_drop(dentry); |
666 | spin_unlock(&dentry->d_lock); | 797 | spin_unlock(&dentry->d_lock); |