mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	NFSv4: Send RENEW requests to the server only when we're holding state
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
		
							parent
							
								
									5043e900f5
								
							
						
					
					
						commit
						58d9714a44
					
				
					 5 changed files with 75 additions and 2 deletions
				
			
		|  | @ -8,6 +8,7 @@ | |||
|  */ | ||||
| #include <linux/config.h> | ||||
| #include <linux/completion.h> | ||||
| #include <linux/kthread.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/spinlock.h> | ||||
|  | @ -231,6 +232,51 @@ restart: | |||
| 	spin_unlock(&clp->cl_lock); | ||||
| } | ||||
| 
 | ||||
| int nfs_do_expire_all_delegations(void *ptr) | ||||
| { | ||||
| 	struct nfs4_client *clp = ptr; | ||||
| 	struct nfs_delegation *delegation; | ||||
| 	struct inode *inode; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	allow_signal(SIGKILL); | ||||
| restart: | ||||
| 	spin_lock(&clp->cl_lock); | ||||
| 	if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) | ||||
| 		goto out; | ||||
| 	if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) | ||||
| 		goto out; | ||||
| 	list_for_each_entry(delegation, &clp->cl_delegations, super_list) { | ||||
| 		inode = igrab(delegation->inode); | ||||
| 		if (inode == NULL) | ||||
| 			continue; | ||||
| 		spin_unlock(&clp->cl_lock); | ||||
| 		err = nfs_inode_return_delegation(inode); | ||||
| 		iput(inode); | ||||
| 		if (!err) | ||||
| 			goto restart; | ||||
| 	} | ||||
| out: | ||||
| 	spin_unlock(&clp->cl_lock); | ||||
| 	nfs4_put_client(clp); | ||||
| 	module_put_and_exit(0); | ||||
| } | ||||
| 
 | ||||
| void nfs_expire_all_delegations(struct nfs4_client *clp) | ||||
| { | ||||
| 	struct task_struct *task; | ||||
| 
 | ||||
| 	__module_get(THIS_MODULE); | ||||
| 	atomic_inc(&clp->cl_count); | ||||
| 	task = kthread_run(nfs_do_expire_all_delegations, clp, | ||||
| 			"%u.%u.%u.%u-delegreturn", | ||||
| 			NIPQUAD(clp->cl_addr)); | ||||
| 	if (!IS_ERR(task)) | ||||
| 		return; | ||||
| 	nfs4_put_client(clp); | ||||
| 	module_put(THIS_MODULE); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. | ||||
|  */ | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s | |||
| 
 | ||||
| struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle); | ||||
| void nfs_return_all_delegations(struct super_block *sb); | ||||
| void nfs_expire_all_delegations(struct nfs4_client *clp); | ||||
| void nfs_handle_cb_pathdown(struct nfs4_client *clp); | ||||
| 
 | ||||
| void nfs_delegation_mark_reclaim(struct nfs4_client *clp); | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ struct idmap; | |||
| 
 | ||||
| enum nfs4_client_state { | ||||
| 	NFS4CLNT_STATE_RECOVER  = 0, | ||||
| 	NFS4CLNT_LEASE_EXPIRED, | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -63,6 +63,7 @@ static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinf | |||
| static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *); | ||||
| static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry); | ||||
| static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception); | ||||
| static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp); | ||||
| extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); | ||||
| extern struct rpc_procinfo nfs4_procedures[]; | ||||
| 
 | ||||
|  | @ -765,6 +766,15 @@ out: | |||
| 	return -EACCES; | ||||
| } | ||||
| 
 | ||||
| int nfs4_recover_expired_lease(struct nfs_server *server) | ||||
| { | ||||
| 	struct nfs4_client *clp = server->nfs4_state; | ||||
| 
 | ||||
| 	if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | ||||
| 		nfs4_schedule_state_recovery(clp); | ||||
| 	return nfs4_wait_clnt_recover(server->client, clp); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * OPEN_EXPIRED: | ||||
|  * 	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 | |||
| 	int open_flags = flags & (FMODE_READ|FMODE_WRITE); | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = nfs4_recover_expired_lease(server); | ||||
| 	if (err != 0) | ||||
| 		return err; | ||||
| 	/* Protect against reboot recovery - NOTE ORDER! */ | ||||
| 	down_read(&clp->cl_sem); | ||||
| 	/* Protect against delegation recall */ | ||||
|  | @ -921,12 +934,16 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st | |||
| 	int                     status; | ||||
| 
 | ||||
| 	/* Protect against reboot recovery conflicts */ | ||||
| 	down_read(&clp->cl_sem); | ||||
| 	status = -ENOMEM; | ||||
| 	if (!(sp = nfs4_get_state_owner(server, cred))) { | ||||
| 		dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); | ||||
| 		goto out_err; | ||||
| 	} | ||||
| 	status = nfs4_recover_expired_lease(server); | ||||
| 	if (status != 0) | ||||
| 		goto out_err; | ||||
| 	down_read(&clp->cl_sem); | ||||
| 	status = -ENOMEM; | ||||
| 	opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); | ||||
| 	if (opendata == NULL) | ||||
| 		goto err_put_state_owner; | ||||
|  | @ -2897,6 +2914,7 @@ nfs4_proc_setclientid_confirm(struct nfs4_client *clp) | |||
| 		spin_lock(&clp->cl_lock); | ||||
| 		clp->cl_lease_time = fsinfo.lease_time * HZ; | ||||
| 		clp->cl_last_renewal = now; | ||||
| 		clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||||
| 		spin_unlock(&clp->cl_lock); | ||||
| 	} | ||||
| 	return status; | ||||
|  |  | |||
|  | @ -54,6 +54,7 @@ | |||
| #include <linux/nfs4.h> | ||||
| #include <linux/nfs_fs.h> | ||||
| #include "nfs4_fs.h" | ||||
| #include "delegation.h" | ||||
| 
 | ||||
| #define NFSDBG_FACILITY	NFSDBG_PROC | ||||
| 
 | ||||
|  | @ -68,7 +69,7 @@ nfs4_renew_state(void *data) | |||
| 	dprintk("%s: start\n", __FUNCTION__); | ||||
| 	/* Are there any active superblocks? */ | ||||
| 	if (list_empty(&clp->cl_superblocks)) | ||||
| 		goto out;  | ||||
| 		goto out; | ||||
| 	spin_lock(&clp->cl_lock); | ||||
| 	lease = clp->cl_lease_time; | ||||
| 	last = clp->cl_last_renewal; | ||||
|  | @ -76,6 +77,12 @@ nfs4_renew_state(void *data) | |||
| 	timeout = (2 * lease) / 3 + (long)last - (long)now; | ||||
| 	/* Are we close to a lease timeout? */ | ||||
| 	if (time_after(now, last + lease/3)) { | ||||
| 		if (list_empty(&clp->cl_state_owners)) { | ||||
| 			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||||
| 			spin_unlock(&clp->cl_lock); | ||||
| 			nfs_expire_all_delegations(clp); | ||||
| 			goto out; | ||||
| 		} | ||||
| 		spin_unlock(&clp->cl_lock); | ||||
| 		/* Queue an asynchronous RENEW. */ | ||||
| 		nfs4_proc_async_renew(clp); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Trond Myklebust
						Trond Myklebust