diff options
Diffstat (limited to 'fs/afs/mntpt.c')
-rw-r--r-- | fs/afs/mntpt.c | 106 |
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); |
31 | static int afs_mntpt_open(struct inode *inode, struct file *file); | 27 | static int afs_mntpt_open(struct inode *inode, struct file *file); |
32 | static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd); | 28 | static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd); |
29 | static void afs_mntpt_expiry_timed_out(struct work_struct *work); | ||
33 | 30 | ||
34 | const struct file_operations afs_mntpt_file_operations = { | 31 | const 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 | ||
45 | static LIST_HEAD(afs_vfsmounts); | 42 | static LIST_HEAD(afs_vfsmounts); |
43 | static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); | ||
46 | 44 | ||
47 | static void afs_mntpt_expiry_timed_out(struct afs_timer *timer); | 45 | unsigned long afs_mntpt_expiry_timeout = 10 * 60; |
48 | |||
49 | struct afs_timer_ops afs_mntpt_expiry_timer_ops = { | ||
50 | .timed_out = afs_mntpt_expiry_timed_out, | ||
51 | }; | ||
52 | |||
53 | struct afs_timer afs_mntpt_expiry_timer; | ||
54 | |||
55 | unsigned 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 | */ |
130 | static int afs_mntpt_open(struct inode *inode, struct file *file) | 120 | static 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 | ||
208 | error: | 198 | error: |
@@ -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: | |||
222 | static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) | 212 | static 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 | */ |
262 | static void afs_mntpt_expiry_timed_out(struct afs_timer *timer) | 261 | static 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 | */ | ||
277 | void 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 | */ | ||
289 | void afs_umount_begin(struct vfsmount *vfsmnt, int flags) | ||
290 | { | ||
291 | shrink_submounts(vfsmnt, &afs_vfsmounts); | ||
272 | } | 292 | } |