nfs41: consider minorversion in callback_xdr:process_op
Note that this patch changes the nfsv4.0 behavior also when CONFIG_NFS_V4_1 is not defined where NFS4ERR_MINOR_VERS_MISMATCH will be returned if the client received a CB_COMPOUND with minorversion != 0. Previously, it would have returned NFS4ERR_OP_ILLEGAL for CB_SEQUENCE. (or if the server is broken and sent OP_CB_GETATTR or OP_CB_RECALL with minorversion!=0, they would have been processed normally. Signed-off-by: Benny Halevy <bhalevy@panasas.com> [nfs41: refactor op preprocessing out of process_op] See http://linux-nfs.org/pipermail/pnfs/2009-June/007845.html [nfs41: define CB_NOTIFY_DEVICEID as not supported] Signed-off-by: Benny Halevy <bhalevy@panasas.com>
This commit is contained in:
		
							parent
							
								
									45377b94ed
								
							
						
					
					
						commit
						34bc47c941
					
				| @ -30,6 +30,7 @@ enum nfs4_callback_opnum { | ||||
| 	OP_CB_SEQUENCE      = 11, | ||||
| 	OP_CB_WANTS_CANCELLED = 12, | ||||
| 	OP_CB_NOTIFY_LOCK   = 13, | ||||
| 	OP_CB_NOTIFY_DEVICEID = 14, | ||||
| 	OP_CB_ILLEGAL = 10044, | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -356,31 +356,87 @@ out: | ||||
| 	return status; | ||||
| } | ||||
| 
 | ||||
| static __be32 process_op(struct svc_rqst *rqstp, | ||||
| #if defined(CONFIG_NFS_V4_1) | ||||
| 
 | ||||
| static __be32 | ||||
| preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||||
| { | ||||
| 	switch (op_nr) { | ||||
| 	case OP_CB_GETATTR: | ||||
| 	case OP_CB_RECALL: | ||||
| 		*op = &callback_ops[op_nr]; | ||||
| 		break; | ||||
| 
 | ||||
| 	case OP_CB_LAYOUTRECALL: | ||||
| 	case OP_CB_NOTIFY_DEVICEID: | ||||
| 	case OP_CB_NOTIFY: | ||||
| 	case OP_CB_PUSH_DELEG: | ||||
| 	case OP_CB_RECALL_ANY: | ||||
| 	case OP_CB_RECALLABLE_OBJ_AVAIL: | ||||
| 	case OP_CB_RECALL_SLOT: | ||||
| 	case OP_CB_SEQUENCE: | ||||
| 	case OP_CB_WANTS_CANCELLED: | ||||
| 	case OP_CB_NOTIFY_LOCK: | ||||
| 		return htonl(NFS4ERR_NOTSUPP); | ||||
| 
 | ||||
| 	default: | ||||
| 		return htonl(NFS4ERR_OP_ILLEGAL); | ||||
| 	} | ||||
| 
 | ||||
| 	return htonl(NFS_OK); | ||||
| } | ||||
| 
 | ||||
| #else /* CONFIG_NFS_V4_1 */ | ||||
| 
 | ||||
| static __be32 | ||||
| preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||||
| { | ||||
| 	return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | ||||
| } | ||||
| 
 | ||||
| #endif /* CONFIG_NFS_V4_1 */ | ||||
| 
 | ||||
| static __be32 | ||||
| preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | ||||
| { | ||||
| 	switch (op_nr) { | ||||
| 	case OP_CB_GETATTR: | ||||
| 	case OP_CB_RECALL: | ||||
| 		*op = &callback_ops[op_nr]; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return htonl(NFS4ERR_OP_ILLEGAL); | ||||
| 	} | ||||
| 
 | ||||
| 	return htonl(NFS_OK); | ||||
| } | ||||
| 
 | ||||
| static __be32 process_op(uint32_t minorversion, int nop, | ||||
| 		struct svc_rqst *rqstp, | ||||
| 		struct xdr_stream *xdr_in, void *argp, | ||||
| 		struct xdr_stream *xdr_out, void *resp) | ||||
| { | ||||
| 	struct callback_op *op = &callback_ops[0]; | ||||
| 	unsigned int op_nr = OP_CB_ILLEGAL; | ||||
| 	__be32 status = 0; | ||||
| 	__be32 status; | ||||
| 	long maxlen; | ||||
| 	__be32 res; | ||||
| 
 | ||||
| 	dprintk("%s: start\n", __func__); | ||||
| 	status = decode_op_hdr(xdr_in, &op_nr); | ||||
| 	if (likely(status == 0)) { | ||||
| 		switch (op_nr) { | ||||
| 			case OP_CB_GETATTR: | ||||
| 			case OP_CB_RECALL: | ||||
| 				op = &callback_ops[op_nr]; | ||||
| 				break; | ||||
| 			default: | ||||
| 				op_nr = OP_CB_ILLEGAL; | ||||
| 				op = &callback_ops[0]; | ||||
| 				status = htonl(NFS4ERR_OP_ILLEGAL); | ||||
| 		} | ||||
| 	if (unlikely(status)) { | ||||
| 		status = htonl(NFS4ERR_OP_ILLEGAL); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", | ||||
| 		__func__, minorversion, nop, op_nr); | ||||
| 
 | ||||
| 	status = minorversion ? preprocess_nfs41_op(nop, op_nr, &op) : | ||||
| 				preprocess_nfs4_op(op_nr, &op); | ||||
| 	if (status == htonl(NFS4ERR_OP_ILLEGAL)) | ||||
| 		op_nr = OP_CB_ILLEGAL; | ||||
| out: | ||||
| 	maxlen = xdr_out->end - xdr_out->p; | ||||
| 	if (maxlen > 0 && maxlen < PAGE_SIZE) { | ||||
| 		if (likely(status == 0 && op->decode_args != NULL)) | ||||
| @ -428,7 +484,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | ||||
| 		return rpc_system_err; | ||||
| 
 | ||||
| 	while (status == 0 && nops != hdr_arg.nops) { | ||||
| 		status = process_op(rqstp, &xdr_in, argp, &xdr_out, resp); | ||||
| 		status = process_op(hdr_arg.minorversion, nops, | ||||
| 				    rqstp, &xdr_in, argp, &xdr_out, resp); | ||||
| 		nops++; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user