diff options
-rw-r--r-- | fs/autofs4/autofs_i.h | 1 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 34 | ||||
-rw-r--r-- | fs/autofs4/inode.c | 12 | ||||
-rw-r--r-- | fs/autofs4/root.c | 23 |
4 files changed, 59 insertions, 11 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index eea25934da62..00da71d0f32a 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -55,6 +55,7 @@ struct autofs_info { | |||
55 | 55 | ||
56 | struct autofs_sb_info *sbi; | 56 | struct autofs_sb_info *sbi; |
57 | unsigned long last_used; | 57 | unsigned long last_used; |
58 | atomic_t count; | ||
58 | 59 | ||
59 | mode_t mode; | 60 | mode_t mode; |
60 | size_t size; | 61 | size_t size; |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 165fe9e2d570..053d92a745b9 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -101,6 +101,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
101 | unsigned long timeout, | 101 | unsigned long timeout, |
102 | int do_now) | 102 | int do_now) |
103 | { | 103 | { |
104 | struct autofs_info *ino; | ||
104 | struct dentry *p; | 105 | struct dentry *p; |
105 | 106 | ||
106 | DPRINTK("top %p %.*s", | 107 | DPRINTK("top %p %.*s", |
@@ -110,14 +111,6 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
110 | if (!simple_positive(top)) | 111 | if (!simple_positive(top)) |
111 | return 1; | 112 | return 1; |
112 | 113 | ||
113 | /* Timeout of a tree mount is determined by its top dentry */ | ||
114 | if (!autofs4_can_expire(top, timeout, do_now)) | ||
115 | return 1; | ||
116 | |||
117 | /* Is someone visiting anywhere in the tree ? */ | ||
118 | if (may_umount_tree(mnt)) | ||
119 | return 1; | ||
120 | |||
121 | spin_lock(&dcache_lock); | 114 | spin_lock(&dcache_lock); |
122 | for (p = top; p; p = next_dentry(p, top)) { | 115 | for (p = top; p; p = next_dentry(p, top)) { |
123 | /* Negative dentry - give up */ | 116 | /* Negative dentry - give up */ |
@@ -130,17 +123,40 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
130 | p = dget(p); | 123 | p = dget(p); |
131 | spin_unlock(&dcache_lock); | 124 | spin_unlock(&dcache_lock); |
132 | 125 | ||
126 | /* | ||
127 | * Is someone visiting anywhere in the subtree ? | ||
128 | * If there's no mount we need to check the usage | ||
129 | * count for the autofs dentry. | ||
130 | */ | ||
131 | ino = autofs4_dentry_ino(p); | ||
133 | if (d_mountpoint(p)) { | 132 | if (d_mountpoint(p)) { |
134 | /* First busy => tree busy */ | ||
135 | if (autofs4_mount_busy(mnt, p)) { | 133 | if (autofs4_mount_busy(mnt, p)) { |
136 | dput(p); | 134 | dput(p); |
137 | return 1; | 135 | return 1; |
138 | } | 136 | } |
137 | } else { | ||
138 | unsigned int ino_count = atomic_read(&ino->count); | ||
139 | |||
140 | /* allow for dget above and top is already dgot */ | ||
141 | if (p == top) | ||
142 | ino_count += 2; | ||
143 | else | ||
144 | ino_count++; | ||
145 | |||
146 | if (atomic_read(&p->d_count) > ino_count) { | ||
147 | dput(p); | ||
148 | return 1; | ||
149 | } | ||
139 | } | 150 | } |
140 | dput(p); | 151 | dput(p); |
141 | spin_lock(&dcache_lock); | 152 | spin_lock(&dcache_lock); |
142 | } | 153 | } |
143 | spin_unlock(&dcache_lock); | 154 | spin_unlock(&dcache_lock); |
155 | |||
156 | /* Timeout of a tree mount is ultimately determined by its top dentry */ | ||
157 | if (!autofs4_can_expire(top, timeout, do_now)) | ||
158 | return 1; | ||
159 | |||
144 | return 0; | 160 | return 0; |
145 | } | 161 | } |
146 | 162 | ||
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 1ad98d48e550..2335b1d6490f 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -46,6 +46,7 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, | |||
46 | ino->size = 0; | 46 | ino->size = 0; |
47 | 47 | ||
48 | ino->last_used = jiffies; | 48 | ino->last_used = jiffies; |
49 | atomic_set(&ino->count, 0); | ||
49 | 50 | ||
50 | ino->sbi = sbi; | 51 | ino->sbi = sbi; |
51 | 52 | ||
@@ -64,10 +65,19 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, | |||
64 | 65 | ||
65 | void autofs4_free_ino(struct autofs_info *ino) | 66 | void autofs4_free_ino(struct autofs_info *ino) |
66 | { | 67 | { |
68 | struct autofs_info *p_ino; | ||
69 | |||
67 | if (ino->dentry) { | 70 | if (ino->dentry) { |
68 | ino->dentry->d_fsdata = NULL; | 71 | ino->dentry->d_fsdata = NULL; |
69 | if (ino->dentry->d_inode) | 72 | if (ino->dentry->d_inode) { |
73 | struct dentry *parent = ino->dentry->d_parent; | ||
74 | if (atomic_dec_and_test(&ino->count)) { | ||
75 | p_ino = autofs4_dentry_ino(parent); | ||
76 | if (p_ino && parent != ino->dentry) | ||
77 | atomic_dec(&p_ino->count); | ||
78 | } | ||
70 | dput(ino->dentry); | 79 | dput(ino->dentry); |
80 | } | ||
71 | ino->dentry = NULL; | 81 | ino->dentry = NULL; |
72 | } | 82 | } |
73 | if (ino->free) | 83 | if (ino->free) |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index c7ff35774344..d196712c4b94 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -490,6 +490,7 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
490 | { | 490 | { |
491 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 491 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
492 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 492 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
493 | struct autofs_info *p_ino; | ||
493 | struct inode *inode; | 494 | struct inode *inode; |
494 | char *cp; | 495 | char *cp; |
495 | 496 | ||
@@ -523,6 +524,10 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
523 | 524 | ||
524 | dentry->d_fsdata = ino; | 525 | dentry->d_fsdata = ino; |
525 | ino->dentry = dget(dentry); | 526 | ino->dentry = dget(dentry); |
527 | atomic_inc(&ino->count); | ||
528 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
529 | if (p_ino && dentry->d_parent != dentry) | ||
530 | atomic_inc(&p_ino->count); | ||
526 | ino->inode = inode; | 531 | ino->inode = inode; |
527 | 532 | ||
528 | dir->i_mtime = CURRENT_TIME; | 533 | dir->i_mtime = CURRENT_TIME; |
@@ -549,11 +554,17 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
549 | { | 554 | { |
550 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 555 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
551 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 556 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
557 | struct autofs_info *p_ino; | ||
552 | 558 | ||
553 | /* This allows root to remove symlinks */ | 559 | /* This allows root to remove symlinks */ |
554 | if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) | 560 | if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) |
555 | return -EACCES; | 561 | return -EACCES; |
556 | 562 | ||
563 | if (atomic_dec_and_test(&ino->count)) { | ||
564 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
565 | if (p_ino && dentry->d_parent != dentry) | ||
566 | atomic_dec(&p_ino->count); | ||
567 | } | ||
557 | dput(ino->dentry); | 568 | dput(ino->dentry); |
558 | 569 | ||
559 | dentry->d_inode->i_size = 0; | 570 | dentry->d_inode->i_size = 0; |
@@ -570,6 +581,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
570 | { | 581 | { |
571 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 582 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
572 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 583 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
584 | struct autofs_info *p_ino; | ||
573 | 585 | ||
574 | if (!autofs4_oz_mode(sbi)) | 586 | if (!autofs4_oz_mode(sbi)) |
575 | return -EACCES; | 587 | return -EACCES; |
@@ -584,8 +596,12 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
584 | spin_unlock(&dentry->d_lock); | 596 | spin_unlock(&dentry->d_lock); |
585 | spin_unlock(&dcache_lock); | 597 | spin_unlock(&dcache_lock); |
586 | 598 | ||
599 | if (atomic_dec_and_test(&ino->count)) { | ||
600 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
601 | if (p_ino && dentry->d_parent != dentry) | ||
602 | atomic_dec(&p_ino->count); | ||
603 | } | ||
587 | dput(ino->dentry); | 604 | dput(ino->dentry); |
588 | |||
589 | dentry->d_inode->i_size = 0; | 605 | dentry->d_inode->i_size = 0; |
590 | dentry->d_inode->i_nlink = 0; | 606 | dentry->d_inode->i_nlink = 0; |
591 | 607 | ||
@@ -599,6 +615,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
599 | { | 615 | { |
600 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 616 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); |
601 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | 617 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
618 | struct autofs_info *p_ino; | ||
602 | struct inode *inode; | 619 | struct inode *inode; |
603 | 620 | ||
604 | if ( !autofs4_oz_mode(sbi) ) | 621 | if ( !autofs4_oz_mode(sbi) ) |
@@ -621,6 +638,10 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
621 | 638 | ||
622 | dentry->d_fsdata = ino; | 639 | dentry->d_fsdata = ino; |
623 | ino->dentry = dget(dentry); | 640 | ino->dentry = dget(dentry); |
641 | atomic_inc(&ino->count); | ||
642 | p_ino = autofs4_dentry_ino(dentry->d_parent); | ||
643 | if (p_ino && dentry->d_parent != dentry) | ||
644 | atomic_inc(&p_ino->count); | ||
624 | ino->inode = inode; | 645 | ino->inode = inode; |
625 | dir->i_nlink++; | 646 | dir->i_nlink++; |
626 | dir->i_mtime = CURRENT_TIME; | 647 | dir->i_mtime = CURRENT_TIME; |