diff options
author | Benny Halevy <bhalevy@panasas.com> | 2009-04-01 09:23:22 -0400 |
---|---|---|
committer | Benny Halevy <bhalevy@panasas.com> | 2009-06-17 17:11:37 -0400 |
commit | 34bc47c941a074f91c2455b4b08503d02c74b878 (patch) | |
tree | 0e565b6a999080686e7e5c3536cb9f4ac86f1e9a /fs | |
parent | 45377b94edea18f53dd3ba4d46d94de4bb7c00b5 (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')
-rw-r--r-- | fs/nfs/callback.h | 1 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 85 |
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 | ||
359 | static __be32 process_op(struct svc_rqst *rqstp, | 359 | #if defined(CONFIG_NFS_V4_1) |
360 | |||
361 | static __be32 | ||
362 | preprocess_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 | |||
391 | static __be32 | ||
392 | preprocess_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 | |||
399 | static __be32 | ||
400 | preprocess_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 | |||
414 | static __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; | ||
439 | out: | ||
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 | ||