diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/inode.c | 3 | ||||
-rw-r--r-- | fs/nfs/namespace.c | 25 | ||||
-rw-r--r-- | fs/nfs/sysctl.c | 10 |
3 files changed, 37 insertions, 1 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 47167ab64f5b..3eea556d8f59 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) | |||
167 | struct nfs_server *server; | 167 | struct nfs_server *server; |
168 | struct rpc_clnt *rpc; | 168 | struct rpc_clnt *rpc; |
169 | 169 | ||
170 | shrink_submounts(vfsmnt, &nfs_automount_list); | ||
170 | if (!(flags & MNT_FORCE)) | 171 | if (!(flags & MNT_FORCE)) |
171 | return; | 172 | return; |
172 | /* -EIO all pending I/O */ | 173 | /* -EIO all pending I/O */ |
@@ -1943,6 +1944,7 @@ static void nfs_kill_super(struct super_block *s) | |||
1943 | nfs_free_iostats(server->io_stats); | 1944 | nfs_free_iostats(server->io_stats); |
1944 | kfree(server->hostname); | 1945 | kfree(server->hostname); |
1945 | kfree(server); | 1946 | kfree(server); |
1947 | nfs_release_automount_timer(); | ||
1946 | } | 1948 | } |
1947 | 1949 | ||
1948 | static struct file_system_type nfs_fs_type = { | 1950 | static struct file_system_type nfs_fs_type = { |
@@ -2288,6 +2290,7 @@ static void nfs4_kill_super(struct super_block *sb) | |||
2288 | nfs_free_iostats(server->io_stats); | 2290 | nfs_free_iostats(server->io_stats); |
2289 | kfree(server->hostname); | 2291 | kfree(server->hostname); |
2290 | kfree(server); | 2292 | kfree(server); |
2293 | nfs_release_automount_timer(); | ||
2291 | } | 2294 | } |
2292 | 2295 | ||
2293 | static struct file_system_type nfs4_fs_type = { | 2296 | static struct file_system_type nfs4_fs_type = { |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index a155505c36f1..e426516c1116 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -18,6 +18,11 @@ | |||
18 | 18 | ||
19 | #define NFSDBG_FACILITY NFSDBG_VFS | 19 | #define NFSDBG_FACILITY NFSDBG_VFS |
20 | 20 | ||
21 | LIST_HEAD(nfs_automount_list); | ||
22 | static void nfs_expire_automounts(void *list); | ||
23 | static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list); | ||
24 | int nfs_mountpoint_expiry_timeout = 500 * HZ; | ||
25 | |||
21 | /* | 26 | /* |
22 | * nfs_follow_mountpoint - handle crossing a mountpoint on the server | 27 | * nfs_follow_mountpoint - handle crossing a mountpoint on the server |
23 | * @dentry - dentry of mountpoint | 28 | * @dentry - dentry of mountpoint |
@@ -59,7 +64,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
59 | goto out_err; | 64 | goto out_err; |
60 | 65 | ||
61 | mntget(mnt); | 66 | mntget(mnt); |
62 | err = do_add_mount(mnt, nd, nd->mnt->mnt_flags, NULL); | 67 | err = do_add_mount(mnt, nd, nd->mnt->mnt_flags|MNT_SHRINKABLE, &nfs_automount_list); |
63 | if (err < 0) { | 68 | if (err < 0) { |
64 | mntput(mnt); | 69 | mntput(mnt); |
65 | if (err == -EBUSY) | 70 | if (err == -EBUSY) |
@@ -70,6 +75,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
70 | dput(nd->dentry); | 75 | dput(nd->dentry); |
71 | nd->mnt = mnt; | 76 | nd->mnt = mnt; |
72 | nd->dentry = dget(mnt->mnt_root); | 77 | nd->dentry = dget(mnt->mnt_root); |
78 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); | ||
73 | out: | 79 | out: |
74 | dprintk("%s: done, returned %d\n", __FUNCTION__, err); | 80 | dprintk("%s: done, returned %d\n", __FUNCTION__, err); |
75 | return ERR_PTR(err); | 81 | return ERR_PTR(err); |
@@ -87,3 +93,20 @@ struct inode_operations nfs_mountpoint_inode_operations = { | |||
87 | .follow_link = nfs_follow_mountpoint, | 93 | .follow_link = nfs_follow_mountpoint, |
88 | .getattr = nfs_getattr, | 94 | .getattr = nfs_getattr, |
89 | }; | 95 | }; |
96 | |||
97 | static void nfs_expire_automounts(void *data) | ||
98 | { | ||
99 | struct list_head *list = (struct list_head *)data; | ||
100 | |||
101 | mark_mounts_for_expiry(list); | ||
102 | if (!list_empty(list)) | ||
103 | schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); | ||
104 | } | ||
105 | |||
106 | void nfs_release_automount_timer(void) | ||
107 | { | ||
108 | if (list_empty(&nfs_automount_list)) { | ||
109 | cancel_delayed_work(&nfs_automount_task); | ||
110 | flush_scheduled_work(); | ||
111 | } | ||
112 | } | ||
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index 4c486eb867ca..db61e51bb154 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/nfs4.h> | 13 | #include <linux/nfs4.h> |
14 | #include <linux/nfs_idmap.h> | 14 | #include <linux/nfs_idmap.h> |
15 | #include <linux/nfs_fs.h> | ||
15 | 16 | ||
16 | #include "callback.h" | 17 | #include "callback.h" |
17 | 18 | ||
@@ -46,6 +47,15 @@ static ctl_table nfs_cb_sysctls[] = { | |||
46 | .strategy = &sysctl_jiffies, | 47 | .strategy = &sysctl_jiffies, |
47 | }, | 48 | }, |
48 | #endif | 49 | #endif |
50 | { | ||
51 | .ctl_name = CTL_UNNUMBERED, | ||
52 | .procname = "nfs_mountpoint_timeout", | ||
53 | .data = &nfs_mountpoint_expiry_timeout, | ||
54 | .maxlen = sizeof(nfs_mountpoint_expiry_timeout), | ||
55 | .mode = 0644, | ||
56 | .proc_handler = &proc_dointvec_jiffies, | ||
57 | .strategy = &sysctl_jiffies, | ||
58 | }, | ||
49 | { .ctl_name = 0 } | 59 | { .ctl_name = 0 } |
50 | }; | 60 | }; |
51 | 61 | ||