ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-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  *
8  * This file is part of the Linux kernel and is made available under
9  * the terms of the GNU General Public License, version 2, or at your
10  * option, any later version, incorporated herein by reference.
11  *
12  * ------------------------------------------------------------------------- */
13
14 #include "autofs_i.h"
15 #include <linux/mount.h>
16
17 /*
18  * Determine if a subtree of the namespace is busy.
19  *
20  * mnt is the mount tree under the autofs mountpoint
21  */
22 static inline int is_vfsmnt_tree_busy(struct vfsmount *mnt)
23 {
24         struct vfsmount *this_parent = mnt;
25         struct list_head *next;
26         int count;
27
28         count = atomic_read(&mnt->mnt_count) - 1;
29
30 repeat:
31         next = this_parent->mnt_mounts.next;
32         DPRINTK(("is_vfsmnt_tree_busy: mnt=%p, this_parent=%p, next=%p\n",
33                  mnt, this_parent, next));
34 resume:
35         for( ; next != &this_parent->mnt_mounts; next = next->next) {
36                 struct vfsmount *p = list_entry(next, struct vfsmount,
37                                                 mnt_child);
38
39                 /* -1 for struct vfs_mount's normal count, 
40                    -1 to compensate for child's reference to parent */
41                 count += atomic_read(&p->mnt_count) - 1 - 1;
42
43                 DPRINTK(("is_vfsmnt_tree_busy: p=%p, count now %d\n",
44                          p, count));
45
46                 if (!list_empty(&p->mnt_mounts)) {
47                         this_parent = p;
48                         goto repeat;
49                 }
50                 /* root is busy if any leaf is busy */
51                 if (atomic_read(&p->mnt_count) > 1)
52                         return 1;
53         }
54
55         /* All done at this level ... ascend and resume the search. */
56         if (this_parent != mnt) {
57                 next = this_parent->mnt_child.next; 
58                 this_parent = this_parent->mnt_parent;
59                 goto resume;
60         }
61
62         DPRINTK(("is_vfsmnt_tree_busy: count=%d\n", count));
63         return count != 0; /* remaining users? */
64 }
65
66 /* Traverse a dentry's list of vfsmounts and return the number of
67    non-busy mounts */
68 static int check_vfsmnt(struct vfsmount *mnt, struct dentry *dentry)
69 {
70         int ret = dentry->d_mounted;
71         struct vfsmount *vfs = lookup_mnt(mnt, dentry);
72
73         if (vfs) {
74                 mntput(vfs);
75                 if (is_vfsmnt_tree_busy(vfs))
76                         ret--;
77         }
78         DPRINTK(("check_vfsmnt: ret=%d\n", ret));
79         return ret;
80 }
81
82 /* Check dentry tree for busyness.  If a dentry appears to be busy
83    because it is a mountpoint, check to see if the mounted
84    filesystem is busy. */
85 static int is_tree_busy(struct vfsmount *topmnt, struct dentry *top)
86 {
87         struct dentry *this_parent;
88         struct list_head *next;
89         int count;
90
91         count = atomic_read(&top->d_count);
92         
93         DPRINTK(("is_tree_busy: top=%p initial count=%d\n", 
94                  top, count));
95         this_parent = top;
96
97         if (is_autofs4_dentry(top)) {
98                 count--;
99                 DPRINTK(("is_tree_busy: autofs; count=%d\n", count));
100         }
101
102         if (d_mountpoint(top))
103                 count -= check_vfsmnt(topmnt, top);
104
105  repeat:
106         next = this_parent->d_subdirs.next;
107  resume:
108         while (next != &this_parent->d_subdirs) {
109                 int adj = 0;
110                 struct dentry *dentry = list_entry(next, struct dentry,
111                                                    d_child);
112                 next = next->next;
113
114                 count += atomic_read(&dentry->d_count) - 1;
115
116                 if (d_mountpoint(dentry))
117                         adj += check_vfsmnt(topmnt, dentry);
118
119                 if (is_autofs4_dentry(dentry)) {
120                         adj++;
121                         DPRINTK(("is_tree_busy: autofs; adj=%d\n",
122                                  adj));
123                 }
124
125                 count -= adj;
126
127                 if (!list_empty(&dentry->d_subdirs)) {
128                         this_parent = dentry;
129                         goto repeat;
130                 }
131
132                 if (atomic_read(&dentry->d_count) != adj) {
133                         DPRINTK(("is_tree_busy: busy leaf (d_count=%d adj=%d)\n",
134                                  atomic_read(&dentry->d_count), adj));
135                         return 1;
136                 }
137         }
138
139         /* All done at this level ... ascend and resume the search. */
140         if (this_parent != top) {
141                 next = this_parent->d_child.next; 
142                 this_parent = this_parent->d_parent;
143                 goto resume;
144         }
145
146         DPRINTK(("is_tree_busy: count=%d\n", count));
147         return count != 0; /* remaining users? */
148 }
149
150 /*
151  * Find an eligible tree to time-out
152  * A tree is eligible if :-
153  *  - it is unused by any user process
154  *  - it has been unused for exp_timeout time
155  */
156 static struct dentry *autofs4_expire(struct super_block *sb,
157                                      struct vfsmount *mnt,
158                                      struct autofs_sb_info *sbi,
159                                      int do_now)
160 {
161         unsigned long now = jiffies;
162         unsigned long timeout;
163         struct dentry *root = sb->s_root;
164         struct list_head *tmp;
165
166         if (!sbi->exp_timeout || !root)
167                 return NULL;
168
169         timeout = sbi->exp_timeout;
170
171         spin_lock(&dcache_lock);
172         for(tmp = root->d_subdirs.next;
173             tmp != &root->d_subdirs; 
174             tmp = tmp->next) {
175                 struct autofs_info *ino;
176                 struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
177
178                 if (dentry->d_inode == NULL)
179                         continue;
180
181                 ino = autofs4_dentry_ino(dentry);
182
183                 if (ino == NULL) {
184                         /* dentry in the process of being deleted */
185                         continue;
186                 }
187
188                 /* No point expiring a pending mount */
189                 if (dentry->d_flags & DCACHE_AUTOFS_PENDING)
190                         continue;
191
192                 if (!do_now) {
193                         /* Too young to die */
194                         if (time_after(ino->last_used + timeout, now))
195                                 continue;
196                 
197                         /* update last_used here :- 
198                            - obviously makes sense if it is in use now
199                            - less obviously, prevents rapid-fire expire
200                              attempts if expire fails the first time */
201                         ino->last_used = now;
202                 }
203                 if (!is_tree_busy(mnt, dentry)) {
204                         DPRINTK(("autofs_expire: returning %p %.*s\n",
205                                  dentry, (int)dentry->d_name.len, dentry->d_name.name));
206                         /* Start from here next time */
207                         list_del(&root->d_subdirs);
208                         list_add(&root->d_subdirs, &dentry->d_child);
209                         dget(dentry);
210                         spin_unlock(&dcache_lock);
211
212                         return dentry;
213                 }
214         }
215         spin_unlock(&dcache_lock);
216
217         return NULL;
218 }
219
220 /* Perform an expiry operation */
221 int autofs4_expire_run(struct super_block *sb,
222                       struct vfsmount *mnt,
223                       struct autofs_sb_info *sbi,
224                       struct autofs_packet_expire *pkt_p)
225 {
226         struct autofs_packet_expire pkt;
227         struct dentry *dentry;
228
229         memset(&pkt,0,sizeof pkt);
230
231         pkt.hdr.proto_version = sbi->version;
232         pkt.hdr.type = autofs_ptype_expire;
233
234         if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL)
235                 return -EAGAIN;
236
237         pkt.len = dentry->d_name.len;
238         memcpy(pkt.name, dentry->d_name.name, pkt.len);
239         pkt.name[pkt.len] = '\0';
240         dput(dentry);
241
242         if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
243                 return -EFAULT;
244
245         return 0;
246 }
247
248 /* Call repeatedly until it returns -EAGAIN, meaning there's nothing
249    more to be done */
250 int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
251                         struct autofs_sb_info *sbi, int *arg)
252 {
253         struct dentry *dentry;
254         int ret = -EAGAIN;
255         int do_now = 0;
256
257         if (arg && get_user(do_now, arg))
258                 return -EFAULT;
259
260         if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) {
261                 struct autofs_info *de_info = autofs4_dentry_ino(dentry);
262
263                 /* This is synchronous because it makes the daemon a
264                    little easier */
265                 de_info->flags |= AUTOFS_INF_EXPIRING;
266                 ret = autofs4_wait(sbi, &dentry->d_name, NFY_EXPIRE);
267                 de_info->flags &= ~AUTOFS_INF_EXPIRING;
268                 dput(dentry);
269         }
270                 
271         return ret;
272 }
273