diff options
| -rw-r--r-- | fs/nfsd/nfs4state.c | 60 | ||||
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 14 | ||||
| -rw-r--r-- | fs/nfsd/xdr4.h | 1 | ||||
| -rw-r--r-- | include/linux/nfs4.h | 15 | 
4 files changed, 82 insertions, 8 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f1b74a74ec4..967c677c2e5 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -2866,7 +2866,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_  	struct nfs4_delegation *dp;  	struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);  	int cb_up; -	int status, flag = 0; +	int status = 0, flag = 0;  	cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);  	flag = NFS4_OPEN_DELEGATE_NONE; @@ -2907,11 +2907,32 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_  	dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",  		STATEID_VAL(&dp->dl_stid.sc_stateid));  out: -	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS -			&& flag == NFS4_OPEN_DELEGATE_NONE -			&& open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) -		dprintk("NFSD: WARNING: refusing delegation reclaim\n");  	open->op_delegate_type = flag; +	if (flag == NFS4_OPEN_DELEGATE_NONE) { +		if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && +		    open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) +			dprintk("NFSD: WARNING: refusing delegation reclaim\n"); + +		if (open->op_deleg_want) { +			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; +			if (status == -EAGAIN) +				open->op_why_no_deleg = WND4_CONTENTION; +			else { +				open->op_why_no_deleg = WND4_RESOURCE; +				switch (open->op_deleg_want) { +				case NFS4_SHARE_WANT_READ_DELEG: +				case NFS4_SHARE_WANT_WRITE_DELEG: +				case NFS4_SHARE_WANT_ANY_DELEG: +					break; +				case NFS4_SHARE_WANT_CANCEL: +					open->op_why_no_deleg = WND4_CANCELLED; +					break; +				case NFS4_SHARE_WANT_NO_DELEG: +					BUG();	/* not supposed to get here */ +				} +			} +		} +	}  	return;  out_free:  	nfs4_put_delegation(dp); @@ -2981,20 +3002,45 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf  	update_stateid(&stp->st_stid.sc_stateid);  	memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); -	if (nfsd4_has_session(&resp->cstate)) +	if (nfsd4_has_session(&resp->cstate)) {  		open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; +		if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { +			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; +			open->op_why_no_deleg = WND4_NOT_WANTED; +			goto nodeleg; +		} +	} +  	/*  	* Attempt to hand out a delegation. No error return, because the  	* OPEN succeeds even if we fail.  	*/  	nfs4_open_delegation(current_fh, open, stp); - +nodeleg:  	status = nfs_ok;  	dprintk("%s: stateid=" STATEID_FMT "\n", __func__,  		STATEID_VAL(&stp->st_stid.sc_stateid));  out: +	/* 4.1 client trying to upgrade/downgrade delegation? */ +	if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && +	    open->op_deleg_want) { +		if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && +		    dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { +			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; +			open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; +		} else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && +			   dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { +			open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; +			open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; +		} +		/* Otherwise the client must be confused wanting a delegation +		 * it already has, therefore we don't return +		 * NFS4_OPEN_DELEGATE_NONE_EXT and reason. +		 */ +	} +  	if (fp)  		put_nfs4_file(fp);  	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index a58f2064f47..f8fcddca041 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2849,6 +2849,20 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op  		WRITE32(0);   /* XXX: is NULL principal ok? */  		ADJUST_ARGS();  		break; +	case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */ +		switch (open->op_why_no_deleg) { +		case WND4_CONTENTION: +		case WND4_RESOURCE: +			RESERVE_SPACE(8); +			WRITE32(open->op_why_no_deleg); +			WRITE32(0);	/* deleg signaling not supported yet */ +			break; +		default: +			RESERVE_SPACE(4); +			WRITE32(open->op_why_no_deleg); +		} +		ADJUST_ARGS(); +		break;  	default:  		BUG();  	} diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 7110a082275..b89781f1477 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -223,6 +223,7 @@ struct nfsd4_open {  	struct xdr_netobj op_fname;	    /* request - everything but CLAIM_PREV */  	u32		op_delegate_type;   /* request - CLAIM_PREV only */  	stateid_t       op_delegate_stateid; /* request - response */ +	u32		op_why_no_deleg;    /* response - DELEG_NONE_EXT only */  	u32		op_create;     	    /* request */  	u32		op_createmode;      /* request */  	u32		op_bmval[3];        /* request */ diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 32345c2805c..8cdde4d1fad 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -441,7 +441,20 @@ enum limit_by4 {  enum open_delegation_type4 {  	NFS4_OPEN_DELEGATE_NONE = 0,  	NFS4_OPEN_DELEGATE_READ = 1, -	NFS4_OPEN_DELEGATE_WRITE = 2 +	NFS4_OPEN_DELEGATE_WRITE = 2, +	NFS4_OPEN_DELEGATE_NONE_EXT = 3, /* 4.1 */ +}; + +enum why_no_delegation4 { /* new to v4.1 */ +	WND4_NOT_WANTED = 0, +	WND4_CONTENTION = 1, +	WND4_RESOURCE = 2, +	WND4_NOT_SUPP_FTYPE = 3, +	WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4, +	WND4_NOT_SUPP_UPGRADE = 5, +	WND4_NOT_SUPP_DOWNGRADE = 6, +	WND4_CANCELLED = 7, +	WND4_IS_DIR = 8,  };  enum lock_type4 {  |