aboutsummaryrefslogtreecommitdiffstats
path: root/fs/afs/mntpt.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs/mntpt.c')
-rw-r--r--fs/afs/mntpt.c106
1 files changed, 63 insertions, 43 deletions
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index ca3fa81b068a..08c11a0b66bd 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -18,10 +18,6 @@
18#include <linux/mount.h> 18#include <linux/mount.h>
19#include <linux/namei.h> 19#include <linux/namei.h>
20#include <linux/mnt_namespace.h> 20#include <linux/mnt_namespace.h>
21#include "super.h"
22#include "cell.h"
23#include "volume.h"
24#include "vnode.h"
25#include "internal.h" 21#include "internal.h"
26 22
27 23
@@ -30,6 +26,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
30 struct nameidata *nd); 26 struct nameidata *nd);
31static int afs_mntpt_open(struct inode *inode, struct file *file); 27static int afs_mntpt_open(struct inode *inode, struct file *file);
32static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd); 28static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd);
29static void afs_mntpt_expiry_timed_out(struct work_struct *work);
33 30
34const struct file_operations afs_mntpt_file_operations = { 31const struct file_operations afs_mntpt_file_operations = {
35 .open = afs_mntpt_open, 32 .open = afs_mntpt_open,
@@ -43,16 +40,9 @@ const struct inode_operations afs_mntpt_inode_operations = {
43}; 40};
44 41
45static LIST_HEAD(afs_vfsmounts); 42static LIST_HEAD(afs_vfsmounts);
43static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);
46 44
47static void afs_mntpt_expiry_timed_out(struct afs_timer *timer); 45unsigned long afs_mntpt_expiry_timeout = 10 * 60;
48
49struct afs_timer_ops afs_mntpt_expiry_timer_ops = {
50 .timed_out = afs_mntpt_expiry_timed_out,
51};
52
53struct afs_timer afs_mntpt_expiry_timer;
54
55unsigned long afs_mntpt_expiry_timeout = 20;
56 46
57/* 47/*
58 * check a symbolic link to see whether it actually encodes a mountpoint 48 * check a symbolic link to see whether it actually encodes a mountpoint
@@ -84,7 +74,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode)
84 74
85 /* examine the symlink's contents */ 75 /* examine the symlink's contents */
86 size = vnode->status.size; 76 size = vnode->status.size;
87 _debug("symlink to %*.*s", size, (int) size, buf); 77 _debug("symlink to %*.*s", (int) size, (int) size, buf);
88 78
89 if (size > 2 && 79 if (size > 2 &&
90 (buf[0] == '%' || buf[0] == '#') && 80 (buf[0] == '%' || buf[0] == '#') &&
@@ -92,7 +82,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode)
92 ) { 82 ) {
93 _debug("symlink is a mountpoint"); 83 _debug("symlink is a mountpoint");
94 spin_lock(&vnode->lock); 84 spin_lock(&vnode->lock);
95 vnode->flags |= AFS_VNODE_MOUNTPOINT; 85 set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
96 spin_unlock(&vnode->lock); 86 spin_unlock(&vnode->lock);
97 } 87 }
98 88
@@ -113,7 +103,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
113 struct dentry *dentry, 103 struct dentry *dentry,
114 struct nameidata *nd) 104 struct nameidata *nd)
115{ 105{
116 kenter("%p,%p{%p{%s},%s}", 106 _enter("%p,%p{%p{%s},%s}",
117 dir, 107 dir,
118 dentry, 108 dentry,
119 dentry->d_parent, 109 dentry->d_parent,
@@ -129,7 +119,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
129 */ 119 */
130static int afs_mntpt_open(struct inode *inode, struct file *file) 120static int afs_mntpt_open(struct inode *inode, struct file *file)
131{ 121{
132 kenter("%p,%p{%p{%s},%s}", 122 _enter("%p,%p{%p{%s},%s}",
133 inode, file, 123 inode, file,
134 file->f_path.dentry->d_parent, 124 file->f_path.dentry->d_parent,
135 file->f_path.dentry->d_parent ? 125 file->f_path.dentry->d_parent ?
@@ -152,7 +142,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
152 char *buf, *devname = NULL, *options = NULL; 142 char *buf, *devname = NULL, *options = NULL;
153 int ret; 143 int ret;
154 144
155 kenter("{%s}", mntpt->d_name.name); 145 _enter("{%s}", mntpt->d_name.name);
156 146
157 BUG_ON(!mntpt->d_inode); 147 BUG_ON(!mntpt->d_inode);
158 148
@@ -196,13 +186,13 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
196 strcat(options, ",rwpath"); 186 strcat(options, ",rwpath");
197 187
198 /* try and do the mount */ 188 /* try and do the mount */
199 kdebug("--- attempting mount %s -o %s ---", devname, options); 189 _debug("--- attempting mount %s -o %s ---", devname, options);
200 mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options); 190 mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options);
201 kdebug("--- mount result %p ---", mnt); 191 _debug("--- mount result %p ---", mnt);
202 192
203 free_page((unsigned long) devname); 193 free_page((unsigned long) devname);
204 free_page((unsigned long) options); 194 free_page((unsigned long) options);
205 kleave(" = %p", mnt); 195 _leave(" = %p", mnt);
206 return mnt; 196 return mnt;
207 197
208error: 198error:
@@ -212,7 +202,7 @@ error:
212 free_page((unsigned long) devname); 202 free_page((unsigned long) devname);
213 if (options) 203 if (options)
214 free_page((unsigned long) options); 204 free_page((unsigned long) options);
215 kleave(" = %d", ret); 205 _leave(" = %d", ret);
216 return ERR_PTR(ret); 206 return ERR_PTR(ret);
217} 207}
218 208
@@ -222,51 +212,81 @@ error:
222static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) 212static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd)
223{ 213{
224 struct vfsmount *newmnt; 214 struct vfsmount *newmnt;
225 struct dentry *old_dentry;
226 int err; 215 int err;
227 216
228 kenter("%p{%s},{%s:%p{%s}}", 217 _enter("%p{%s},{%s:%p{%s}}",
229 dentry, 218 dentry,
230 dentry->d_name.name, 219 dentry->d_name.name,
231 nd->mnt->mnt_devname, 220 nd->mnt->mnt_devname,
232 dentry, 221 dentry,
233 nd->dentry->d_name.name); 222 nd->dentry->d_name.name);
234 223
235 newmnt = afs_mntpt_do_automount(dentry); 224 dput(nd->dentry);
225 nd->dentry = dget(dentry);
226
227 newmnt = afs_mntpt_do_automount(nd->dentry);
236 if (IS_ERR(newmnt)) { 228 if (IS_ERR(newmnt)) {
237 path_release(nd); 229 path_release(nd);
238 return (void *)newmnt; 230 return (void *)newmnt;
239 } 231 }
240 232
241 old_dentry = nd->dentry; 233 mntget(newmnt);
242 nd->dentry = dentry; 234 err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts);
243 err = do_add_mount(newmnt, nd, 0, &afs_vfsmounts); 235 switch (err) {
244 nd->dentry = old_dentry; 236 case 0:
245 237 path_release(nd);
246 path_release(nd);
247
248 if (!err) {
249 mntget(newmnt);
250 nd->mnt = newmnt; 238 nd->mnt = newmnt;
251 dget(newmnt->mnt_root); 239 nd->dentry = dget(newmnt->mnt_root);
252 nd->dentry = newmnt->mnt_root; 240 schedule_delayed_work(&afs_mntpt_expiry_timer,
241 afs_mntpt_expiry_timeout * HZ);
242 break;
243 case -EBUSY:
244 /* someone else made a mount here whilst we were busy */
245 while (d_mountpoint(nd->dentry) &&
246 follow_down(&nd->mnt, &nd->dentry))
247 ;
248 err = 0;
249 default:
250 mntput(newmnt);
251 break;
253 } 252 }
254 253
255 kleave(" = %d", err); 254 _leave(" = %d", err);
256 return ERR_PTR(err); 255 return ERR_PTR(err);
257} 256}
258 257
259/* 258/*
260 * handle mountpoint expiry timer going off 259 * handle mountpoint expiry timer going off
261 */ 260 */
262static void afs_mntpt_expiry_timed_out(struct afs_timer *timer) 261static void afs_mntpt_expiry_timed_out(struct work_struct *work)
263{ 262{
264 kenter(""); 263 _enter("");
264
265 if (!list_empty(&afs_vfsmounts)) {
266 mark_mounts_for_expiry(&afs_vfsmounts);
267 schedule_delayed_work(&afs_mntpt_expiry_timer,
268 afs_mntpt_expiry_timeout * HZ);
269 }
270
271 _leave("");
272}
265 273
266 mark_mounts_for_expiry(&afs_vfsmounts); 274/*
275 * kill the AFS mountpoint timer if it's still running
276 */
277void afs_mntpt_kill_timer(void)
278{
279 _enter("");
267 280
268 afs_kafstimod_add_timer(&afs_mntpt_expiry_timer, 281 ASSERT(list_empty(&afs_vfsmounts));
269 afs_mntpt_expiry_timeout * HZ); 282 cancel_delayed_work(&afs_mntpt_expiry_timer);
283 flush_scheduled_work();
284}
270 285
271 kleave(""); 286/*
287 * begin unmount by attempting to remove all automounted mountpoints we added
288 */
289void afs_umount_begin(struct vfsmount *vfsmnt, int flags)
290{
291 shrink_submounts(vfsmnt, &afs_vfsmounts);
272} 292}