aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorBenny Halevy <bhalevy@panasas.com>2009-04-01 09:23:22 -0400
committerBenny Halevy <bhalevy@panasas.com>2009-06-17 17:11:37 -0400
commit34bc47c941a074f91c2455b4b08503d02c74b878 (patch)
tree0e565b6a999080686e7e5c3536cb9f4ac86f1e9a /fs/nfs
parent45377b94edea18f53dd3ba4d46d94de4bb7c00b5 (diff)
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>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/callback.h1
-rw-r--r--fs/nfs/callback_xdr.c85
2 files changed, 72 insertions, 14 deletions
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index 7ba42b0d16c9..80fd8a82964f 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -30,6 +30,7 @@ enum nfs4_callback_opnum {
30 OP_CB_SEQUENCE = 11, 30 OP_CB_SEQUENCE = 11,
31 OP_CB_WANTS_CANCELLED = 12, 31 OP_CB_WANTS_CANCELLED = 12,
32 OP_CB_NOTIFY_LOCK = 13, 32 OP_CB_NOTIFY_LOCK = 13,
33 OP_CB_NOTIFY_DEVICEID = 14,
33 OP_CB_ILLEGAL = 10044, 34 OP_CB_ILLEGAL = 10044,
34}; 35};
35 36
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index f6cc79b1d1f3..41c5be1c1be5 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -356,31 +356,87 @@ out:
356 return status; 356 return status;
357} 357}
358 358
359static __be32 process_op(struct svc_rqst *rqstp, 359#if defined(CONFIG_NFS_V4_1)
360
361static __be32
362preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
363{
364 switch (op_nr) {
365 case OP_CB_GETATTR:
366 case OP_CB_RECALL:
367 *op = &callback_ops[op_nr];
368 break;
369
370 case OP_CB_LAYOUTRECALL:
371 case OP_CB_NOTIFY_DEVICEID:
372 case OP_CB_NOTIFY:
373 case OP_CB_PUSH_DELEG:
374 case OP_CB_RECALL_ANY:
375 case OP_CB_RECALLABLE_OBJ_AVAIL:
376 case OP_CB_RECALL_SLOT:
377 case OP_CB_SEQUENCE:
378 case OP_CB_WANTS_CANCELLED:
379 case OP_CB_NOTIFY_LOCK:
380 return htonl(NFS4ERR_NOTSUPP);
381
382 default:
383 return htonl(NFS4ERR_OP_ILLEGAL);
384 }
385
386 return htonl(NFS_OK);
387}
388
389#else /* CONFIG_NFS_V4_1 */
390
391static __be32
392preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
393{
394 return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
395}
396
397#endif /* CONFIG_NFS_V4_1 */
398
399static __be32
400preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op)
401{
402 switch (op_nr) {
403 case OP_CB_GETATTR:
404 case OP_CB_RECALL:
405 *op = &callback_ops[op_nr];
406 break;
407 default:
408 return htonl(NFS4ERR_OP_ILLEGAL);
409 }
410
411 return htonl(NFS_OK);
412}
413
414static __be32 process_op(uint32_t minorversion, int nop,
415 struct svc_rqst *rqstp,
360 struct xdr_stream *xdr_in, void *argp, 416 struct xdr_stream *xdr_in, void *argp,
361 struct xdr_stream *xdr_out, void *resp) 417 struct xdr_stream *xdr_out, void *resp)
362{ 418{
363 struct callback_op *op = &callback_ops[0]; 419 struct callback_op *op = &callback_ops[0];
364 unsigned int op_nr = OP_CB_ILLEGAL; 420 unsigned int op_nr = OP_CB_ILLEGAL;
365 __be32 status = 0; 421 __be32 status;
366 long maxlen; 422 long maxlen;
367 __be32 res; 423 __be32 res;
368 424
369 dprintk("%s: start\n", __func__); 425 dprintk("%s: start\n", __func__);
370 status = decode_op_hdr(xdr_in, &op_nr); 426 status = decode_op_hdr(xdr_in, &op_nr);
371 if (likely(status == 0)) { 427 if (unlikely(status)) {
372 switch (op_nr) { 428 status = htonl(NFS4ERR_OP_ILLEGAL);
373 case OP_CB_GETATTR: 429 goto out;
374 case OP_CB_RECALL:
375 op = &callback_ops[op_nr];
376 break;
377 default:
378 op_nr = OP_CB_ILLEGAL;
379 op = &callback_ops[0];
380 status = htonl(NFS4ERR_OP_ILLEGAL);
381 }
382 } 430 }
383 431
432 dprintk("%s: minorversion=%d nop=%d op_nr=%u\n",
433 __func__, minorversion, nop, op_nr);
434
435 status = minorversion ? preprocess_nfs41_op(nop, op_nr, &op) :
436 preprocess_nfs4_op(op_nr, &op);
437 if (status == htonl(NFS4ERR_OP_ILLEGAL))
438 op_nr = OP_CB_ILLEGAL;
439out:
384 maxlen = xdr_out->end - xdr_out->p; 440 maxlen = xdr_out->end - xdr_out->p;
385 if (maxlen > 0 && maxlen < PAGE_SIZE) { 441 if (maxlen > 0 && maxlen < PAGE_SIZE) {
386 if (likely(status == 0 && op->decode_args != NULL)) 442 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
428 return rpc_system_err; 484 return rpc_system_err;
429 485
430 while (status == 0 && nops != hdr_arg.nops) { 486 while (status == 0 && nops != hdr_arg.nops) {
431 status = process_op(rqstp, &xdr_in, argp, &xdr_out, resp); 487 status = process_op(hdr_arg.minorversion, nops,
488 rqstp, &xdr_in, argp, &xdr_out, resp);
432 nops++; 489 nops++;
433 } 490 }
434 491