aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/delegation.c46
-rw-r--r--fs/nfs/delegation.h1
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4proc.c20
-rw-r--r--fs/nfs/nfs4renewd.c9
5 files changed, 75 insertions, 2 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 618a327027b3..75dfb1c717a0 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -8,6 +8,7 @@
8 */ 8 */
9#include <linux/config.h> 9#include <linux/config.h>
10#include <linux/completion.h> 10#include <linux/completion.h>
11#include <linux/kthread.h>
11#include <linux/module.h> 12#include <linux/module.h>
12#include <linux/sched.h> 13#include <linux/sched.h>
13#include <linux/spinlock.h> 14#include <linux/spinlock.h>
@@ -231,6 +232,51 @@ restart:
231 spin_unlock(&clp->cl_lock); 232 spin_unlock(&clp->cl_lock);
232} 233}
233 234
235int nfs_do_expire_all_delegations(void *ptr)
236{
237 struct nfs4_client *clp = ptr;
238 struct nfs_delegation *delegation;
239 struct inode *inode;
240 int err = 0;
241
242 allow_signal(SIGKILL);
243restart:
244 spin_lock(&clp->cl_lock);
245 if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0)
246 goto out;
247 if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0)
248 goto out;
249 list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
250 inode = igrab(delegation->inode);
251 if (inode == NULL)
252 continue;
253 spin_unlock(&clp->cl_lock);
254 err = nfs_inode_return_delegation(inode);
255 iput(inode);
256 if (!err)
257 goto restart;
258 }
259out:
260 spin_unlock(&clp->cl_lock);
261 nfs4_put_client(clp);
262 module_put_and_exit(0);
263}
264
265void nfs_expire_all_delegations(struct nfs4_client *clp)
266{
267 struct task_struct *task;
268
269 __module_get(THIS_MODULE);
270 atomic_inc(&clp->cl_count);
271 task = kthread_run(nfs_do_expire_all_delegations, clp,
272 "%u.%u.%u.%u-delegreturn",
273 NIPQUAD(clp->cl_addr));
274 if (!IS_ERR(task))
275 return;
276 nfs4_put_client(clp);
277 module_put(THIS_MODULE);
278}
279
234/* 280/*
235 * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. 281 * Return all delegations following an NFS4ERR_CB_PATH_DOWN error.
236 */ 282 */
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index 2fcc30de924b..fbc50ec271c5 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -30,6 +30,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s
30 30
31struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); 31struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle);
32void nfs_return_all_delegations(struct super_block *sb); 32void nfs_return_all_delegations(struct super_block *sb);
33void nfs_expire_all_delegations(struct nfs4_client *clp);
33void nfs_handle_cb_pathdown(struct nfs4_client *clp); 34void nfs_handle_cb_pathdown(struct nfs4_client *clp);
34 35
35void nfs_delegation_mark_reclaim(struct nfs4_client *clp); 36void nfs_delegation_mark_reclaim(struct nfs4_client *clp);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 1d4c5b339b4d..75fe646c28ab 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -39,6 +39,7 @@ struct idmap;
39 39
40enum nfs4_client_state { 40enum nfs4_client_state {
41 NFS4CLNT_STATE_RECOVER = 0, 41 NFS4CLNT_STATE_RECOVER = 0,
42 NFS4CLNT_LEASE_EXPIRED,
42}; 43};
43 44
44/* 45/*
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 46623ac3ce86..cc33a1c32cfb 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -63,6 +63,7 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf
63static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); 63static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *);
64static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); 64static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
65static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); 65static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
66static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp);
66extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); 67extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
67extern struct rpc_procinfo nfs4_procedures[]; 68extern struct rpc_procinfo nfs4_procedures[];
68 69
@@ -765,6 +766,15 @@ out:
765 return -EACCES; 766 return -EACCES;
766} 767}
767 768
769int nfs4_recover_expired_lease(struct nfs_server *server)
770{
771 struct nfs4_client *clp = server->nfs4_state;
772
773 if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
774 nfs4_schedule_state_recovery(clp);
775 return nfs4_wait_clnt_recover(server->client, clp);
776}
777
768/* 778/*
769 * OPEN_EXPIRED: 779 * OPEN_EXPIRED:
770 * reclaim state on the server after a network partition. 780 * reclaim state on the server after a network partition.
@@ -840,6 +850,9 @@ static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred
840 int open_flags = flags & (FMODE_READ|FMODE_WRITE); 850 int open_flags = flags & (FMODE_READ|FMODE_WRITE);
841 int err; 851 int err;
842 852
853 err = nfs4_recover_expired_lease(server);
854 if (err != 0)
855 return err;
843 /* Protect against reboot recovery - NOTE ORDER! */ 856 /* Protect against reboot recovery - NOTE ORDER! */
844 down_read(&clp->cl_sem); 857 down_read(&clp->cl_sem);
845 /* Protect against delegation recall */ 858 /* Protect against delegation recall */
@@ -921,12 +934,16 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
921 int status; 934 int status;
922 935
923 /* Protect against reboot recovery conflicts */ 936 /* Protect against reboot recovery conflicts */
924 down_read(&clp->cl_sem);
925 status = -ENOMEM; 937 status = -ENOMEM;
926 if (!(sp = nfs4_get_state_owner(server, cred))) { 938 if (!(sp = nfs4_get_state_owner(server, cred))) {
927 dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); 939 dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
928 goto out_err; 940 goto out_err;
929 } 941 }
942 status = nfs4_recover_expired_lease(server);
943 if (status != 0)
944 goto out_err;
945 down_read(&clp->cl_sem);
946 status = -ENOMEM;
930 opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); 947 opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr);
931 if (opendata == NULL) 948 if (opendata == NULL)
932 goto err_put_state_owner; 949 goto err_put_state_owner;
@@ -2897,6 +2914,7 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp)
2897 spin_lock(&clp->cl_lock); 2914 spin_lock(&clp->cl_lock);
2898 clp->cl_lease_time = fsinfo.lease_time * HZ; 2915 clp->cl_lease_time = fsinfo.lease_time * HZ;
2899 clp->cl_last_renewal = now; 2916 clp->cl_last_renewal = now;
2917 clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
2900 spin_unlock(&clp->cl_lock); 2918 spin_unlock(&clp->cl_lock);
2901 } 2919 }
2902 return status; 2920 return status;
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index a3001628ad32..f62c2f7a4ffb 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -54,6 +54,7 @@
54#include <linux/nfs4.h> 54#include <linux/nfs4.h>
55#include <linux/nfs_fs.h> 55#include <linux/nfs_fs.h>
56#include "nfs4_fs.h" 56#include "nfs4_fs.h"
57#include "delegation.h"
57 58
58#define NFSDBG_FACILITY NFSDBG_PROC 59#define NFSDBG_FACILITY NFSDBG_PROC
59 60
@@ -68,7 +69,7 @@ nfs4_renew_state(void *data)
68 dprintk("%s: start\n", __FUNCTION__); 69 dprintk("%s: start\n", __FUNCTION__);
69 /* Are there any active superblocks? */ 70 /* Are there any active superblocks? */
70 if (list_empty(&clp->cl_superblocks)) 71 if (list_empty(&clp->cl_superblocks))
71 goto out; 72 goto out;
72 spin_lock(&clp->cl_lock); 73 spin_lock(&clp->cl_lock);
73 lease = clp->cl_lease_time; 74 lease = clp->cl_lease_time;
74 last = clp->cl_last_renewal; 75 last = clp->cl_last_renewal;
@@ -76,6 +77,12 @@ nfs4_renew_state(void *data)
76 timeout = (2 * lease) / 3 + (long)last - (long)now; 77 timeout = (2 * lease) / 3 + (long)last - (long)now;
77 /* Are we close to a lease timeout? */ 78 /* Are we close to a lease timeout? */
78 if (time_after(now, last + lease/3)) { 79 if (time_after(now, last + lease/3)) {
80 if (list_empty(&clp->cl_state_owners)) {
81 set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
82 spin_unlock(&clp->cl_lock);
83 nfs_expire_all_delegations(clp);
84 goto out;
85 }
79 spin_unlock(&clp->cl_lock); 86 spin_unlock(&clp->cl_lock);
80 /* Queue an asynchronous RENEW. */ 87 /* Queue an asynchronous RENEW. */
81 nfs4_proc_async_renew(clp); 88 nfs4_proc_async_renew(clp);