Print this page
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16


   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;