aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/callback_xdr.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/nfs/callback_xdr.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'fs/nfs/callback_xdr.c')
-rw-r--r--fs/nfs/callback_xdr.c238
1 files changed, 221 insertions, 17 deletions
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 05af212f0edf..c6c86a77e043 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,8 @@
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)
28#define CB_OP_DEVICENOTIFY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
25#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ 29#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \
26 4 + 1 + 3) 30 4 + 1 + 3)
27#define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 31#define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
@@ -33,7 +37,8 @@
33/* Internal error code */ 37/* Internal error code */
34#define NFS4ERR_RESOURCE_HDR 11050 38#define NFS4ERR_RESOURCE_HDR 11050
35 39
36typedef __be32 (*callback_process_op_t)(void *, void *); 40typedef __be32 (*callback_process_op_t)(void *, void *,
41 struct cb_process_state *);
37typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); 42typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
38typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); 43typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
39 44
@@ -160,7 +165,7 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound
160 hdr->minorversion = ntohl(*p++); 165 hdr->minorversion = ntohl(*p++);
161 /* Check minor version is zero or one. */ 166 /* Check minor version is zero or one. */
162 if (hdr->minorversion <= 1) { 167 if (hdr->minorversion <= 1) {
163 p++; /* skip callback_ident */ 168 hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 */
164 } else { 169 } else {
165 printk(KERN_WARNING "%s: NFSv4 server callback with " 170 printk(KERN_WARNING "%s: NFSv4 server callback with "
166 "illegal minor version %u!\n", 171 "illegal minor version %u!\n",
@@ -220,6 +225,153 @@ out:
220 225
221#if defined(CONFIG_NFS_V4_1) 226#if defined(CONFIG_NFS_V4_1)
222 227
228static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp,
229 struct xdr_stream *xdr,
230 struct cb_layoutrecallargs *args)
231{
232 __be32 *p;
233 __be32 status = 0;
234 uint32_t iomode;
235
236 args->cbl_addr = svc_addr(rqstp);
237 p = read_buf(xdr, 4 * sizeof(uint32_t));
238 if (unlikely(p == NULL)) {
239 status = htonl(NFS4ERR_BADXDR);
240 goto out;
241 }
242
243 args->cbl_layout_type = ntohl(*p++);
244 /* Depite the spec's xdr, iomode really belongs in the FILE switch,
245 * as it is unusable and ignored with the other types.
246 */
247 iomode = ntohl(*p++);
248 args->cbl_layoutchanged = ntohl(*p++);
249 args->cbl_recall_type = ntohl(*p++);
250
251 if (args->cbl_recall_type == RETURN_FILE) {
252 args->cbl_range.iomode = iomode;
253 status = decode_fh(xdr, &args->cbl_fh);
254 if (unlikely(status != 0))
255 goto out;
256
257 p = read_buf(xdr, 2 * sizeof(uint64_t));
258 if (unlikely(p == NULL)) {
259 status = htonl(NFS4ERR_BADXDR);
260 goto out;
261 }
262 p = xdr_decode_hyper(p, &args->cbl_range.offset);
263 p = xdr_decode_hyper(p, &args->cbl_range.length);
264 status = decode_stateid(xdr, &args->cbl_stateid);
265 if (unlikely(status != 0))
266 goto out;
267 } else if (args->cbl_recall_type == RETURN_FSID) {
268 p = read_buf(xdr, 2 * sizeof(uint64_t));
269 if (unlikely(p == NULL)) {
270 status = htonl(NFS4ERR_BADXDR);
271 goto out;
272 }
273 p = xdr_decode_hyper(p, &args->cbl_fsid.major);
274 p = xdr_decode_hyper(p, &args->cbl_fsid.minor);
275 } else if (args->cbl_recall_type != RETURN_ALL) {
276 status = htonl(NFS4ERR_BADXDR);
277 goto out;
278 }
279 dprintk("%s: ltype 0x%x iomode %d changed %d recall_type %d\n",
280 __func__,
281 args->cbl_layout_type, iomode,
282 args->cbl_layoutchanged, args->cbl_recall_type);
283out:
284 dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
285 return status;
286}
287
288static
289__be32 decode_devicenotify_args(struct svc_rqst *rqstp,
290 struct xdr_stream *xdr,
291 struct cb_devicenotifyargs *args)
292{
293 __be32 *p;
294 __be32 status = 0;
295 u32 tmp;
296 int n, i;
297 args->ndevs = 0;
298
299 /* Num of device notifications */
300 p = read_buf(xdr, sizeof(uint32_t));
301 if (unlikely(p == NULL)) {
302 status = htonl(NFS4ERR_BADXDR);
303 goto out;
304 }
305 n = ntohl(*p++);
306 if (n <= 0)
307 goto out;
308
309 args->devs = kmalloc(n * sizeof(*args->devs), GFP_KERNEL);
310 if (!args->devs) {
311 status = htonl(NFS4ERR_DELAY);
312 goto out;
313 }
314
315 /* Decode each dev notification */
316 for (i = 0; i < n; i++) {
317 struct cb_devicenotifyitem *dev = &args->devs[i];
318
319 p = read_buf(xdr, (4 * sizeof(uint32_t)) + NFS4_DEVICEID4_SIZE);
320 if (unlikely(p == NULL)) {
321 status = htonl(NFS4ERR_BADXDR);
322 goto err;
323 }
324
325 tmp = ntohl(*p++); /* bitmap size */
326 if (tmp != 1) {
327 status = htonl(NFS4ERR_INVAL);
328 goto err;
329 }
330 dev->cbd_notify_type = ntohl(*p++);
331 if (dev->cbd_notify_type != NOTIFY_DEVICEID4_CHANGE &&
332 dev->cbd_notify_type != NOTIFY_DEVICEID4_DELETE) {
333 status = htonl(NFS4ERR_INVAL);
334 goto err;
335 }
336
337 tmp = ntohl(*p++); /* opaque size */
338 if (((dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE) &&
339 (tmp != NFS4_DEVICEID4_SIZE + 8)) ||
340 ((dev->cbd_notify_type == NOTIFY_DEVICEID4_DELETE) &&
341 (tmp != NFS4_DEVICEID4_SIZE + 4))) {
342 status = htonl(NFS4ERR_INVAL);
343 goto err;
344 }
345 dev->cbd_layout_type = ntohl(*p++);
346 memcpy(dev->cbd_dev_id.data, p, NFS4_DEVICEID4_SIZE);
347 p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
348
349 if (dev->cbd_layout_type == NOTIFY_DEVICEID4_CHANGE) {
350 p = read_buf(xdr, sizeof(uint32_t));
351 if (unlikely(p == NULL)) {
352 status = htonl(NFS4ERR_BADXDR);
353 goto err;
354 }
355 dev->cbd_immediate = ntohl(*p++);
356 } else {
357 dev->cbd_immediate = 0;
358 }
359
360 args->ndevs++;
361
362 dprintk("%s: type %d layout 0x%x immediate %d\n",
363 __func__, dev->cbd_notify_type, dev->cbd_layout_type,
364 dev->cbd_immediate);
365 }
366out:
367 dprintk("%s: status %d ndevs %d\n",
368 __func__, ntohl(status), args->ndevs);
369 return status;
370err:
371 kfree(args->devs);
372 goto out;
373}
374
223static __be32 decode_sessionid(struct xdr_stream *xdr, 375static __be32 decode_sessionid(struct xdr_stream *xdr,
224 struct nfs4_sessionid *sid) 376 struct nfs4_sessionid *sid)
225{ 377{
@@ -574,11 +726,11 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
574 case OP_CB_SEQUENCE: 726 case OP_CB_SEQUENCE:
575 case OP_CB_RECALL_ANY: 727 case OP_CB_RECALL_ANY:
576 case OP_CB_RECALL_SLOT: 728 case OP_CB_RECALL_SLOT:
729 case OP_CB_LAYOUTRECALL:
730 case OP_CB_NOTIFY_DEVICEID:
577 *op = &callback_ops[op_nr]; 731 *op = &callback_ops[op_nr];
578 break; 732 break;
579 733
580 case OP_CB_LAYOUTRECALL:
581 case OP_CB_NOTIFY_DEVICEID:
582 case OP_CB_NOTIFY: 734 case OP_CB_NOTIFY:
583 case OP_CB_PUSH_DELEG: 735 case OP_CB_PUSH_DELEG:
584 case OP_CB_RECALLABLE_OBJ_AVAIL: 736 case OP_CB_RECALLABLE_OBJ_AVAIL:
@@ -593,6 +745,37 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
593 return htonl(NFS_OK); 745 return htonl(NFS_OK);
594} 746}
595 747
748static void nfs4_callback_free_slot(struct nfs4_session *session)
749{
750 struct nfs4_slot_table *tbl = &session->bc_slot_table;
751
752 spin_lock(&tbl->slot_tbl_lock);
753 /*
754 * Let the state manager know callback processing done.
755 * A single slot, so highest used slotid is either 0 or -1
756 */
757 tbl->highest_used_slotid--;
758 nfs4_check_drain_bc_complete(session);
759 spin_unlock(&tbl->slot_tbl_lock);
760}
761
762static void nfs4_cb_free_slot(struct nfs_client *clp)
763{
764 if (clp && clp->cl_session)
765 nfs4_callback_free_slot(clp->cl_session);
766}
767
768/* A single slot, so highest used slotid is either 0 or -1 */
769void nfs4_cb_take_slot(struct nfs_client *clp)
770{
771 struct nfs4_slot_table *tbl = &clp->cl_session->bc_slot_table;
772
773 spin_lock(&tbl->slot_tbl_lock);
774 tbl->highest_used_slotid++;
775 BUG_ON(tbl->highest_used_slotid != 0);
776 spin_unlock(&tbl->slot_tbl_lock);
777}
778
596#else /* CONFIG_NFS_V4_1 */ 779#else /* CONFIG_NFS_V4_1 */
597 780
598static __be32 781static __be32
@@ -601,6 +784,9 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
601 return htonl(NFS4ERR_MINOR_VERS_MISMATCH); 784 return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
602} 785}
603 786
787static void nfs4_cb_free_slot(struct nfs_client *clp)
788{
789}
604#endif /* CONFIG_NFS_V4_1 */ 790#endif /* CONFIG_NFS_V4_1 */
605 791
606static __be32 792static __be32
@@ -621,7 +807,8 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op)
621static __be32 process_op(uint32_t minorversion, int nop, 807static __be32 process_op(uint32_t minorversion, int nop,
622 struct svc_rqst *rqstp, 808 struct svc_rqst *rqstp,
623 struct xdr_stream *xdr_in, void *argp, 809 struct xdr_stream *xdr_in, void *argp,
624 struct xdr_stream *xdr_out, void *resp, int* drc_status) 810 struct xdr_stream *xdr_out, void *resp,
811 struct cb_process_state *cps)
625{ 812{
626 struct callback_op *op = &callback_ops[0]; 813 struct callback_op *op = &callback_ops[0];
627 unsigned int op_nr; 814 unsigned int op_nr;
@@ -644,8 +831,8 @@ static __be32 process_op(uint32_t minorversion, int nop,
644 if (status) 831 if (status)
645 goto encode_hdr; 832 goto encode_hdr;
646 833
647 if (*drc_status) { 834 if (cps->drc_status) {
648 status = *drc_status; 835 status = cps->drc_status;
649 goto encode_hdr; 836 goto encode_hdr;
650 } 837 }
651 838
@@ -653,16 +840,10 @@ static __be32 process_op(uint32_t minorversion, int nop,
653 if (maxlen > 0 && maxlen < PAGE_SIZE) { 840 if (maxlen > 0 && maxlen < PAGE_SIZE) {
654 status = op->decode_args(rqstp, xdr_in, argp); 841 status = op->decode_args(rqstp, xdr_in, argp);
655 if (likely(status == 0)) 842 if (likely(status == 0))
656 status = op->process_op(argp, resp); 843 status = op->process_op(argp, resp, cps);
657 } else 844 } else
658 status = htonl(NFS4ERR_RESOURCE); 845 status = htonl(NFS4ERR_RESOURCE);
659 846
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
666encode_hdr: 847encode_hdr:
667 res = encode_op_hdr(xdr_out, op_nr, status); 848 res = encode_op_hdr(xdr_out, op_nr, status);
668 if (unlikely(res)) 849 if (unlikely(res))
@@ -681,8 +862,11 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
681 struct cb_compound_hdr_arg hdr_arg = { 0 }; 862 struct cb_compound_hdr_arg hdr_arg = { 0 };
682 struct cb_compound_hdr_res hdr_res = { NULL }; 863 struct cb_compound_hdr_res hdr_res = { NULL };
683 struct xdr_stream xdr_in, xdr_out; 864 struct xdr_stream xdr_in, xdr_out;
684 __be32 *p; 865 __be32 *p, status;
685 __be32 status, drc_status = 0; 866 struct cb_process_state cps = {
867 .drc_status = 0,
868 .clp = NULL,
869 };
686 unsigned int nops = 0; 870 unsigned int nops = 0;
687 871
688 dprintk("%s: start\n", __func__); 872 dprintk("%s: start\n", __func__);
@@ -696,6 +880,12 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
696 if (status == __constant_htonl(NFS4ERR_RESOURCE)) 880 if (status == __constant_htonl(NFS4ERR_RESOURCE))
697 return rpc_garbage_args; 881 return rpc_garbage_args;
698 882
883 if (hdr_arg.minorversion == 0) {
884 cps.clp = nfs4_find_client_ident(hdr_arg.cb_ident);
885 if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
886 return rpc_drop_reply;
887 }
888
699 hdr_res.taglen = hdr_arg.taglen; 889 hdr_res.taglen = hdr_arg.taglen;
700 hdr_res.tag = hdr_arg.tag; 890 hdr_res.tag = hdr_arg.tag;
701 if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) 891 if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0)
@@ -703,7 +893,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
703 893
704 while (status == 0 && nops != hdr_arg.nops) { 894 while (status == 0 && nops != hdr_arg.nops) {
705 status = process_op(hdr_arg.minorversion, nops, rqstp, 895 status = process_op(hdr_arg.minorversion, nops, rqstp,
706 &xdr_in, argp, &xdr_out, resp, &drc_status); 896 &xdr_in, argp, &xdr_out, resp, &cps);
707 nops++; 897 nops++;
708 } 898 }
709 899
@@ -716,6 +906,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
716 906
717 *hdr_res.status = status; 907 *hdr_res.status = status;
718 *hdr_res.nops = htonl(nops); 908 *hdr_res.nops = htonl(nops);
909 nfs4_cb_free_slot(cps.clp);
910 nfs_put_client(cps.clp);
719 dprintk("%s: done, status = %u\n", __func__, ntohl(status)); 911 dprintk("%s: done, status = %u\n", __func__, ntohl(status));
720 return rpc_success; 912 return rpc_success;
721} 913}
@@ -739,6 +931,18 @@ static struct callback_op callback_ops[] = {
739 .res_maxsize = CB_OP_RECALL_RES_MAXSZ, 931 .res_maxsize = CB_OP_RECALL_RES_MAXSZ,
740 }, 932 },
741#if defined(CONFIG_NFS_V4_1) 933#if defined(CONFIG_NFS_V4_1)
934 [OP_CB_LAYOUTRECALL] = {
935 .process_op = (callback_process_op_t)nfs4_callback_layoutrecall,
936 .decode_args =
937 (callback_decode_arg_t)decode_layoutrecall_args,
938 .res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ,
939 },
940 [OP_CB_NOTIFY_DEVICEID] = {
941 .process_op = (callback_process_op_t)nfs4_callback_devicenotify,
942 .decode_args =
943 (callback_decode_arg_t)decode_devicenotify_args,
944 .res_maxsize = CB_OP_DEVICENOTIFY_RES_MAXSZ,
945 },
742 [OP_CB_SEQUENCE] = { 946 [OP_CB_SEQUENCE] = {
743 .process_op = (callback_process_op_t)nfs4_callback_sequence, 947 .process_op = (callback_process_op_t)nfs4_callback_sequence,
744 .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, 948 .decode_args = (callback_decode_arg_t)decode_cb_sequence_args,