7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/systm.h>
28 #include <sys/sdt.h>
29 #include <rpc/types.h>
30 #include <rpc/auth.h>
31 #include <rpc/auth_unix.h>
32 #include <rpc/auth_des.h>
33 #include <rpc/svc.h>
34 #include <rpc/xdr.h>
35 #include <nfs/nfs4.h>
36 #include <nfs/nfs_dispatch.h>
37 #include <nfs/nfs4_drc.h>
38
39 #define NFS4_MAX_MINOR_VERSION 0
40
41 /*
42 * This is the duplicate request cache for NFSv4
43 */
44 rfs4_drc_t *nfs4_drc = NULL;
45
46 /*
47 * The default size of the duplicate request cache
48 */
49 uint32_t nfs4_drc_max = 8 * 1024;
50
51 /*
52 * The number of buckets we'd like to hash the
53 * replies into.. do not change this on the fly.
54 */
55 uint32_t nfs4_drc_hash = 541;
56
57 static void rfs4_resource_err(struct svc_req *req, COMPOUND4args *argsp);
58
59 /*
60 * Initialize a duplicate request cache.
61 */
62 rfs4_drc_t *
63 rfs4_init_drc(uint32_t drc_size, uint32_t drc_hash_size)
64 {
65 rfs4_drc_t *drc;
66 uint32_t bki;
77
78 drc->dr_hash = drc_hash_size;
79
80 drc->dr_buckets = kmem_alloc(sizeof (list_t)*drc_hash_size, KM_SLEEP);
81
82 for (bki = 0; bki < drc_hash_size; bki++) {
83 list_create(&drc->dr_buckets[bki], sizeof (rfs4_dupreq_t),
84 offsetof(rfs4_dupreq_t, dr_bkt_next));
85 }
86
87 list_create(&(drc->dr_cache), sizeof (rfs4_dupreq_t),
88 offsetof(rfs4_dupreq_t, dr_next));
89
90 return (drc);
91 }
92
93 /*
94 * Destroy a duplicate request cache.
95 */
96 void
97 rfs4_fini_drc(rfs4_drc_t *drc)
98 {
99 rfs4_dupreq_t *drp, *drp_next;
100
101 ASSERT(drc);
102
103 /* iterate over the dr_cache and free the enties */
104 for (drp = list_head(&(drc->dr_cache)); drp != NULL; drp = drp_next) {
105
106 if (drp->dr_state == NFS4_DUP_REPLAY)
107 rfs4_compound_free(&(drp->dr_res));
108
109 if (drp->dr_addr.buf != NULL)
110 kmem_free(drp->dr_addr.buf, drp->dr_addr.maxlen);
111
112 drp_next = list_next(&(drc->dr_cache), drp);
113
114 kmem_free(drp, sizeof (rfs4_dupreq_t));
115 }
116
117 mutex_destroy(&drc->lock);
118 kmem_free(drc->dr_buckets,
119 sizeof (list_t)*drc->dr_hash);
120 kmem_free(drc, sizeof (rfs4_drc_t));
121 }
122
356 *
357 * Passed into this function are:-
358 *
359 * disp A pointer to our dispatch table entry
360 * req The request to process
361 * xprt The server transport handle
362 * ap A pointer to the arguments
363 *
364 *
365 * When appropriate this function is responsible for inserting
366 * the reply into the duplicate cache or replaying an existing
367 * cached reply.
368 *
369 * dr_stat reflects the state of the duplicate request that
370 * has been inserted into or retrieved from the cache
371 *
372 * drp is the duplicate request entry
373 *
374 */
375 int
376 rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req,
377 SVCXPRT *xprt, char *ap)
378 {
379
380 COMPOUND4res res_buf;
381 COMPOUND4res *rbp;
382 COMPOUND4args *cap;
383 cred_t *cr = NULL;
384 int error = 0;
385 int dis_flags = 0;
386 int dr_stat = NFS4_NOT_DUP;
387 rfs4_dupreq_t *drp = NULL;
388 int rv;
389
390 ASSERT(disp);
391
392 /*
393 * Short circuit the RPC_NULL proc.
394 */
395 if (disp->dis_proc == rpc_null) {
396 DTRACE_NFSV4_1(null__start, struct svc_req *, req);
397 if (!svc_sendreply(xprt, xdr_void, NULL)) {
398 DTRACE_NFSV4_1(null__done, struct svc_req *, req);
399 svcerr_systemerr(xprt);
400 return (1);
401 }
402 DTRACE_NFSV4_1(null__done, struct svc_req *, req);
403 return (0);
404 }
405
406 /* Only NFSv4 Compounds from this point onward */
407
408 rbp = &res_buf;
527 return (error);
528 }
529
530 bool_t
531 rfs4_minorvers_mismatch(struct svc_req *req, SVCXPRT *xprt, void *args)
532 {
533 COMPOUND4args *argsp;
534 COMPOUND4res res_buf, *resp;
535
536 if (req->rq_vers != 4)
537 return (FALSE);
538
539 argsp = (COMPOUND4args *)args;
540
541 if (argsp->minorversion <= NFS4_MAX_MINOR_VERSION)
542 return (FALSE);
543
544 resp = &res_buf;
545
546 /*
547 * Form a reply tag by copying over the reqeuest tag.
548 */
549 resp->tag.utf8string_val =
550 kmem_alloc(argsp->tag.utf8string_len, KM_SLEEP);
551 resp->tag.utf8string_len = argsp->tag.utf8string_len;
552 bcopy(argsp->tag.utf8string_val, resp->tag.utf8string_val,
553 resp->tag.utf8string_len);
554 resp->array_len = 0;
555 resp->array = NULL;
556 resp->status = NFS4ERR_MINOR_VERS_MISMATCH;
557 if (!svc_sendreply(xprt, xdr_COMPOUND4res_srv, (char *)resp)) {
558 DTRACE_PROBE2(nfss__e__minorvers_mismatch,
559 SVCXPRT *, xprt, char *, resp);
560 svcerr_systemerr(xprt);
561 }
562 rfs4_compound_free(resp);
563 return (TRUE);
564 }
565
566 void
567 rfs4_resource_err(struct svc_req *req, COMPOUND4args *argsp)
568 {
569 COMPOUND4res res_buf, *rbp;
570 nfs_resop4 *resop;
571 PUTFH4res *resp;
572
573 rbp = &res_buf;
574
575 /*
576 * Form a reply tag by copying over the request tag.
577 */
578 rbp->tag.utf8string_val =
579 kmem_alloc(argsp->tag.utf8string_len, KM_SLEEP);
580 rbp->tag.utf8string_len = argsp->tag.utf8string_len;
581 bcopy(argsp->tag.utf8string_val, rbp->tag.utf8string_val,
582 rbp->tag.utf8string_len);
583
584 rbp->array_len = 1;
585 rbp->array = kmem_zalloc(rbp->array_len * sizeof (nfs_resop4),
586 KM_SLEEP);
587 resop = &rbp->array[0];
588 resop->resop = argsp->array[0].argop; /* copy first op over */
589
590 /* Any op will do, just need to access status field */
591 resp = &resop->nfs_resop4_u.opputfh;
592
593 /*
594 * NFS4ERR_RESOURCE is allowed for all ops, except OP_ILLEGAL.
595 * Note that all op numbers in the compound array were already
596 * validated by the XDR decoder (xdr_COMPOUND4args_srv()).
597 */
598 resp->status = (resop->resop == OP_ILLEGAL ?
599 NFS4ERR_OP_ILLEGAL : NFS4ERR_RESOURCE);
600
601 /* compound status is same as first op status */
602 rbp->status = resp->status;
|
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright 2018 Nexenta Systems, Inc.
29 */
30
31 #include <sys/systm.h>
32 #include <sys/sdt.h>
33 #include <rpc/types.h>
34 #include <rpc/auth.h>
35 #include <rpc/auth_unix.h>
36 #include <rpc/auth_des.h>
37 #include <rpc/svc.h>
38 #include <rpc/xdr.h>
39 #include <nfs/nfs4.h>
40 #include <nfs/nfs_dispatch.h>
41 #include <nfs/nfs4_drc.h>
42
43 #define NFS4_MAX_MINOR_VERSION 0
44
45 /*
46 * The default size of the duplicate request cache
47 */
48 uint32_t nfs4_drc_max = 8 * 1024;
49
50 /*
51 * The number of buckets we'd like to hash the
52 * replies into.. do not change this on the fly.
53 */
54 uint32_t nfs4_drc_hash = 541;
55
56 static void rfs4_resource_err(struct svc_req *req, COMPOUND4args *argsp);
57
58 /*
59 * Initialize a duplicate request cache.
60 */
61 rfs4_drc_t *
62 rfs4_init_drc(uint32_t drc_size, uint32_t drc_hash_size)
63 {
64 rfs4_drc_t *drc;
65 uint32_t bki;
76
77 drc->dr_hash = drc_hash_size;
78
79 drc->dr_buckets = kmem_alloc(sizeof (list_t)*drc_hash_size, KM_SLEEP);
80
81 for (bki = 0; bki < drc_hash_size; bki++) {
82 list_create(&drc->dr_buckets[bki], sizeof (rfs4_dupreq_t),
83 offsetof(rfs4_dupreq_t, dr_bkt_next));
84 }
85
86 list_create(&(drc->dr_cache), sizeof (rfs4_dupreq_t),
87 offsetof(rfs4_dupreq_t, dr_next));
88
89 return (drc);
90 }
91
92 /*
93 * Destroy a duplicate request cache.
94 */
95 void
96 rfs4_fini_drc(void)
97 {
98 nfs4_srv_t *nsrv4 = nfs4_get_srv();
99 rfs4_drc_t *drc = nsrv4->nfs4_drc;
100 rfs4_dupreq_t *drp, *drp_next;
101
102 /* iterate over the dr_cache and free the enties */
103 for (drp = list_head(&(drc->dr_cache)); drp != NULL; drp = drp_next) {
104
105 if (drp->dr_state == NFS4_DUP_REPLAY)
106 rfs4_compound_free(&(drp->dr_res));
107
108 if (drp->dr_addr.buf != NULL)
109 kmem_free(drp->dr_addr.buf, drp->dr_addr.maxlen);
110
111 drp_next = list_next(&(drc->dr_cache), drp);
112
113 kmem_free(drp, sizeof (rfs4_dupreq_t));
114 }
115
116 mutex_destroy(&drc->lock);
117 kmem_free(drc->dr_buckets,
118 sizeof (list_t)*drc->dr_hash);
119 kmem_free(drc, sizeof (rfs4_drc_t));
120 }
121
355 *
356 * Passed into this function are:-
357 *
358 * disp A pointer to our dispatch table entry
359 * req The request to process
360 * xprt The server transport handle
361 * ap A pointer to the arguments
362 *
363 *
364 * When appropriate this function is responsible for inserting
365 * the reply into the duplicate cache or replaying an existing
366 * cached reply.
367 *
368 * dr_stat reflects the state of the duplicate request that
369 * has been inserted into or retrieved from the cache
370 *
371 * drp is the duplicate request entry
372 *
373 */
374 int
375 rfs4_dispatch(struct rpcdisp *disp, struct svc_req *req, SVCXPRT *xprt,
376 char *ap)
377 {
378
379 COMPOUND4res res_buf;
380 COMPOUND4res *rbp;
381 COMPOUND4args *cap;
382 cred_t *cr = NULL;
383 int error = 0;
384 int dis_flags = 0;
385 int dr_stat = NFS4_NOT_DUP;
386 rfs4_dupreq_t *drp = NULL;
387 int rv;
388 nfs4_srv_t *nsrv4 = nfs4_get_srv();
389 rfs4_drc_t *nfs4_drc = nsrv4->nfs4_drc;
390
391 ASSERT(disp);
392
393 /*
394 * Short circuit the RPC_NULL proc.
395 */
396 if (disp->dis_proc == rpc_null) {
397 DTRACE_NFSV4_1(null__start, struct svc_req *, req);
398 if (!svc_sendreply(xprt, xdr_void, NULL)) {
399 DTRACE_NFSV4_1(null__done, struct svc_req *, req);
400 svcerr_systemerr(xprt);
401 return (1);
402 }
403 DTRACE_NFSV4_1(null__done, struct svc_req *, req);
404 return (0);
405 }
406
407 /* Only NFSv4 Compounds from this point onward */
408
409 rbp = &res_buf;
528 return (error);
529 }
530
531 bool_t
532 rfs4_minorvers_mismatch(struct svc_req *req, SVCXPRT *xprt, void *args)
533 {
534 COMPOUND4args *argsp;
535 COMPOUND4res res_buf, *resp;
536
537 if (req->rq_vers != 4)
538 return (FALSE);
539
540 argsp = (COMPOUND4args *)args;
541
542 if (argsp->minorversion <= NFS4_MAX_MINOR_VERSION)
543 return (FALSE);
544
545 resp = &res_buf;
546
547 /*
548 * Form a reply tag by copying over the request tag.
549 */
550 resp->tag.utf8string_len = argsp->tag.utf8string_len;
551 if (argsp->tag.utf8string_len != 0) {
552 resp->tag.utf8string_val =
553 kmem_alloc(argsp->tag.utf8string_len, KM_SLEEP);
554 bcopy(argsp->tag.utf8string_val, resp->tag.utf8string_val,
555 resp->tag.utf8string_len);
556 } else {
557 resp->tag.utf8string_val = NULL;
558 }
559 resp->array_len = 0;
560 resp->array = NULL;
561 resp->status = NFS4ERR_MINOR_VERS_MISMATCH;
562 if (!svc_sendreply(xprt, xdr_COMPOUND4res_srv, (char *)resp)) {
563 DTRACE_PROBE2(nfss__e__minorvers_mismatch,
564 SVCXPRT *, xprt, char *, resp);
565 svcerr_systemerr(xprt);
566 }
567 rfs4_compound_free(resp);
568 return (TRUE);
569 }
570
571 void
572 rfs4_resource_err(struct svc_req *req, COMPOUND4args *argsp)
573 {
574 COMPOUND4res res_buf, *rbp;
575 nfs_resop4 *resop;
576 PUTFH4res *resp;
577
578 rbp = &res_buf;
579
580 /*
581 * Form a reply tag by copying over the request tag.
582 */
583 rbp->tag.utf8string_len = argsp->tag.utf8string_len;
584 if (argsp->tag.utf8string_len != 0) {
585 rbp->tag.utf8string_val =
586 kmem_alloc(argsp->tag.utf8string_len, KM_SLEEP);
587 bcopy(argsp->tag.utf8string_val, rbp->tag.utf8string_val,
588 rbp->tag.utf8string_len);
589 } else {
590 rbp->tag.utf8string_val = NULL;
591 }
592
593 rbp->array_len = 1;
594 rbp->array = kmem_zalloc(rbp->array_len * sizeof (nfs_resop4),
595 KM_SLEEP);
596 resop = &rbp->array[0];
597 resop->resop = argsp->array[0].argop; /* copy first op over */
598
599 /* Any op will do, just need to access status field */
600 resp = &resop->nfs_resop4_u.opputfh;
601
602 /*
603 * NFS4ERR_RESOURCE is allowed for all ops, except OP_ILLEGAL.
604 * Note that all op numbers in the compound array were already
605 * validated by the XDR decoder (xdr_COMPOUND4args_srv()).
606 */
607 resp->status = (resop->resop == OP_ILLEGAL ?
608 NFS4ERR_OP_ILLEGAL : NFS4ERR_RESOURCE);
609
610 /* compound status is same as first op status */
611 rbp->status = resp->status;
|