diff options
Diffstat (limited to 'fs/autofs4')
-rw-r--r-- | fs/autofs4/expire.c | 102 |
1 files changed, 40 insertions, 62 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index bcc17f533699..165fe9e2d570 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -72,6 +72,27 @@ done: | |||
72 | return status; | 72 | return status; |
73 | } | 73 | } |
74 | 74 | ||
75 | /* | ||
76 | * Calculate next entry in top down tree traversal. | ||
77 | * From next_mnt in namespace.c - elegant. | ||
78 | */ | ||
79 | static struct dentry *next_dentry(struct dentry *p, struct dentry *root) | ||
80 | { | ||
81 | struct list_head *next = p->d_subdirs.next; | ||
82 | |||
83 | if (next == &p->d_subdirs) { | ||
84 | while (1) { | ||
85 | if (p == root) | ||
86 | return NULL; | ||
87 | next = p->d_u.d_child.next; | ||
88 | if (next != &p->d_parent->d_subdirs) | ||
89 | break; | ||
90 | p = p->d_parent; | ||
91 | } | ||
92 | } | ||
93 | return list_entry(next, struct dentry, d_u.d_child); | ||
94 | } | ||
95 | |||
75 | /* Check a directory tree of mount points for busyness | 96 | /* Check a directory tree of mount points for busyness |
76 | * The tree is not busy iff no mountpoints are busy | 97 | * The tree is not busy iff no mountpoints are busy |
77 | */ | 98 | */ |
@@ -80,8 +101,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
80 | unsigned long timeout, | 101 | unsigned long timeout, |
81 | int do_now) | 102 | int do_now) |
82 | { | 103 | { |
83 | struct dentry *this_parent = top; | 104 | struct dentry *p; |
84 | struct list_head *next; | ||
85 | 105 | ||
86 | DPRINTK("top %p %.*s", | 106 | DPRINTK("top %p %.*s", |
87 | top, (int)top->d_name.len, top->d_name.name); | 107 | top, (int)top->d_name.len, top->d_name.name); |
@@ -99,49 +119,28 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
99 | return 1; | 119 | return 1; |
100 | 120 | ||
101 | spin_lock(&dcache_lock); | 121 | spin_lock(&dcache_lock); |
102 | repeat: | 122 | for (p = top; p; p = next_dentry(p, top)) { |
103 | next = this_parent->d_subdirs.next; | ||
104 | resume: | ||
105 | while (next != &this_parent->d_subdirs) { | ||
106 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | ||
107 | |||
108 | /* Negative dentry - give up */ | 123 | /* Negative dentry - give up */ |
109 | if (!simple_positive(dentry)) { | 124 | if (!simple_positive(p)) |
110 | next = next->next; | ||
111 | continue; | 125 | continue; |
112 | } | ||
113 | 126 | ||
114 | DPRINTK("dentry %p %.*s", | 127 | DPRINTK("dentry %p %.*s", |
115 | dentry, (int)dentry->d_name.len, dentry->d_name.name); | 128 | p, (int) p->d_name.len, p->d_name.name); |
116 | |||
117 | if (!simple_empty_nolock(dentry)) { | ||
118 | this_parent = dentry; | ||
119 | goto repeat; | ||
120 | } | ||
121 | 129 | ||
122 | dentry = dget(dentry); | 130 | p = dget(p); |
123 | spin_unlock(&dcache_lock); | 131 | spin_unlock(&dcache_lock); |
124 | 132 | ||
125 | if (d_mountpoint(dentry)) { | 133 | if (d_mountpoint(p)) { |
126 | /* First busy => tree busy */ | 134 | /* First busy => tree busy */ |
127 | if (autofs4_mount_busy(mnt, dentry)) { | 135 | if (autofs4_mount_busy(mnt, p)) { |
128 | dput(dentry); | 136 | dput(p); |
129 | return 1; | 137 | return 1; |
130 | } | 138 | } |
131 | } | 139 | } |
132 | 140 | dput(p); | |
133 | dput(dentry); | ||
134 | spin_lock(&dcache_lock); | 141 | spin_lock(&dcache_lock); |
135 | next = next->next; | ||
136 | } | ||
137 | |||
138 | if (this_parent != top) { | ||
139 | next = this_parent->d_u.d_child.next; | ||
140 | this_parent = this_parent->d_parent; | ||
141 | goto resume; | ||
142 | } | 142 | } |
143 | spin_unlock(&dcache_lock); | 143 | spin_unlock(&dcache_lock); |
144 | |||
145 | return 0; | 144 | return 0; |
146 | } | 145 | } |
147 | 146 | ||
@@ -150,59 +149,38 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, | |||
150 | unsigned long timeout, | 149 | unsigned long timeout, |
151 | int do_now) | 150 | int do_now) |
152 | { | 151 | { |
153 | struct dentry *this_parent = parent; | 152 | struct dentry *p; |
154 | struct list_head *next; | ||
155 | 153 | ||
156 | DPRINTK("parent %p %.*s", | 154 | DPRINTK("parent %p %.*s", |
157 | parent, (int)parent->d_name.len, parent->d_name.name); | 155 | parent, (int)parent->d_name.len, parent->d_name.name); |
158 | 156 | ||
159 | spin_lock(&dcache_lock); | 157 | spin_lock(&dcache_lock); |
160 | repeat: | 158 | for (p = parent; p; p = next_dentry(p, parent)) { |
161 | next = this_parent->d_subdirs.next; | ||
162 | resume: | ||
163 | while (next != &this_parent->d_subdirs) { | ||
164 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | ||
165 | |||
166 | /* Negative dentry - give up */ | 159 | /* Negative dentry - give up */ |
167 | if (!simple_positive(dentry)) { | 160 | if (!simple_positive(p)) |
168 | next = next->next; | ||
169 | continue; | 161 | continue; |
170 | } | ||
171 | 162 | ||
172 | DPRINTK("dentry %p %.*s", | 163 | DPRINTK("dentry %p %.*s", |
173 | dentry, (int)dentry->d_name.len, dentry->d_name.name); | 164 | p, (int) p->d_name.len, p->d_name.name); |
174 | 165 | ||
175 | if (!list_empty(&dentry->d_subdirs)) { | 166 | p = dget(p); |
176 | this_parent = dentry; | ||
177 | goto repeat; | ||
178 | } | ||
179 | |||
180 | dentry = dget(dentry); | ||
181 | spin_unlock(&dcache_lock); | 167 | spin_unlock(&dcache_lock); |
182 | 168 | ||
183 | if (d_mountpoint(dentry)) { | 169 | if (d_mountpoint(p)) { |
184 | /* Can we expire this guy */ | 170 | /* Can we expire this guy */ |
185 | if (!autofs4_can_expire(dentry, timeout, do_now)) | 171 | if (!autofs4_can_expire(p, timeout, do_now)) |
186 | goto cont; | 172 | goto cont; |
187 | 173 | ||
188 | /* Can we umount this guy */ | 174 | /* Can we umount this guy */ |
189 | if (!autofs4_mount_busy(mnt, dentry)) | 175 | if (!autofs4_mount_busy(mnt, p)) |
190 | return dentry; | 176 | return p; |
191 | 177 | ||
192 | } | 178 | } |
193 | cont: | 179 | cont: |
194 | dput(dentry); | 180 | dput(p); |
195 | spin_lock(&dcache_lock); | 181 | spin_lock(&dcache_lock); |
196 | next = next->next; | ||
197 | } | ||
198 | |||
199 | if (this_parent != parent) { | ||
200 | next = this_parent->d_u.d_child.next; | ||
201 | this_parent = this_parent->d_parent; | ||
202 | goto resume; | ||
203 | } | 182 | } |
204 | spin_unlock(&dcache_lock); | 183 | spin_unlock(&dcache_lock); |
205 | |||
206 | return NULL; | 184 | return NULL; |
207 | } | 185 | } |
208 | 186 | ||