diff options
Diffstat (limited to 'fs/nfs/nfs4state.c')
| -rw-r--r-- | fs/nfs/nfs4state.c | 51 | 
1 files changed, 34 insertions, 17 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index a6804f704d9..036f5adc9e1 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -64,10 +64,15 @@ static LIST_HEAD(nfs4_clientid_list);  int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)  { -	struct nfs4_setclientid_res clid; +	struct nfs4_setclientid_res clid = { +		.clientid = clp->cl_clientid, +		.confirm = clp->cl_confirm, +	};  	unsigned short port;  	int status; +	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) +		goto do_confirm;  	port = nfs_callback_tcpport;  	if (clp->cl_addr.ss_family == AF_INET6)  		port = nfs_callback_tcpport6; @@ -75,10 +80,14 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)  	status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);  	if (status != 0)  		goto out; +	clp->cl_clientid = clid.clientid; +	clp->cl_confirm = clid.confirm; +	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); +do_confirm:  	status = nfs4_proc_setclientid_confirm(clp, &clid, cred);  	if (status != 0)  		goto out; -	clp->cl_clientid = clid.clientid; +	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);  	nfs4_schedule_state_renewal(clp);  out:  	return status; @@ -230,13 +239,18 @@ int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)  {  	int status; +	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state)) +		goto do_confirm;  	nfs4_begin_drain_session(clp);  	status = nfs4_proc_exchange_id(clp, cred);  	if (status != 0)  		goto out; +	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); +do_confirm:  	status = nfs4_proc_create_session(clp);  	if (status != 0)  		goto out; +	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);  	nfs41_setup_state_renewal(clp);  	nfs_mark_client_ready(clp, NFS_CS_READY);  out: @@ -1584,20 +1598,23 @@ static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }   */  static void nfs4_set_lease_expired(struct nfs_client *clp, int status)  { -	if (nfs4_has_session(clp)) { -		switch (status) { -		case -NFS4ERR_DELAY: -		case -NFS4ERR_CLID_INUSE: -		case -EAGAIN: -			break; +	switch (status) { +	case -NFS4ERR_CLID_INUSE: +	case -NFS4ERR_STALE_CLIENTID: +		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); +		break; +	case -NFS4ERR_DELAY: +	case -ETIMEDOUT: +	case -EAGAIN: +		ssleep(1); +		break; -		case -EKEYEXPIRED: -			nfs4_warn_keyexpired(clp->cl_hostname); -		case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery -					 * in nfs4_exchange_id */ -		default: -			return; -		} +	case -EKEYEXPIRED: +		nfs4_warn_keyexpired(clp->cl_hostname); +	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery +				 * in nfs4_exchange_id */ +	default: +		return;  	}  	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);  } @@ -1607,7 +1624,7 @@ static void nfs4_state_manager(struct nfs_client *clp)  	int status = 0;  	/* Ensure exclusive access to NFSv4 state */ -	for(;;) { +	do {  		if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {  			/* We're going to have to re-establish a clientid */  			status = nfs4_reclaim_lease(clp); @@ -1691,7 +1708,7 @@ static void nfs4_state_manager(struct nfs_client *clp)  			break;  		if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)  			break; -	} +	} while (atomic_read(&clp->cl_count) > 1);  	return;  out_error:  	printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"  |