diff options
-rw-r--r-- | fs/nfs/delegation.c | 46 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 20 | ||||
-rw-r--r-- | fs/nfs/nfs4renewd.c | 9 |
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 | ||
235 | int 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); | ||
243 | restart: | ||
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 | } | ||
259 | out: | ||
260 | spin_unlock(&clp->cl_lock); | ||
261 | nfs4_put_client(clp); | ||
262 | module_put_and_exit(0); | ||
263 | } | ||
264 | |||
265 | void 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 | ||
31 | struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); | 31 | struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); |
32 | void nfs_return_all_delegations(struct super_block *sb); | 32 | void nfs_return_all_delegations(struct super_block *sb); |
33 | void nfs_expire_all_delegations(struct nfs4_client *clp); | ||
33 | void nfs_handle_cb_pathdown(struct nfs4_client *clp); | 34 | void nfs_handle_cb_pathdown(struct nfs4_client *clp); |
34 | 35 | ||
35 | void nfs_delegation_mark_reclaim(struct nfs4_client *clp); | 36 | void 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 | ||
40 | enum nfs4_client_state { | 40 | enum 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 | |||
63 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | 63 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); |
64 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | 64 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); |
65 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | 65 | static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); |
66 | static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp); | ||
66 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | 67 | extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); |
67 | extern struct rpc_procinfo nfs4_procedures[]; | 68 | extern struct rpc_procinfo nfs4_procedures[]; |
68 | 69 | ||
@@ -765,6 +766,15 @@ out: | |||
765 | return -EACCES; | 766 | return -EACCES; |
766 | } | 767 | } |
767 | 768 | ||
769 | int 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); |