diff options
-rw-r--r-- | fs/nfs/inode.c | 3 | ||||
-rw-r--r-- | fs/nfs/namespace.c | 25 | ||||
-rw-r--r-- | fs/nfs/sysctl.c | 10 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 3 |
4 files changed, 40 insertions, 1 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 47167ab64f5..3eea556d8f5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -167,6 +167,7 @@ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) struct nfs_server *server; struct rpc_clnt *rpc; + shrink_submounts(vfsmnt, &nfs_automount_list); if (!(flags & MNT_FORCE)) return; /* -EIO all pending I/O */ @@ -1943,6 +1944,7 @@ static void nfs_kill_super(struct super_block *s) nfs_free_iostats(server->io_stats); kfree(server->hostname); kfree(server); + nfs_release_automount_timer(); } static struct file_system_type nfs_fs_type = { @@ -2288,6 +2290,7 @@ static void nfs4_kill_super(struct super_block *sb) nfs_free_iostats(server->io_stats); kfree(server->hostname); kfree(server); + nfs_release_automount_timer(); } static struct file_system_type nfs4_fs_type = { diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index a155505c36f..e426516c111 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -18,6 +18,11 @@ #define NFSDBG_FACILITY NFSDBG_VFS +LIST_HEAD(nfs_automount_list); +static void nfs_expire_automounts(void *list); +static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list); +int nfs_mountpoint_expiry_timeout = 500 * HZ; + /* * nfs_follow_mountpoint - handle crossing a mountpoint on the server * @dentry - dentry of mountpoint @@ -59,7 +64,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) goto out_err; mntget(mnt); - err = do_add_mount(mnt, nd, nd->mnt->mnt_flags, NULL); + err = do_add_mount(mnt, nd, nd->mnt->mnt_flags|MNT_SHRINKABLE, &nfs_automount_list); if (err < 0) { mntput(mnt); if (err == -EBUSY) @@ -70,6 +75,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) dput(nd->dentry); nd->mnt = mnt; nd->dentry = dget(mnt->mnt_root); + schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); out: dprintk("%s: done, returned %d\n", __FUNCTION__, err); return ERR_PTR(err); @@ -87,3 +93,20 @@ struct inode_operations nfs_mountpoint_inode_operations = { .follow_link = nfs_follow_mountpoint, .getattr = nfs_getattr, }; + +static void nfs_expire_automounts(void *data) +{ + struct list_head *list = (struct list_head *)data; + + mark_mounts_for_expiry(list); + if (!list_empty(list)) + schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); +} + +void nfs_release_automount_timer(void) +{ + if (list_empty(&nfs_automount_list)) { + cancel_delayed_work(&nfs_automount_task); + flush_scheduled_work(); + } +} diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index 4c486eb867c..db61e51bb15 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/nfs4.h> #include <linux/nfs_idmap.h> +#include <linux/nfs_fs.h> #include "callback.h" @@ -46,6 +47,15 @@ static ctl_table nfs_cb_sysctls[] = { .strategy = &sysctl_jiffies, }, #endif + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nfs_mountpoint_timeout", + .data = &nfs_mountpoint_expiry_timeout, + .maxlen = sizeof(nfs_mountpoint_expiry_timeout), + .mode = 0644, + .proc_handler = &proc_dointvec_jiffies, + .strategy = &sysctl_jiffies, + }, { .ctl_name = 0 } }; diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 0ce8704732c..a34b3ee443f 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -405,7 +405,10 @@ extern void nfs_unregister_sysctl(void); /* * linux/fs/nfs/namespace.c */ +extern struct list_head nfs_automount_list; extern struct inode_operations nfs_mountpoint_inode_operations; +extern int nfs_mountpoint_expiry_timeout; +extern void nfs_release_automount_timer(void); /* * linux/fs/nfs/unlink.c |