diff options
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
| -rw-r--r-- | fs/nfsd/nfs4proc.c | 58 | 
1 files changed, 47 insertions, 11 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3a6dbd70b34b..e80777666618 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -291,6 +291,15 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  	if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)  		return nfserr_inval; +	/* +	 * RFC5661 18.51.3 +	 * Before RECLAIM_COMPLETE done, server should deny new lock +	 */ +	if (nfsd4_has_session(cstate) && +	    !cstate->session->se_client->cl_firststate && +	    open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) +		return nfserr_grace; +  	if (nfsd4_has_session(cstate))  		copy_clientid(&open->op_clientid, cstate->session); @@ -998,6 +1007,15 @@ struct nfsd4_operation {  	nfsd4op_func op_func;  	u32 op_flags;  	char *op_name; +	/* +	 * We use the DRC for compounds containing non-idempotent +	 * operations, *except* those that are 4.1-specific (since +	 * sessions provide their own EOS), and except for stateful +	 * operations other than setclientid and setclientid_confirm +	 * (since sequence numbers provide EOS for open, lock, etc in +	 * the v4.0 case). +	 */ +	bool op_cacheresult;  };  static struct nfsd4_operation nfsd4_ops[]; @@ -1042,6 +1060,11 @@ static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op)  	return &nfsd4_ops[op->opnum];  } +bool nfsd4_cache_this_op(struct nfsd4_op *op) +{ +	return OPDESC(op)->op_cacheresult; +} +  static bool need_wrongsec_check(struct svc_rqst *rqstp)  {  	struct nfsd4_compoundres *resp = rqstp->rq_resp; @@ -1209,7 +1232,6 @@ encode_op:  	fh_put(&resp->cstate.save_fh);  	BUG_ON(resp->cstate.replay_owner);  out: -	nfsd4_release_compoundargs(args);  	/* Reset deferral mechanism for RPC deferrals */  	rqstp->rq_usedeferral = 1;  	dprintk("nfsv4 compound returned %d\n", ntohl(status)); @@ -1232,6 +1254,7 @@ static struct nfsd4_operation nfsd4_ops[] = {  	[OP_CREATE] = {  		.op_func = (nfsd4op_func)nfsd4_create,  		.op_name = "OP_CREATE", +		.op_cacheresult = true,  	},  	[OP_DELEGRETURN] = {  		.op_func = (nfsd4op_func)nfsd4_delegreturn, @@ -1249,6 +1272,7 @@ static struct nfsd4_operation nfsd4_ops[] = {  	[OP_LINK] = {  		.op_func = (nfsd4op_func)nfsd4_link,  		.op_name = "OP_LINK", +		.op_cacheresult = true,  	},  	[OP_LOCK] = {  		.op_func = (nfsd4op_func)nfsd4_lock, @@ -1322,10 +1346,12 @@ static struct nfsd4_operation nfsd4_ops[] = {  	[OP_REMOVE] = {  		.op_func = (nfsd4op_func)nfsd4_remove,  		.op_name = "OP_REMOVE", +		.op_cacheresult = true,  	},  	[OP_RENAME] = {  		.op_name = "OP_RENAME",  		.op_func = (nfsd4op_func)nfsd4_rename, +		.op_cacheresult = true,  	},  	[OP_RENEW] = {  		.op_func = (nfsd4op_func)nfsd4_renew, @@ -1351,16 +1377,19 @@ static struct nfsd4_operation nfsd4_ops[] = {  	[OP_SETATTR] = {  		.op_func = (nfsd4op_func)nfsd4_setattr,  		.op_name = "OP_SETATTR", +		.op_cacheresult = true,  	},  	[OP_SETCLIENTID] = {  		.op_func = (nfsd4op_func)nfsd4_setclientid,  		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,  		.op_name = "OP_SETCLIENTID", +		.op_cacheresult = true,  	},  	[OP_SETCLIENTID_CONFIRM] = {  		.op_func = (nfsd4op_func)nfsd4_setclientid_confirm,  		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,  		.op_name = "OP_SETCLIENTID_CONFIRM", +		.op_cacheresult = true,  	},  	[OP_VERIFY] = {  		.op_func = (nfsd4op_func)nfsd4_verify, @@ -1369,6 +1398,7 @@ static struct nfsd4_operation nfsd4_ops[] = {  	[OP_WRITE] = {  		.op_func = (nfsd4op_func)nfsd4_write,  		.op_name = "OP_WRITE", +		.op_cacheresult = true,  	},  	[OP_RELEASE_LOCKOWNER] = {  		.op_func = (nfsd4op_func)nfsd4_release_lockowner, @@ -1402,6 +1432,11 @@ static struct nfsd4_operation nfsd4_ops[] = {  		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,  		.op_name = "OP_SEQUENCE",  	}, +	[OP_DESTROY_CLIENTID] = { +		.op_func = NULL, +		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP, +		.op_name = "OP_DESTROY_CLIENTID", +	},  	[OP_RECLAIM_COMPLETE] = {  		.op_func = (nfsd4op_func)nfsd4_reclaim_complete,  		.op_flags = ALLOWED_WITHOUT_FH, @@ -1412,6 +1447,16 @@ static struct nfsd4_operation nfsd4_ops[] = {  		.op_flags = OP_HANDLES_WRONGSEC,  		.op_name = "OP_SECINFO_NO_NAME",  	}, +	[OP_TEST_STATEID] = { +		.op_func = (nfsd4op_func)nfsd4_test_stateid, +		.op_flags = ALLOWED_WITHOUT_FH, +		.op_name = "OP_TEST_STATEID", +	}, +	[OP_FREE_STATEID] = { +		.op_func = (nfsd4op_func)nfsd4_free_stateid, +		.op_flags = ALLOWED_WITHOUT_FH, +		.op_name = "OP_FREE_STATEID", +	},  };  static const char *nfsd4_op_name(unsigned opnum) @@ -1424,16 +1469,6 @@ static const char *nfsd4_op_name(unsigned opnum)  #define nfsd4_voidres			nfsd4_voidargs  struct nfsd4_voidargs { int dummy; }; -/* - * TODO: At the present time, the NFSv4 server does not do XID caching - * of requests.  Implementing XID caching would not be a serious problem, - * although it would require a mild change in interfaces since one - * doesn't know whether an NFSv4 request is idempotent until after the - * XDR decode.  However, XID caching totally confuses pynfs (Peter - * Astrand's regression testsuite for NFSv4 servers), which reuses - * XID's liberally, so I've left it unimplemented until pynfs generates - * better XID's. - */  static struct svc_procedure		nfsd_procedures4[2] = {  	[NFSPROC4_NULL] = {  		.pc_func = (svc_procfunc) nfsd4_proc_null, @@ -1449,6 +1484,7 @@ static struct svc_procedure		nfsd_procedures4[2] = {  		.pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres,  		.pc_argsize = sizeof(struct nfsd4_compoundargs),  		.pc_ressize = sizeof(struct nfsd4_compoundres), +		.pc_release = nfsd4_release_compoundargs,  		.pc_cachetype = RC_NOCACHE,  		.pc_xdrressize = NFSD_BUFSIZE/4,  	},  |