07021a4d1ca038568fe6e25b43b29bbd90a172d9
[linux-flexiantxendom0-3.2.10.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 && is_vfsmnt_tree_busy(vfs))
74                 ret--;
75         DPRINTK(("check_vfsmnt: ret=%d\n", ret));
76         return ret;
77 }
78
79 /* Check dentry tree for busyness.  If a dentry appears to be busy
80    because it is a mountpoint, check to see if the mounted
81    filesystem is busy. */
82 static int is_tree_busy(struct vfsmount *topmnt, struct dentry *top)
83 {
84         struct dentry *this_parent;
85         struct list_head *next;
86         int count;
87
88         count = atomic_read(&top->d_count);
89         
90         DPRINTK(("is_tree_busy: top=%p initial count=%d\n", 
91                  top, count));
92         this_parent = top;
93
94         if (is_autofs4_dentry(top)) {
95                 count--;
96                 DPRINTK(("is_tree_busy: autofs; count=%d\n", count));
97         }
98
99         if (d_mountpoint(top))
100                 count -= check_vfsmnt(topmnt, top);
101
102  repeat:
103         next = this_parent->d_subdirs.next;
104  resume:
105         while (next != &this_parent->d_subdirs) {
106                 int adj = 0;
107                 struct dentry *dentry = list_entry(next, struct dentry,
108                                                    d_child);
109                 next = next->next;
110
111                 count += atomic_read(&dentry->d_count) - 1;
112
113                 if (d_mountpoint(dentry))
114                         adj += check_vfsmnt(topmnt, dentry);
115
116                 if (is_autofs4_dentry(dentry)) {
117                         adj++;
118                         DPRINTK(("is_tree_busy: autofs; adj=%d\n",
119                                  adj));
120                 }
121
122                 count -= adj;
123
124                 if (!list_empty(&dentry->d_subdirs)) {
125                         this_parent = dentry;
126                         goto repeat;
127                 }
128
129                 if (atomic_read(&dentry->d_count) != adj) {
130                         DPRINTK(("is_tree_busy: busy leaf (d_count=%d adj=%d)\n",
131                                  atomic_read(&dentry->d_count), adj));
132                         return 1;
133                 }
134         }
135
136         /* All done at this level ... ascend and resume the search. */
137         if (this_parent != top) {
138                 next = this_parent->d_child.next; 
139                 this_parent = this_parent->d_parent;
140                 goto resume;
141         }
142
143         DPRINTK(("is_tree_busy: count=%d\n", count));
144         return count != 0; /* remaining users? */
145 }
146
147 /*
148  * Find an eligible tree to time-out
149  * A tree is eligible if :-
150  *  - it is unused by any user process
151  *  - it has been unused for exp_timeout time
152  */
153 static struct dentry *autofs4_expire(struct super_block *sb,
154                                      struct vfsmount *mnt,
155                                      struct autofs_sb_info *sbi,
156                                      int do_now)
157 {
158         unsigned long now = jiffies;
159         unsigned long timeout;
160         struct dentry *root = sb->s_root;
161         struct list_head *tmp;
162
163         if (!sbi->exp_timeout || !root)
164                 return NULL;
165
166         timeout = sbi->exp_timeout;
167
168         spin_lock(&dcache_lock);
169         for(tmp = root->d_subdirs.next;
170             tmp != &root->d_subdirs; 
171             tmp = tmp->next) {
172                 struct autofs_info *ino;
173                 struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
174
175                 if (dentry->d_inode == NULL)
176                         continue;
177
178                 ino = autofs4_dentry_ino(dentry);
179
180                 if (ino == NULL) {
181                         /* dentry in the process of being deleted */
182                         continue;
183                 }
184
185                 /* No point expiring a pending mount */
186                 if (dentry->d_flags & DCACHE_AUTOFS_PENDING)
187                         continue;
188
189                 if (!do_now) {
190                         /* Too young to die */
191                         if (time_after(ino->last_used + timeout, now))
192                                 continue;
193                 
194                         /* update last_used here :- 
195                            - obviously makes sense if it is in use now
196                            - less obviously, prevents rapid-fire expire
197                              attempts if expire fails the first time */
198                         ino->last_used = now;
199                 }
200                 if (!is_tree_busy(mnt, dentry)) {
201                         DPRINTK(("autofs_expire: returning %p %.*s\n",
202                                  dentry, (int)dentry->d_name.len, dentry->d_name.name));
203                         /* Start from here next time */
204                         list_del(&root->d_subdirs);
205                         list_add(&root->d_subdirs, &dentry->d_child);
206                         dget(dentry);
207                         spin_unlock(&dcache_lock);
208
209                         return dentry;
210                 }
211         }
212         spin_unlock(&dcache_lock);
213
214         return NULL;
215 }
216
217 /* Perform an expiry operation */
218 int autofs4_expire_run(struct super_block *sb,
219                       struct vfsmount *mnt,
220                       struct autofs_sb_info *sbi,
221                       struct autofs_packet_expire *pkt_p)
222 {
223         struct autofs_packet_expire pkt;
224         struct dentry *dentry;
225
226         memset(&pkt,0,sizeof pkt);
227
228         pkt.hdr.proto_version = sbi->version;
229         pkt.hdr.type = autofs_ptype_expire;
230
231         if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL)
232                 return -EAGAIN;
233
234         pkt.len = dentry->d_name.len;
235         memcpy(pkt.name, dentry->d_name.name, pkt.len);
236         pkt.name[pkt.len] = '\0';
237         dput(dentry);
238
239         if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
240                 return -EFAULT;
241
242         return 0;
243 }
244
245 /* Call repeatedly until it returns -EAGAIN, meaning there's nothing
246    more to be done */
247 int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
248                         struct autofs_sb_info *sbi, int *arg)
249 {
250         struct dentry *dentry;
251         int ret = -EAGAIN;
252         int do_now = 0;
253
254         if (arg && get_user(do_now, arg))
255                 return -EFAULT;
256
257         if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) {
258                 struct autofs_info *de_info = autofs4_dentry_ino(dentry);
259
260                 /* This is synchronous because it makes the daemon a
261                    little easier */
262                 de_info->flags |= AUTOFS_INF_EXPIRING;
263                 ret = autofs4_wait(sbi, &dentry->d_name, NFY_EXPIRE);
264                 de_info->flags &= ~AUTOFS_INF_EXPIRING;
265                 dput(dentry);
266         }
267                 
268         return ret;
269 }
270