[PATCH] autofs4: expire code readability cleanup
[sfrench/cifs-2.6.git] / fs / autofs4 / expire.c
1 /* -*- c -*- --------------------------------------------------------------- *
2  *
3  * linux/fs/autofs/expire.c
4  *
5  *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
6  *  Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
7  *  Copyright 2001-2003 Ian Kent <raven@themaw.net>
8  *
9  * This file is part of the Linux kernel and is made available under
10  * the terms of the GNU General Public License, version 2, or at your
11  * option, any later version, incorporated herein by reference.
12  *
13  * ------------------------------------------------------------------------- */
14
15 #include "autofs_i.h"
16
17 static unsigned long now;
18
19 /* Check if a dentry can be expired */
20 static inline int autofs4_can_expire(struct dentry *dentry,
21                                         unsigned long timeout, int do_now)
22 {
23         struct autofs_info *ino = autofs4_dentry_ino(dentry);
24
25         /* dentry in the process of being deleted */
26         if (ino == NULL)
27                 return 0;
28
29         /* No point expiring a pending mount */
30         if (dentry->d_flags & DCACHE_AUTOFS_PENDING)
31                 return 0;
32
33         if (!do_now) {
34                 /* Too young to die */
35                 if (time_after(ino->last_used + timeout, now))
36                         return 0;
37
38                 /* update last_used here :-
39                    - obviously makes sense if it is in use now
40                    - less obviously, prevents rapid-fire expire
41                      attempts if expire fails the first time */
42                 ino->last_used = now;
43         }
44         return 1;
45 }
46
47 /* Check a mount point for busyness */
48 static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
49 {
50         int status = 1;
51
52         DPRINTK("dentry %p %.*s",
53                 dentry, (int)dentry->d_name.len, dentry->d_name.name);
54
55         mntget(mnt);
56         dget(dentry);
57
58         if (!autofs4_follow_mount(&mnt, &dentry))
59                 goto done;
60
61         /* This is an autofs submount, we can't expire it */
62         if (is_autofs4_dentry(dentry))
63                 goto done;
64
65         /* The big question */
66         if (may_umount_tree(mnt) == 0)
67                 status = 0;
68 done:
69         DPRINTK("returning = %d", status);
70         mntput(mnt);
71         dput(dentry);
72         return status;
73 }
74
75 /* Check a directory tree of mount points for busyness
76  * The tree is not busy iff no mountpoints are busy
77  */
78 static int autofs4_tree_busy(struct vfsmount *mnt,
79                              struct dentry *top,
80                              unsigned long timeout,
81                              int do_now)
82 {
83         struct dentry *this_parent = top;
84         struct list_head *next;
85
86         DPRINTK("top %p %.*s",
87                 top, (int)top->d_name.len, top->d_name.name);
88
89         /* Negative dentry - give up */
90         if (!simple_positive(top))
91                 return 1;
92
93         /* Timeout of a tree mount is determined by its top dentry */
94         if (!autofs4_can_expire(top, timeout, do_now))
95                 return 1;
96
97         /* Is someone visiting anywhere in the tree ? */
98         if (may_umount_tree(mnt))
99                 return 1;
100
101         spin_lock(&dcache_lock);
102 repeat:
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 */
109                 if (!simple_positive(dentry)) {
110                         next = next->next;
111                         continue;
112                 }
113
114                 DPRINTK("dentry %p %.*s",
115                         dentry, (int)dentry->d_name.len, dentry->d_name.name);
116
117                 if (!simple_empty_nolock(dentry)) {
118                         this_parent = dentry;
119                         goto repeat;
120                 }
121
122                 dentry = dget(dentry);
123                 spin_unlock(&dcache_lock);
124
125                 if (d_mountpoint(dentry)) {
126                         /* First busy => tree busy */
127                         if (autofs4_mount_busy(mnt, dentry)) {
128                                 dput(dentry);
129                                 return 1;
130                         }
131                 }
132
133                 dput(dentry);
134                 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         }
143         spin_unlock(&dcache_lock);
144
145         return 0;
146 }
147
148 static struct dentry *autofs4_check_leaves(struct vfsmount *mnt,
149                                            struct dentry *parent,
150                                            unsigned long timeout,
151                                            int do_now)
152 {
153         struct dentry *this_parent = parent;
154         struct list_head *next;
155
156         DPRINTK("parent %p %.*s",
157                 parent, (int)parent->d_name.len, parent->d_name.name);
158
159         spin_lock(&dcache_lock);
160 repeat:
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 */
167                 if (!simple_positive(dentry)) {
168                         next = next->next;
169                         continue;
170                 }
171
172                 DPRINTK("dentry %p %.*s",
173                         dentry, (int)dentry->d_name.len, dentry->d_name.name);
174
175                 if (!list_empty(&dentry->d_subdirs)) {
176                         this_parent = dentry;
177                         goto repeat;
178                 }
179
180                 dentry = dget(dentry);
181                 spin_unlock(&dcache_lock);
182
183                 if (d_mountpoint(dentry)) {
184                         /* Can we expire this guy */
185                         if (!autofs4_can_expire(dentry, timeout, do_now))
186                                 goto cont;
187
188                         /* Can we umount this guy */
189                         if (!autofs4_mount_busy(mnt, dentry))
190                                 return dentry;
191
192                 }
193 cont:
194                 dput(dentry);
195                 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         }
204         spin_unlock(&dcache_lock);
205
206         return NULL;
207 }
208
209 /*
210  * Find an eligible tree to time-out
211  * A tree is eligible if :-
212  *  - it is unused by any user process
213  *  - it has been unused for exp_timeout time
214  */
215 static struct dentry *autofs4_expire(struct super_block *sb,
216                                      struct vfsmount *mnt,
217                                      struct autofs_sb_info *sbi,
218                                      int how)
219 {
220         unsigned long timeout;
221         struct dentry *root = sb->s_root;
222         struct dentry *expired = NULL;
223         struct list_head *next;
224         int do_now = how & AUTOFS_EXP_IMMEDIATE;
225         int exp_leaves = how & AUTOFS_EXP_LEAVES;
226
227         if ( !sbi->exp_timeout || !root )
228                 return NULL;
229
230         now = jiffies;
231         timeout = sbi->exp_timeout;
232
233         spin_lock(&dcache_lock);
234         next = root->d_subdirs.next;
235
236         /* On exit from the loop expire is set to a dgot dentry
237          * to expire or it's NULL */
238         while ( next != &root->d_subdirs ) {
239                 struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
240
241                 /* Negative dentry - give up */
242                 if (!simple_positive(dentry)) {
243                         next = next->next;
244                         continue;
245                 }
246
247                 dentry = dget(dentry);
248                 spin_unlock(&dcache_lock);
249
250                 /* Case 1: indirect mount or top level direct mount */
251                 if (d_mountpoint(dentry)) {
252                         DPRINTK("checking mountpoint %p %.*s",
253                                 dentry, (int)dentry->d_name.len, dentry->d_name.name);
254
255                         /* Can we expire this guy */
256                         if (!autofs4_can_expire(dentry, timeout, do_now))
257                                 goto next;
258
259                         /* Can we umount this guy */
260                         if (!autofs4_mount_busy(mnt, dentry)) {
261                                 expired = dentry;
262                                 break;
263                         }
264                         goto next;
265                 }
266
267                 if (simple_empty(dentry))
268                         goto next;
269
270                 /* Case 2: tree mount, expire iff entire tree is not busy */
271                 if (!exp_leaves) {
272                         /* Lock the tree as we must expire as a whole */
273                         spin_lock(&sbi->fs_lock);
274                         if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
275                                 struct autofs_info *inf = autofs4_dentry_ino(dentry);
276
277                                 /* Set this flag early to catch sys_chdir and the like */
278                                 inf->flags |= AUTOFS_INF_EXPIRING;
279                                 spin_unlock(&sbi->fs_lock);
280                                 expired = dentry;
281                                 break;
282                         }
283                         spin_unlock(&sbi->fs_lock);
284                 /* Case 3: direct mount, expire individual leaves */
285                 } else {
286                         expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
287                         if (expired) {
288                                 dput(dentry);
289                                 break;
290                         }
291                 }
292 next:
293                 dput(dentry);
294                 spin_lock(&dcache_lock);
295                 next = next->next;
296         }
297
298         if (expired) {
299                 DPRINTK("returning %p %.*s",
300                         expired, (int)expired->d_name.len, expired->d_name.name);
301                 spin_lock(&dcache_lock);
302                 list_del(&expired->d_parent->d_subdirs);
303                 list_add(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
304                 spin_unlock(&dcache_lock);
305                 return expired;
306         }
307         spin_unlock(&dcache_lock);
308
309         return NULL;
310 }
311
312 /* Perform an expiry operation */
313 int autofs4_expire_run(struct super_block *sb,
314                       struct vfsmount *mnt,
315                       struct autofs_sb_info *sbi,
316                       struct autofs_packet_expire __user *pkt_p)
317 {
318         struct autofs_packet_expire pkt;
319         struct dentry *dentry;
320
321         memset(&pkt,0,sizeof pkt);
322
323         pkt.hdr.proto_version = sbi->version;
324         pkt.hdr.type = autofs_ptype_expire;
325
326         if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL)
327                 return -EAGAIN;
328
329         pkt.len = dentry->d_name.len;
330         memcpy(pkt.name, dentry->d_name.name, pkt.len);
331         pkt.name[pkt.len] = '\0';
332         dput(dentry);
333
334         if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
335                 return -EFAULT;
336
337         return 0;
338 }
339
340 /* Call repeatedly until it returns -EAGAIN, meaning there's nothing
341    more to be done */
342 int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
343                         struct autofs_sb_info *sbi, int __user *arg)
344 {
345         struct dentry *dentry;
346         int ret = -EAGAIN;
347         int do_now = 0;
348
349         if (arg && get_user(do_now, arg))
350                 return -EFAULT;
351
352         if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) {
353                 struct autofs_info *ino = autofs4_dentry_ino(dentry);
354
355                 /* This is synchronous because it makes the daemon a
356                    little easier */
357                 ino->flags |= AUTOFS_INF_EXPIRING;
358                 ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
359                 ino->flags &= ~AUTOFS_INF_EXPIRING;
360                 dput(dentry);
361         }
362
363         return ret;
364 }
365