diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
| -rw-r--r-- | fs/nfs/nfs4proc.c | 95 | 
1 files changed, 45 insertions, 50 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 405bd95c1f58..69dc20a743f9 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -370,11 +370,6 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc  		case -NFS4ERR_DELEG_REVOKED:  		case -NFS4ERR_ADMIN_REVOKED:  		case -NFS4ERR_BAD_STATEID: -			if (inode != NULL && nfs4_have_delegation(inode, FMODE_READ)) { -				nfs_remove_bad_delegation(inode); -				exception->retry = 1; -				break; -			}  			if (state == NULL)  				break;  			ret = nfs4_schedule_stateid_recovery(server, state); @@ -1654,7 +1649,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct  			nfs_inode_find_state_and_recover(state->inode,  					stateid);  			nfs4_schedule_stateid_recovery(server, state); -			return 0; +			return -EAGAIN;  		case -NFS4ERR_DELAY:  		case -NFS4ERR_GRACE:  			set_bit(NFS_DELEGATED_STATE, &state->flags); @@ -2109,46 +2104,60 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta  	return ret;  } +static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state) +{ +	nfs_remove_bad_delegation(state->inode); +	write_seqlock(&state->seqlock); +	nfs4_stateid_copy(&state->stateid, &state->open_stateid); +	write_sequnlock(&state->seqlock); +	clear_bit(NFS_DELEGATED_STATE, &state->flags); +} + +static void nfs40_clear_delegation_stateid(struct nfs4_state *state) +{ +	if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL) +		nfs_finish_clear_delegation_stateid(state); +} + +static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) +{ +	/* NFSv4.0 doesn't allow for delegation recovery on open expire */ +	nfs40_clear_delegation_stateid(state); +	return nfs4_open_expired(sp, state); +} +  #if defined(CONFIG_NFS_V4_1) -static void nfs41_clear_delegation_stateid(struct nfs4_state *state) +static void nfs41_check_delegation_stateid(struct nfs4_state *state)  {  	struct nfs_server *server = NFS_SERVER(state->inode); -	nfs4_stateid *stateid = &state->stateid; +	nfs4_stateid stateid;  	struct nfs_delegation *delegation; -	struct rpc_cred *cred = NULL; -	int status = -NFS4ERR_BAD_STATEID; - -	/* If a state reset has been done, test_stateid is unneeded */ -	if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) -		return; +	struct rpc_cred *cred; +	int status;  	/* Get the delegation credential for use by test/free_stateid */  	rcu_read_lock();  	delegation = rcu_dereference(NFS_I(state->inode)->delegation); -	if (delegation != NULL && -	    nfs4_stateid_match(&delegation->stateid, stateid)) { -		cred = get_rpccred(delegation->cred); -		rcu_read_unlock(); -		status = nfs41_test_stateid(server, stateid, cred); -		trace_nfs4_test_delegation_stateid(state, NULL, status); -	} else +	if (delegation == NULL) {  		rcu_read_unlock(); +		return; +	} + +	nfs4_stateid_copy(&stateid, &delegation->stateid); +	cred = get_rpccred(delegation->cred); +	rcu_read_unlock(); +	status = nfs41_test_stateid(server, &stateid, cred); +	trace_nfs4_test_delegation_stateid(state, NULL, status);  	if (status != NFS_OK) {  		/* Free the stateid unless the server explicitly  		 * informs us the stateid is unrecognized. */  		if (status != -NFS4ERR_BAD_STATEID) -			nfs41_free_stateid(server, stateid, cred); -		nfs_remove_bad_delegation(state->inode); - -		write_seqlock(&state->seqlock); -		nfs4_stateid_copy(&state->stateid, &state->open_stateid); -		write_sequnlock(&state->seqlock); -		clear_bit(NFS_DELEGATED_STATE, &state->flags); +			nfs41_free_stateid(server, &stateid, cred); +		nfs_finish_clear_delegation_stateid(state);  	} -	if (cred != NULL) -		put_rpccred(cred); +	put_rpccred(cred);  }  /** @@ -2192,7 +2201,7 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st  {  	int status; -	nfs41_clear_delegation_stateid(state); +	nfs41_check_delegation_stateid(state);  	status = nfs41_check_open_stateid(state);  	if (status != NFS_OK)  		status = nfs4_open_expired(sp, state); @@ -2231,19 +2240,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,  	seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);  	ret = _nfs4_proc_open(opendata); -	if (ret != 0) { -		if (ret == -ENOENT) { -			dentry = opendata->dentry; -			if (dentry->d_inode) -				d_delete(dentry); -			else if (d_unhashed(dentry)) -				d_add(dentry, NULL); - -			nfs_set_verifier(dentry, -					 nfs_save_change_attribute(opendata->dir->d_inode)); -		} +	if (ret != 0)  		goto out; -	}  	state = nfs4_opendata_to_nfs4_state(opendata);  	ret = PTR_ERR(state); @@ -4841,9 +4839,6 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,  		case -NFS4ERR_DELEG_REVOKED:  		case -NFS4ERR_ADMIN_REVOKED:  		case -NFS4ERR_BAD_STATEID: -			if (state == NULL) -				break; -			nfs_remove_bad_delegation(state->inode);  		case -NFS4ERR_OPENMODE:  			if (state == NULL)  				break; @@ -8341,7 +8336,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {  static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {  	.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,  	.state_flag_bit	= NFS_STATE_RECLAIM_NOGRACE, -	.recover_open	= nfs4_open_expired, +	.recover_open	= nfs40_open_expired,  	.recover_lock	= nfs4_lock_expired,  	.establish_clid = nfs4_init_clientid,  }; @@ -8408,8 +8403,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {  		| NFS_CAP_CHANGE_ATTR  		| NFS_CAP_POSIX_LOCK  		| NFS_CAP_STATEID_NFSV41 -		| NFS_CAP_ATOMIC_OPEN_V1 -		| NFS_CAP_SEEK, +		| NFS_CAP_ATOMIC_OPEN_V1,  	.init_client = nfs41_init_client,  	.shutdown_client = nfs41_shutdown_client,  	.match_stateid = nfs41_match_stateid, @@ -8431,7 +8425,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {  		| NFS_CAP_CHANGE_ATTR  		| NFS_CAP_POSIX_LOCK  		| NFS_CAP_STATEID_NFSV41 -		| NFS_CAP_ATOMIC_OPEN_V1, +		| NFS_CAP_ATOMIC_OPEN_V1 +		| NFS_CAP_SEEK,  	.init_client = nfs41_init_client,  	.shutdown_client = nfs41_shutdown_client,  	.match_stateid = nfs41_match_stateid,  | 
