]> err.no Git - linux-2.6/blob - fs/autofs4/expire.c
[PATCH] autofs4: simplify expire tree traversal
[linux-2.6] / 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 /*
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
96 /* Check a directory tree of mount points for busyness
97  * The tree is not busy iff no mountpoints are busy
98  */
99 static int autofs4_tree_busy(struct vfsmount *mnt,
100                              struct dentry *top,
101                              unsigned long timeout,
102                              int do_now)
103 {
104         struct dentry *p;
105
106         DPRINTK("top %p %.*s",
107                 top, (int)top->d_name.len, top->d_name.name);
108
109         /* Negative dentry - give up */
110         if (!simple_positive(top))
111                 return 1;
112
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);
122         for (p = top; p; p = next_dentry(p, top)) {
123                 /* Negative dentry - give up */
124                 if (!simple_positive(p))
125                         continue;
126
127                 DPRINTK("dentry %p %.*s",
128                         p, (int) p->d_name.len, p->d_name.name);
129
130                 p = dget(p);
131                 spin_unlock(&dcache_lock);
132
133                 if (d_mountpoint(p)) {
134                         /* First busy => tree busy */
135                         if (autofs4_mount_busy(mnt, p)) {
136                                 dput(p);
137                                 return 1;
138                         }
139                 }
140                 dput(p);
141                 spin_lock(&dcache_lock);
142         }
143         spin_unlock(&dcache_lock);
144         return 0;
145 }
146
147 static struct dentry *autofs4_check_leaves(struct vfsmount *mnt,
148                                            struct dentry *parent,
149                                            unsigned long timeout,
150                                            int do_now)
151 {
152         struct dentry *p;
153
154         DPRINTK("parent %p %.*s",
155                 parent, (int)parent->d_name.len, parent->d_name.name);
156
157         spin_lock(&dcache_lock);
158         for (p = parent; p; p = next_dentry(p, parent)) {
159                 /* Negative dentry - give up */
160                 if (!simple_positive(p))
161                         continue;
162
163                 DPRINTK("dentry %p %.*s",
164                         p, (int) p->d_name.len, p->d_name.name);
165
166                 p = dget(p);
167                 spin_unlock(&dcache_lock);
168
169                 if (d_mountpoint(p)) {
170                         /* Can we expire this guy */
171                         if (!autofs4_can_expire(p, timeout, do_now))
172                                 goto cont;
173
174                         /* Can we umount this guy */
175                         if (!autofs4_mount_busy(mnt, p))
176                                 return p;
177
178                 }
179 cont:
180                 dput(p);
181                 spin_lock(&dcache_lock);
182         }
183         spin_unlock(&dcache_lock);
184         return NULL;
185 }
186
187 /*
188  * Find an eligible tree to time-out
189  * A tree is eligible if :-
190  *  - it is unused by any user process
191  *  - it has been unused for exp_timeout time
192  */
193 static struct dentry *autofs4_expire(struct super_block *sb,
194                                      struct vfsmount *mnt,
195                                      struct autofs_sb_info *sbi,
196                                      int how)
197 {
198         unsigned long timeout;
199         struct dentry *root = sb->s_root;
200         struct dentry *expired = NULL;
201         struct list_head *next;
202         int do_now = how & AUTOFS_EXP_IMMEDIATE;
203         int exp_leaves = how & AUTOFS_EXP_LEAVES;
204
205         if ( !sbi->exp_timeout || !root )
206                 return NULL;
207
208         now = jiffies;
209         timeout = sbi->exp_timeout;
210
211         spin_lock(&dcache_lock);
212         next = root->d_subdirs.next;
213
214         /* On exit from the loop expire is set to a dgot dentry
215          * to expire or it's NULL */
216         while ( next != &root->d_subdirs ) {
217                 struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
218
219                 /* Negative dentry - give up */
220                 if (!simple_positive(dentry)) {
221                         next = next->next;
222                         continue;
223                 }
224
225                 dentry = dget(dentry);
226                 spin_unlock(&dcache_lock);
227
228                 /* Case 1: indirect mount or top level direct mount */
229                 if (d_mountpoint(dentry)) {
230                         DPRINTK("checking mountpoint %p %.*s",
231                                 dentry, (int)dentry->d_name.len, dentry->d_name.name);
232
233                         /* Can we expire this guy */
234                         if (!autofs4_can_expire(dentry, timeout, do_now))
235                                 goto next;
236
237                         /* Can we umount this guy */
238                         if (!autofs4_mount_busy(mnt, dentry)) {
239                                 expired = dentry;
240                                 break;
241                         }
242                         goto next;
243                 }
244
245                 if (simple_empty(dentry))
246                         goto next;
247
248                 /* Case 2: tree mount, expire iff entire tree is not busy */
249                 if (!exp_leaves) {
250                         /* Lock the tree as we must expire as a whole */
251                         spin_lock(&sbi->fs_lock);
252                         if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
253                                 struct autofs_info *inf = autofs4_dentry_ino(dentry);
254
255                                 /* Set this flag early to catch sys_chdir and the like */
256                                 inf->flags |= AUTOFS_INF_EXPIRING;
257                                 spin_unlock(&sbi->fs_lock);
258                                 expired = dentry;
259                                 break;
260                         }
261                         spin_unlock(&sbi->fs_lock);
262                 /* Case 3: direct mount, expire individual leaves */
263                 } else {
264                         expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
265                         if (expired) {
266                                 dput(dentry);
267                                 break;
268                         }
269                 }
270 next:
271                 dput(dentry);
272                 spin_lock(&dcache_lock);
273                 next = next->next;
274         }
275
276         if (expired) {
277                 DPRINTK("returning %p %.*s",
278                         expired, (int)expired->d_name.len, expired->d_name.name);
279                 spin_lock(&dcache_lock);
280                 list_del(&expired->d_parent->d_subdirs);
281                 list_add(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
282                 spin_unlock(&dcache_lock);
283                 return expired;
284         }
285         spin_unlock(&dcache_lock);
286
287         return NULL;
288 }
289
290 /* Perform an expiry operation */
291 int autofs4_expire_run(struct super_block *sb,
292                       struct vfsmount *mnt,
293                       struct autofs_sb_info *sbi,
294                       struct autofs_packet_expire __user *pkt_p)
295 {
296         struct autofs_packet_expire pkt;
297         struct dentry *dentry;
298
299         memset(&pkt,0,sizeof pkt);
300
301         pkt.hdr.proto_version = sbi->version;
302         pkt.hdr.type = autofs_ptype_expire;
303
304         if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL)
305                 return -EAGAIN;
306
307         pkt.len = dentry->d_name.len;
308         memcpy(pkt.name, dentry->d_name.name, pkt.len);
309         pkt.name[pkt.len] = '\0';
310         dput(dentry);
311
312         if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
313                 return -EFAULT;
314
315         return 0;
316 }
317
318 /* Call repeatedly until it returns -EAGAIN, meaning there's nothing
319    more to be done */
320 int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
321                         struct autofs_sb_info *sbi, int __user *arg)
322 {
323         struct dentry *dentry;
324         int ret = -EAGAIN;
325         int do_now = 0;
326
327         if (arg && get_user(do_now, arg))
328                 return -EFAULT;
329
330         if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) {
331                 struct autofs_info *ino = autofs4_dentry_ino(dentry);
332
333                 /* This is synchronous because it makes the daemon a
334                    little easier */
335                 ino->flags |= AUTOFS_INF_EXPIRING;
336                 ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
337                 ino->flags &= ~AUTOFS_INF_EXPIRING;
338                 dput(dentry);
339         }
340
341         return ret;
342 }
343