diff options
Diffstat (limited to 'fs/afs/mntpt.c')
-rw-r--r-- | fs/afs/mntpt.c | 141 |
1 files changed, 79 insertions, 62 deletions
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 68495f0de7b3..b905ae37f912 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -1,4 +1,4 @@ -/* mntpt.c: mountpoint management +/* mountpoint management * * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) @@ -18,10 +18,6 @@ #include <linux/mount.h> #include <linux/namei.h> #include <linux/mnt_namespace.h> -#include "super.h" -#include "cell.h" -#include "volume.h" -#include "vnode.h" #include "internal.h" @@ -30,6 +26,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, struct nameidata *nd); static int afs_mntpt_open(struct inode *inode, struct file *file); static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd); +static void afs_mntpt_expiry_timed_out(struct work_struct *work); const struct file_operations afs_mntpt_file_operations = { .open = afs_mntpt_open, @@ -43,24 +40,19 @@ const struct inode_operations afs_mntpt_inode_operations = { }; static LIST_HEAD(afs_vfsmounts); +static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); -static void afs_mntpt_expiry_timed_out(struct afs_timer *timer); +unsigned long afs_mntpt_expiry_timeout = 10 * 60; -struct afs_timer_ops afs_mntpt_expiry_timer_ops = { - .timed_out = afs_mntpt_expiry_timed_out, -}; - -struct afs_timer afs_mntpt_expiry_timer; - -unsigned long afs_mntpt_expiry_timeout = 20; - -/*****************************************************************************/ /* * check a symbolic link to see whether it actually encodes a mountpoint * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately */ -int afs_mntpt_check_symlink(struct afs_vnode *vnode) +int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key) { + struct file file = { + .private_data = key, + }; struct page *page; size_t size; char *buf; @@ -69,7 +61,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode) _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique); /* read the contents of the symlink into the pagecache */ - page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, NULL); + page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file); if (IS_ERR(page)) { ret = PTR_ERR(page); goto out; @@ -85,7 +77,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode) /* examine the symlink's contents */ size = vnode->status.size; - _debug("symlink to %*.*s", size, (int) size, buf); + _debug("symlink to %*.*s", (int) size, (int) size, buf); if (size > 2 && (buf[0] == '%' || buf[0] == '#') && @@ -93,22 +85,20 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode) ) { _debug("symlink is a mountpoint"); spin_lock(&vnode->lock); - vnode->flags |= AFS_VNODE_MOUNTPOINT; + set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); spin_unlock(&vnode->lock); } ret = 0; - out_free: +out_free: kunmap(page); page_cache_release(page); - out: +out: _leave(" = %d", ret); return ret; +} -} /* end afs_mntpt_check_symlink() */ - -/*****************************************************************************/ /* * no valid lookup procedure on this sort of dir */ @@ -116,7 +106,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - kenter("%p,%p{%p{%s},%s}", + _enter("%p,%p{%p{%s},%s}", dir, dentry, dentry->d_parent, @@ -125,15 +115,14 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, dentry->d_name.name); return ERR_PTR(-EREMOTE); -} /* end afs_mntpt_lookup() */ +} -/*****************************************************************************/ /* * no valid open procedure on this sort of dir */ static int afs_mntpt_open(struct inode *inode, struct file *file) { - kenter("%p,%p{%p{%s},%s}", + _enter("%p,%p{%p{%s},%s}", inode, file, file->f_path.dentry->d_parent, file->f_path.dentry->d_parent ? @@ -142,9 +131,8 @@ static int afs_mntpt_open(struct inode *inode, struct file *file) file->f_path.dentry->d_name.name); return -EREMOTE; -} /* end afs_mntpt_open() */ +} -/*****************************************************************************/ /* * create a vfsmount to be automounted */ @@ -157,7 +145,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) char *buf, *devname = NULL, *options = NULL; int ret; - kenter("{%s}", mntpt->d_name.name); + _enter("{%s}", mntpt->d_name.name); BUG_ON(!mntpt->d_inode); @@ -201,79 +189,108 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) strcat(options, ",rwpath"); /* try and do the mount */ - kdebug("--- attempting mount %s -o %s ---", devname, options); + _debug("--- attempting mount %s -o %s ---", devname, options); mnt = vfs_kern_mount(&afs_fs_type, 0, devname, options); - kdebug("--- mount result %p ---", mnt); + _debug("--- mount result %p ---", mnt); free_page((unsigned long) devname); free_page((unsigned long) options); - kleave(" = %p", mnt); + _leave(" = %p", mnt); return mnt; - error: +error: if (page) page_cache_release(page); if (devname) free_page((unsigned long) devname); if (options) free_page((unsigned long) options); - kleave(" = %d", ret); + _leave(" = %d", ret); return ERR_PTR(ret); -} /* end afs_mntpt_do_automount() */ +} -/*****************************************************************************/ /* * follow a link from a mountpoint directory, thus causing it to be mounted */ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) { struct vfsmount *newmnt; - struct dentry *old_dentry; int err; - kenter("%p{%s},{%s:%p{%s}}", + _enter("%p{%s},{%s:%p{%s},}", dentry, dentry->d_name.name, nd->mnt->mnt_devname, dentry, nd->dentry->d_name.name); - newmnt = afs_mntpt_do_automount(dentry); + dput(nd->dentry); + nd->dentry = dget(dentry); + + newmnt = afs_mntpt_do_automount(nd->dentry); if (IS_ERR(newmnt)) { path_release(nd); return (void *)newmnt; } - old_dentry = nd->dentry; - nd->dentry = dentry; - err = do_add_mount(newmnt, nd, 0, &afs_vfsmounts); - nd->dentry = old_dentry; - - path_release(nd); - - if (!err) { - mntget(newmnt); + mntget(newmnt); + err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts); + switch (err) { + case 0: + mntput(nd->mnt); + dput(nd->dentry); nd->mnt = newmnt; - dget(newmnt->mnt_root); - nd->dentry = newmnt->mnt_root; + nd->dentry = dget(newmnt->mnt_root); + schedule_delayed_work(&afs_mntpt_expiry_timer, + afs_mntpt_expiry_timeout * HZ); + break; + case -EBUSY: + /* someone else made a mount here whilst we were busy */ + while (d_mountpoint(nd->dentry) && + follow_down(&nd->mnt, &nd->dentry)) + ; + err = 0; + default: + mntput(newmnt); + break; } - kleave(" = %d", err); + _leave(" = %d", err); return ERR_PTR(err); -} /* end afs_mntpt_follow_link() */ +} -/*****************************************************************************/ /* * handle mountpoint expiry timer going off */ -static void afs_mntpt_expiry_timed_out(struct afs_timer *timer) +static void afs_mntpt_expiry_timed_out(struct work_struct *work) { - kenter(""); + _enter(""); - mark_mounts_for_expiry(&afs_vfsmounts); + if (!list_empty(&afs_vfsmounts)) { + mark_mounts_for_expiry(&afs_vfsmounts); + schedule_delayed_work(&afs_mntpt_expiry_timer, + afs_mntpt_expiry_timeout * HZ); + } + + _leave(""); +} - afs_kafstimod_add_timer(&afs_mntpt_expiry_timer, - afs_mntpt_expiry_timeout * HZ); +/* + * kill the AFS mountpoint timer if it's still running + */ +void afs_mntpt_kill_timer(void) +{ + _enter(""); - kleave(""); -} /* end afs_mntpt_expiry_timed_out() */ + ASSERT(list_empty(&afs_vfsmounts)); + cancel_delayed_work(&afs_mntpt_expiry_timer); + flush_scheduled_work(); +} + +/* + * begin unmount by attempting to remove all automounted mountpoints we added + */ +void afs_umount_begin(struct vfsmount *vfsmnt, int flags) +{ + shrink_submounts(vfsmnt, &afs_vfsmounts); +} |