diff options
author | Andy Adamson <andros@netapp.com> | 2011-01-05 21:04:32 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-01-06 14:46:24 -0500 |
commit | c36fca52f5e4594ffd0ff175b328966b0d393184 (patch) | |
tree | 6d771744cc49f0edc0d2b6b2f9fe919163002346 /fs/nfs/callback_xdr.c | |
parent | 2c2618c6f29c41a0a966f14f05c8bf45fcabb750 (diff) |
NFS refactor nfs_find_client and reference client across callback processing
Fixes a bug where the nfs_client could be freed during callback processing.
Refactor nfs_find_client to use minorversion specific means to locate the
correct nfs_client structure.
In the NFS layer, V4.0 clients are found using the callback_ident field in the
CB_COMPOUND header. V4.1 clients are found using the sessionID in the
CB_SEQUENCE operation which is also compared against the sessionID associated
with the back channel thread after a successful CREATE_SESSION.
Each of these methods finds the one an only nfs_client associated
with the incoming callback request - so nfs_find_client_next is not needed.
In the RPC layer, the pg_authenticate call needs to find the nfs_client. For
the v4.0 callback service, the callback identifier has not been decoded so a
search by address, version, and minorversion is used. The sessionid for the
sessions based callback service has (usually) not been set for the
pg_authenticate on a CB_NULL call which can be sent prior to the return
of a CREATE_SESSION call, so the sessionid associated with the back channel
thread is not used to find the client in pg_authenticate for CB_NULL calls.
Pass the referenced nfs_client to each CB_COMPOUND operation being proceesed
via the new cb_process_state structure. The reference is held across
cb_compound processing.
Use the new cb_process_state struct to move the NFS4ERR_RETRY_UNCACHED_REP
processing from process_op into nfs4_callback_sequence where it belongs.
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/callback_xdr.c')
-rw-r--r-- | fs/nfs/callback_xdr.c | 39 |
1 files changed, 24 insertions, 15 deletions
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 05af212f0edf..dbd0d649805c 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -10,8 +10,10 @@ | |||
10 | #include <linux/nfs4.h> | 10 | #include <linux/nfs4.h> |
11 | #include <linux/nfs_fs.h> | 11 | #include <linux/nfs_fs.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/sunrpc/bc_xprt.h> | ||
13 | #include "nfs4_fs.h" | 14 | #include "nfs4_fs.h" |
14 | #include "callback.h" | 15 | #include "callback.h" |
16 | #include "internal.h" | ||
15 | 17 | ||
16 | #define CB_OP_TAGLEN_MAXSZ (512) | 18 | #define CB_OP_TAGLEN_MAXSZ (512) |
17 | #define CB_OP_HDR_RES_MAXSZ (2 + CB_OP_TAGLEN_MAXSZ) | 19 | #define CB_OP_HDR_RES_MAXSZ (2 + CB_OP_TAGLEN_MAXSZ) |
@@ -33,7 +35,8 @@ | |||
33 | /* Internal error code */ | 35 | /* Internal error code */ |
34 | #define NFS4ERR_RESOURCE_HDR 11050 | 36 | #define NFS4ERR_RESOURCE_HDR 11050 |
35 | 37 | ||
36 | typedef __be32 (*callback_process_op_t)(void *, void *); | 38 | typedef __be32 (*callback_process_op_t)(void *, void *, |
39 | struct cb_process_state *); | ||
37 | typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); | 40 | typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); |
38 | typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); | 41 | typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); |
39 | 42 | ||
@@ -160,7 +163,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
160 | hdr->minorversion = ntohl(*p++); | 163 | hdr->minorversion = ntohl(*p++); |
161 | /* Check minor version is zero or one. */ | 164 | /* Check minor version is zero or one. */ |
162 | if (hdr->minorversion <= 1) { | 165 | if (hdr->minorversion <= 1) { |
163 | p++; /* skip callback_ident */ | 166 | hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */ |
164 | } else { | 167 | } else { |
165 | printk(KERN_WARNING "%s: NFSv4 server callback with " | 168 | printk(KERN_WARNING "%s: NFSv4 server callback with " |
166 | "illegal minor version %u!\n", | 169 | "illegal minor version %u!\n", |
@@ -621,7 +624,8 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | |||
621 | static __be32 process_op(uint32_t minorversion, int nop, | 624 | static __be32 process_op(uint32_t minorversion, int nop, |
622 | struct svc_rqst *rqstp, | 625 | struct svc_rqst *rqstp, |
623 | struct xdr_stream *xdr_in, void *argp, | 626 | struct xdr_stream *xdr_in, void *argp, |
624 | struct xdr_stream *xdr_out, void *resp, int* drc_status) | 627 | struct xdr_stream *xdr_out, void *resp, |
628 | struct cb_process_state *cps) | ||
625 | { | 629 | { |
626 | struct callback_op *op = &callback_ops[0]; | 630 | struct callback_op *op = &callback_ops[0]; |
627 | unsigned int op_nr; | 631 | unsigned int op_nr; |
@@ -644,8 +648,8 @@ static __be32 process_op(uint32_t minorversion, int nop, | |||
644 | if (status) | 648 | if (status) |
645 | goto encode_hdr; | 649 | goto encode_hdr; |
646 | 650 | ||
647 | if (*drc_status) { | 651 | if (cps->drc_status) { |
648 | status = *drc_status; | 652 | status = cps->drc_status; |
649 | goto encode_hdr; | 653 | goto encode_hdr; |
650 | } | 654 | } |
651 | 655 | ||
@@ -653,16 +657,10 @@ static __be32 process_op(uint32_t minorversion, int nop, | |||
653 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 657 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
654 | status = op->decode_args(rqstp, xdr_in, argp); | 658 | status = op->decode_args(rqstp, xdr_in, argp); |
655 | if (likely(status == 0)) | 659 | if (likely(status == 0)) |
656 | status = op->process_op(argp, resp); | 660 | status = op->process_op(argp, resp, cps); |
657 | } else | 661 | } else |
658 | status = htonl(NFS4ERR_RESOURCE); | 662 | status = htonl(NFS4ERR_RESOURCE); |
659 | 663 | ||
660 | /* Only set by OP_CB_SEQUENCE processing */ | ||
661 | if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) { | ||
662 | *drc_status = status; | ||
663 | status = 0; | ||
664 | } | ||
665 | |||
666 | encode_hdr: | 664 | encode_hdr: |
667 | res = encode_op_hdr(xdr_out, op_nr, status); | 665 | res = encode_op_hdr(xdr_out, op_nr, status); |
668 | if (unlikely(res)) | 666 | if (unlikely(res)) |
@@ -681,8 +679,11 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
681 | struct cb_compound_hdr_arg hdr_arg = { 0 }; | 679 | struct cb_compound_hdr_arg hdr_arg = { 0 }; |
682 | struct cb_compound_hdr_res hdr_res = { NULL }; | 680 | struct cb_compound_hdr_res hdr_res = { NULL }; |
683 | struct xdr_stream xdr_in, xdr_out; | 681 | struct xdr_stream xdr_in, xdr_out; |
684 | __be32 *p; | 682 | __be32 *p, status; |
685 | __be32 status, drc_status = 0; | 683 | struct cb_process_state cps = { |
684 | .drc_status = 0, | ||
685 | .clp = NULL, | ||
686 | }; | ||
686 | unsigned int nops = 0; | 687 | unsigned int nops = 0; |
687 | 688 | ||
688 | dprintk("%s: start\n", __func__); | 689 | dprintk("%s: start\n", __func__); |
@@ -696,6 +697,13 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
696 | if (status == __constant_htonl(NFS4ERR_RESOURCE)) | 697 | if (status == __constant_htonl(NFS4ERR_RESOURCE)) |
697 | return rpc_garbage_args; | 698 | return rpc_garbage_args; |
698 | 699 | ||
700 | if (hdr_arg.minorversion == 0) { | ||
701 | cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident); | ||
702 | if (!cps.clp) | ||
703 | return rpc_drop_reply; | ||
704 | } else | ||
705 | cps.svc_sid = bc_xprt_sid(rqstp); | ||
706 | |||
699 | hdr_res.taglen = hdr_arg.taglen; | 707 | hdr_res.taglen = hdr_arg.taglen; |
700 | hdr_res.tag = hdr_arg.tag; | 708 | hdr_res.tag = hdr_arg.tag; |
701 | if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) | 709 | if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) |
@@ -703,7 +711,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
703 | 711 | ||
704 | while (status == 0 && nops != hdr_arg.nops) { | 712 | while (status == 0 && nops != hdr_arg.nops) { |
705 | status = process_op(hdr_arg.minorversion, nops, rqstp, | 713 | status = process_op(hdr_arg.minorversion, nops, rqstp, |
706 | &xdr_in, argp, &xdr_out, resp, &drc_status); | 714 | &xdr_in, argp, &xdr_out, resp, &cps); |
707 | nops++; | 715 | nops++; |
708 | } | 716 | } |
709 | 717 | ||
@@ -716,6 +724,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
716 | 724 | ||
717 | *hdr_res.status = status; | 725 | *hdr_res.status = status; |
718 | *hdr_res.nops = htonl(nops); | 726 | *hdr_res.nops = htonl(nops); |
727 | nfs_put_client(cps.clp); | ||
719 | dprintk("%s: done, status = %u\n", __func__, ntohl(status)); | 728 | dprintk("%s: done, status = %u\n", __func__, ntohl(status)); |
720 | return rpc_success; | 729 | return rpc_success; |
721 | } | 730 | } |