diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-11 18:11:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-11 18:11:56 -0500 |
commit | b9d919a4ac6cf031b8e065f82ad8f1b0c9ed74b1 (patch) | |
tree | 3139b066396956fd3794df0cb1aa74dcc9f1cb28 /fs/nfs/callback_xdr.c | |
parent | 7c955fca3e1d8132982148267d9efcafae849bb6 (diff) | |
parent | 357f54d6b38252737116a6d631f6ac28ded018ed (diff) |
Merge branch 'nfs-for-2.6.38' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'nfs-for-2.6.38' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (89 commits)
NFS fix the setting of exchange id flag
NFS: Don't use vm_map_ram() in readdir
NFSv4: Ensure continued open and lockowner name uniqueness
NFS: Move cl_delegations to the nfs_server struct
NFS: Introduce nfs_detach_delegations()
NFS: Move cl_state_owners and related fields to the nfs_server struct
NFS: Allow walking nfs_client.cl_superblocks list outside client.c
pnfs: layout roc code
pnfs: update nfs4_callback_recallany to handle layouts
pnfs: add CB_LAYOUTRECALL handling
pnfs: CB_LAYOUTRECALL xdr code
pnfs: change lo refcounting to atomic_t
pnfs: check that partial LAYOUTGET return is ignored
pnfs: add layout to client list before sending rpc
pnfs: serialize LAYOUTGET(openstateid)
pnfs: layoutget rpc code cleanup
pnfs: change how lsegs are removed from layout list
pnfs: change layout state seqlock to a spinlock
pnfs: add prefix to struct pnfs_layout_hdr fields
pnfs: add prefix to struct pnfs_layout_segment fields
...
Diffstat (limited to 'fs/nfs/callback_xdr.c')
-rw-r--r-- | fs/nfs/callback_xdr.c | 143 |
1 files changed, 127 insertions, 16 deletions
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 05af212f0edf..23112c263f81 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) |
@@ -22,6 +24,7 @@ | |||
22 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 24 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
23 | 25 | ||
24 | #if defined(CONFIG_NFS_V4_1) | 26 | #if defined(CONFIG_NFS_V4_1) |
27 | #define CB_OP_LAYOUTRECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | ||
25 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | 28 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ |
26 | 4 + 1 + 3) | 29 | 4 + 1 + 3) |
27 | #define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 30 | #define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
@@ -33,7 +36,8 @@ | |||
33 | /* Internal error code */ | 36 | /* Internal error code */ |
34 | #define NFS4ERR_RESOURCE_HDR 11050 | 37 | #define NFS4ERR_RESOURCE_HDR 11050 |
35 | 38 | ||
36 | typedef __be32 (*callback_process_op_t)(void *, void *); | 39 | typedef __be32 (*callback_process_op_t)(void *, void *, |
40 | struct cb_process_state *); | ||
37 | typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); | 41 | 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 *); | 42 | typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); |
39 | 43 | ||
@@ -160,7 +164,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
160 | hdr->minorversion = ntohl(*p++); | 164 | hdr->minorversion = ntohl(*p++); |
161 | /* Check minor version is zero or one. */ | 165 | /* Check minor version is zero or one. */ |
162 | if (hdr->minorversion <= 1) { | 166 | if (hdr->minorversion <= 1) { |
163 | p++; /* skip callback_ident */ | 167 | hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */ |
164 | } else { | 168 | } else { |
165 | printk(KERN_WARNING "%s: NFSv4 server callback with " | 169 | printk(KERN_WARNING "%s: NFSv4 server callback with " |
166 | "illegal minor version %u!\n", | 170 | "illegal minor version %u!\n", |
@@ -220,6 +224,66 @@ out: | |||
220 | 224 | ||
221 | #if defined(CONFIG_NFS_V4_1) | 225 | #if defined(CONFIG_NFS_V4_1) |
222 | 226 | ||
227 | static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp, | ||
228 | struct xdr_stream *xdr, | ||
229 | struct cb_layoutrecallargs *args) | ||
230 | { | ||
231 | __be32 *p; | ||
232 | __be32 status = 0; | ||
233 | uint32_t iomode; | ||
234 | |||
235 | args->cbl_addr = svc_addr(rqstp); | ||
236 | p = read_buf(xdr, 4 * sizeof(uint32_t)); | ||
237 | if (unlikely(p == NULL)) { | ||
238 | status = htonl(NFS4ERR_BADXDR); | ||
239 | goto out; | ||
240 | } | ||
241 | |||
242 | args->cbl_layout_type = ntohl(*p++); | ||
243 | /* Depite the spec's xdr, iomode really belongs in the FILE switch, | ||
244 | * as it is unuseable and ignored with the other types. | ||
245 | */ | ||
246 | iomode = ntohl(*p++); | ||
247 | args->cbl_layoutchanged = ntohl(*p++); | ||
248 | args->cbl_recall_type = ntohl(*p++); | ||
249 | |||
250 | if (args->cbl_recall_type == RETURN_FILE) { | ||
251 | args->cbl_range.iomode = iomode; | ||
252 | status = decode_fh(xdr, &args->cbl_fh); | ||
253 | if (unlikely(status != 0)) | ||
254 | goto out; | ||
255 | |||
256 | p = read_buf(xdr, 2 * sizeof(uint64_t)); | ||
257 | if (unlikely(p == NULL)) { | ||
258 | status = htonl(NFS4ERR_BADXDR); | ||
259 | goto out; | ||
260 | } | ||
261 | p = xdr_decode_hyper(p, &args->cbl_range.offset); | ||
262 | p = xdr_decode_hyper(p, &args->cbl_range.length); | ||
263 | status = decode_stateid(xdr, &args->cbl_stateid); | ||
264 | if (unlikely(status != 0)) | ||
265 | goto out; | ||
266 | } else if (args->cbl_recall_type == RETURN_FSID) { | ||
267 | p = read_buf(xdr, 2 * sizeof(uint64_t)); | ||
268 | if (unlikely(p == NULL)) { | ||
269 | status = htonl(NFS4ERR_BADXDR); | ||
270 | goto out; | ||
271 | } | ||
272 | p = xdr_decode_hyper(p, &args->cbl_fsid.major); | ||
273 | p = xdr_decode_hyper(p, &args->cbl_fsid.minor); | ||
274 | } else if (args->cbl_recall_type != RETURN_ALL) { | ||
275 | status = htonl(NFS4ERR_BADXDR); | ||
276 | goto out; | ||
277 | } | ||
278 | dprintk("%s: ltype 0x%x iomode %d changed %d recall_type %d\n", | ||
279 | __func__, | ||
280 | args->cbl_layout_type, iomode, | ||
281 | args->cbl_layoutchanged, args->cbl_recall_type); | ||
282 | out: | ||
283 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
284 | return status; | ||
285 | } | ||
286 | |||
223 | static __be32 decode_sessionid(struct xdr_stream *xdr, | 287 | static __be32 decode_sessionid(struct xdr_stream *xdr, |
224 | struct nfs4_sessionid *sid) | 288 | struct nfs4_sessionid *sid) |
225 | { | 289 | { |
@@ -574,10 +638,10 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
574 | case OP_CB_SEQUENCE: | 638 | case OP_CB_SEQUENCE: |
575 | case OP_CB_RECALL_ANY: | 639 | case OP_CB_RECALL_ANY: |
576 | case OP_CB_RECALL_SLOT: | 640 | case OP_CB_RECALL_SLOT: |
641 | case OP_CB_LAYOUTRECALL: | ||
577 | *op = &callback_ops[op_nr]; | 642 | *op = &callback_ops[op_nr]; |
578 | break; | 643 | break; |
579 | 644 | ||
580 | case OP_CB_LAYOUTRECALL: | ||
581 | case OP_CB_NOTIFY_DEVICEID: | 645 | case OP_CB_NOTIFY_DEVICEID: |
582 | case OP_CB_NOTIFY: | 646 | case OP_CB_NOTIFY: |
583 | case OP_CB_PUSH_DELEG: | 647 | case OP_CB_PUSH_DELEG: |
@@ -593,6 +657,37 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
593 | return htonl(NFS_OK); | 657 | return htonl(NFS_OK); |
594 | } | 658 | } |
595 | 659 | ||
660 | static void nfs4_callback_free_slot(struct nfs4_session *session) | ||
661 | { | ||
662 | struct nfs4_slot_table *tbl = &session->bc_slot_table; | ||
663 | |||
664 | spin_lock(&tbl->slot_tbl_lock); | ||
665 | /* | ||
666 | * Let the state manager know callback processing done. | ||
667 | * A single slot, so highest used slotid is either 0 or -1 | ||
668 | */ | ||
669 | tbl->highest_used_slotid--; | ||
670 | nfs4_check_drain_bc_complete(session); | ||
671 | spin_unlock(&tbl->slot_tbl_lock); | ||
672 | } | ||
673 | |||
674 | static void nfs4_cb_free_slot(struct nfs_client *clp) | ||
675 | { | ||
676 | if (clp && clp->cl_session) | ||
677 | nfs4_callback_free_slot(clp->cl_session); | ||
678 | } | ||
679 | |||
680 | /* A single slot, so highest used slotid is either 0 or -1 */ | ||
681 | void nfs4_cb_take_slot(struct nfs_client *clp) | ||
682 | { | ||
683 | struct nfs4_slot_table *tbl = &clp->cl_session->bc_slot_table; | ||
684 | |||
685 | spin_lock(&tbl->slot_tbl_lock); | ||
686 | tbl->highest_used_slotid++; | ||
687 | BUG_ON(tbl->highest_used_slotid != 0); | ||
688 | spin_unlock(&tbl->slot_tbl_lock); | ||
689 | } | ||
690 | |||
596 | #else /* CONFIG_NFS_V4_1 */ | 691 | #else /* CONFIG_NFS_V4_1 */ |
597 | 692 | ||
598 | static __be32 | 693 | static __be32 |
@@ -601,6 +696,9 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
601 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | 696 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); |
602 | } | 697 | } |
603 | 698 | ||
699 | static void nfs4_cb_free_slot(struct nfs_client *clp) | ||
700 | { | ||
701 | } | ||
604 | #endif /* CONFIG_NFS_V4_1 */ | 702 | #endif /* CONFIG_NFS_V4_1 */ |
605 | 703 | ||
606 | static __be32 | 704 | static __be32 |
@@ -621,7 +719,8 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | |||
621 | static __be32 process_op(uint32_t minorversion, int nop, | 719 | static __be32 process_op(uint32_t minorversion, int nop, |
622 | struct svc_rqst *rqstp, | 720 | struct svc_rqst *rqstp, |
623 | struct xdr_stream *xdr_in, void *argp, | 721 | struct xdr_stream *xdr_in, void *argp, |
624 | struct xdr_stream *xdr_out, void *resp, int* drc_status) | 722 | struct xdr_stream *xdr_out, void *resp, |
723 | struct cb_process_state *cps) | ||
625 | { | 724 | { |
626 | struct callback_op *op = &callback_ops[0]; | 725 | struct callback_op *op = &callback_ops[0]; |
627 | unsigned int op_nr; | 726 | unsigned int op_nr; |
@@ -644,8 +743,8 @@ static __be32 process_op(uint32_t minorversion, int nop, | |||
644 | if (status) | 743 | if (status) |
645 | goto encode_hdr; | 744 | goto encode_hdr; |
646 | 745 | ||
647 | if (*drc_status) { | 746 | if (cps->drc_status) { |
648 | status = *drc_status; | 747 | status = cps->drc_status; |
649 | goto encode_hdr; | 748 | goto encode_hdr; |
650 | } | 749 | } |
651 | 750 | ||
@@ -653,16 +752,10 @@ static __be32 process_op(uint32_t minorversion, int nop, | |||
653 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 752 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
654 | status = op->decode_args(rqstp, xdr_in, argp); | 753 | status = op->decode_args(rqstp, xdr_in, argp); |
655 | if (likely(status == 0)) | 754 | if (likely(status == 0)) |
656 | status = op->process_op(argp, resp); | 755 | status = op->process_op(argp, resp, cps); |
657 | } else | 756 | } else |
658 | status = htonl(NFS4ERR_RESOURCE); | 757 | status = htonl(NFS4ERR_RESOURCE); |
659 | 758 | ||
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: | 759 | encode_hdr: |
667 | res = encode_op_hdr(xdr_out, op_nr, status); | 760 | res = encode_op_hdr(xdr_out, op_nr, status); |
668 | if (unlikely(res)) | 761 | if (unlikely(res)) |
@@ -681,8 +774,11 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
681 | struct cb_compound_hdr_arg hdr_arg = { 0 }; | 774 | struct cb_compound_hdr_arg hdr_arg = { 0 }; |
682 | struct cb_compound_hdr_res hdr_res = { NULL }; | 775 | struct cb_compound_hdr_res hdr_res = { NULL }; |
683 | struct xdr_stream xdr_in, xdr_out; | 776 | struct xdr_stream xdr_in, xdr_out; |
684 | __be32 *p; | 777 | __be32 *p, status; |
685 | __be32 status, drc_status = 0; | 778 | struct cb_process_state cps = { |
779 | .drc_status = 0, | ||
780 | .clp = NULL, | ||
781 | }; | ||
686 | unsigned int nops = 0; | 782 | unsigned int nops = 0; |
687 | 783 | ||
688 | dprintk("%s: start\n", __func__); | 784 | dprintk("%s: start\n", __func__); |
@@ -696,6 +792,13 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
696 | if (status == __constant_htonl(NFS4ERR_RESOURCE)) | 792 | if (status == __constant_htonl(NFS4ERR_RESOURCE)) |
697 | return rpc_garbage_args; | 793 | return rpc_garbage_args; |
698 | 794 | ||
795 | if (hdr_arg.minorversion == 0) { | ||
796 | cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident); | ||
797 | if (!cps.clp) | ||
798 | return rpc_drop_reply; | ||
799 | } else | ||
800 | cps.svc_sid = bc_xprt_sid(rqstp); | ||
801 | |||
699 | hdr_res.taglen = hdr_arg.taglen; | 802 | hdr_res.taglen = hdr_arg.taglen; |
700 | hdr_res.tag = hdr_arg.tag; | 803 | hdr_res.tag = hdr_arg.tag; |
701 | if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) | 804 | if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) |
@@ -703,7 +806,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
703 | 806 | ||
704 | while (status == 0 && nops != hdr_arg.nops) { | 807 | while (status == 0 && nops != hdr_arg.nops) { |
705 | status = process_op(hdr_arg.minorversion, nops, rqstp, | 808 | status = process_op(hdr_arg.minorversion, nops, rqstp, |
706 | &xdr_in, argp, &xdr_out, resp, &drc_status); | 809 | &xdr_in, argp, &xdr_out, resp, &cps); |
707 | nops++; | 810 | nops++; |
708 | } | 811 | } |
709 | 812 | ||
@@ -716,6 +819,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
716 | 819 | ||
717 | *hdr_res.status = status; | 820 | *hdr_res.status = status; |
718 | *hdr_res.nops = htonl(nops); | 821 | *hdr_res.nops = htonl(nops); |
822 | nfs4_cb_free_slot(cps.clp); | ||
823 | nfs_put_client(cps.clp); | ||
719 | dprintk("%s: done, status = %u\n", __func__, ntohl(status)); | 824 | dprintk("%s: done, status = %u\n", __func__, ntohl(status)); |
720 | return rpc_success; | 825 | return rpc_success; |
721 | } | 826 | } |
@@ -739,6 +844,12 @@ static struct callback_op callback_ops[] = { | |||
739 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, | 844 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, |
740 | }, | 845 | }, |
741 | #if defined(CONFIG_NFS_V4_1) | 846 | #if defined(CONFIG_NFS_V4_1) |
847 | [OP_CB_LAYOUTRECALL] = { | ||
848 | .process_op = (callback_process_op_t)nfs4_callback_layoutrecall, | ||
849 | .decode_args = | ||
850 | (callback_decode_arg_t)decode_layoutrecall_args, | ||
851 | .res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ, | ||
852 | }, | ||
742 | [OP_CB_SEQUENCE] = { | 853 | [OP_CB_SEQUENCE] = { |
743 | .process_op = (callback_process_op_t)nfs4_callback_sequence, | 854 | .process_op = (callback_process_op_t)nfs4_callback_sequence, |
744 | .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, | 855 | .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, |