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