Print this page
    
7651 default maximum nfs server threads is insufficient
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/rpc/svc_clts.c
          +++ new/usr/src/uts/common/rpc/svc_clts.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  
    | 
      ↓ open down ↓ | 
    14 lines elided | 
    
      ↑ open up ↑ | 
  
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24   24   *  Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
       25 + * Copyright (c) 2012 by Delphix. All rights reserved.
  25   26   */
  26   27  
  27   28  /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
  28   29  /*        All Rights Reserved   */
  29   30  
  30   31  /*
  31   32   * Portions of this source code were derived from Berkeley 4.3 BSD
  32   33   * under license from the Regents of the University of California.
  33   34   */
  34   35  
  35   36  /*
  36   37   * svc_clts.c
  37   38   * Server side for RPC in the kernel.
  38   39   *
  39   40   */
  40   41  
  41   42  #include <sys/param.h>
  42   43  #include <sys/types.h>
  43   44  #include <sys/sysmacros.h>
  44   45  #include <sys/file.h>
  45   46  #include <sys/stream.h>
  46   47  #include <sys/strsun.h>
  47   48  #include <sys/strsubr.h>
  48   49  #include <sys/tihdr.h>
  49   50  #include <sys/tiuser.h>
  50   51  #include <sys/t_kuser.h>
  51   52  #include <sys/fcntl.h>
  52   53  #include <sys/errno.h>
  53   54  #include <sys/kmem.h>
  54   55  #include <sys/systm.h>
  55   56  #include <sys/cmn_err.h>
  56   57  #include <sys/kstat.h>
  57   58  #include <sys/vtrace.h>
  58   59  #include <sys/debug.h>
  59   60  
  60   61  #include <rpc/types.h>
  61   62  #include <rpc/xdr.h>
  62   63  #include <rpc/auth.h>
  63   64  #include <rpc/clnt.h>
  64   65  #include <rpc/rpc_msg.h>
  65   66  #include <rpc/svc.h>
  66   67  #include <inet/ip.h>
  67   68  
  68   69  /*
  69   70   * Routines exported through ops vector.
  70   71   */
  71   72  static bool_t           svc_clts_krecv(SVCXPRT *, mblk_t *, struct rpc_msg *);
  72   73  static bool_t           svc_clts_ksend(SVCXPRT *, struct rpc_msg *);
  73   74  static bool_t           svc_clts_kgetargs(SVCXPRT *, xdrproc_t, caddr_t);
  74   75  static bool_t           svc_clts_kfreeargs(SVCXPRT *, xdrproc_t, caddr_t);
  75   76  static void             svc_clts_kdestroy(SVCMASTERXPRT *);
  76   77  static int              svc_clts_kdup(struct svc_req *, caddr_t, int,
  77   78                                  struct dupreq **, bool_t *);
  78   79  static void             svc_clts_kdupdone(struct dupreq *, caddr_t,
  79   80                                  void (*)(), int, int);
  80   81  static int32_t          *svc_clts_kgetres(SVCXPRT *, int);
  81   82  static void             svc_clts_kclone_destroy(SVCXPRT *);
  82   83  static void             svc_clts_kfreeres(SVCXPRT *);
  83   84  static void             svc_clts_kstart(SVCMASTERXPRT *);
  84   85  static void             svc_clts_kclone_xprt(SVCXPRT *, SVCXPRT *);
  85   86  static void             svc_clts_ktattrs(SVCXPRT *, int, void **);
  86   87  
  87   88  /*
  88   89   * Server transport operations vector.
  89   90   */
  90   91  struct svc_ops svc_clts_op = {
  91   92          svc_clts_krecv,         /* Get requests */
  92   93          svc_clts_kgetargs,      /* Deserialize arguments */
  93   94          svc_clts_ksend,         /* Send reply */
  94   95          svc_clts_kfreeargs,     /* Free argument data space */
  95   96          svc_clts_kdestroy,      /* Destroy transport handle */
  96   97          svc_clts_kdup,          /* Check entry in dup req cache */
  97   98          svc_clts_kdupdone,      /* Mark entry in dup req cache as done */
  98   99          svc_clts_kgetres,       /* Get pointer to response buffer */
  99  100          svc_clts_kfreeres,      /* Destroy pre-serialized response header */
 100  101          svc_clts_kclone_destroy, /* Destroy a clone xprt */
 101  102          svc_clts_kstart,        /* Tell `ready-to-receive' to rpcmod */
 102  103          svc_clts_kclone_xprt,   /* transport specific clone xprt function */
 103  104          svc_clts_ktattrs        /* Transport specific attributes. */
 104  105  };
 105  106  
 106  107  /*
 107  108   * Transport private data.
 108  109   * Kept in xprt->xp_p2buf.
 109  110   */
 110  111  struct udp_data {
 111  112          mblk_t  *ud_resp;                       /* buffer for response */
 112  113          mblk_t  *ud_inmp;                       /* mblk chain of request */
 113  114  };
 114  115  
 115  116  #define UD_MAXSIZE      8800
 116  117  #define UD_INITSIZE     2048
 117  118  
 118  119  /*
 119  120   * Connectionless server statistics
 120  121   */
 121  122  static const struct rpc_clts_server {
 122  123          kstat_named_t   rscalls;
 123  124          kstat_named_t   rsbadcalls;
 124  125          kstat_named_t   rsnullrecv;
 125  126          kstat_named_t   rsbadlen;
 126  127          kstat_named_t   rsxdrcall;
 127  128          kstat_named_t   rsdupchecks;
 128  129          kstat_named_t   rsdupreqs;
 129  130  } clts_rsstat_tmpl = {
 130  131          { "calls",      KSTAT_DATA_UINT64 },
 131  132          { "badcalls",   KSTAT_DATA_UINT64 },
 132  133          { "nullrecv",   KSTAT_DATA_UINT64 },
 133  134          { "badlen",     KSTAT_DATA_UINT64 },
 134  135          { "xdrcall",    KSTAT_DATA_UINT64 },
 135  136          { "dupchecks",  KSTAT_DATA_UINT64 },
 136  137          { "dupreqs",    KSTAT_DATA_UINT64 }
 137  138  };
 138  139  
 139  140  static uint_t clts_rsstat_ndata =
 140  141          sizeof (clts_rsstat_tmpl) / sizeof (kstat_named_t);
 141  142  
 142  143  #define CLONE2STATS(clone_xprt) \
 143  144          (struct rpc_clts_server *)(clone_xprt)->xp_master->xp_p2
 144  145  
 145  146  #define RSSTAT_INCR(stats, x)   \
 146  147          atomic_inc_64(&(stats)->x.value.ui64)
 147  148  
 148  149  /*
 149  150   * Create a transport record.
 150  151   * The transport record, output buffer, and private data structure
 151  152   * are allocated.  The output buffer is serialized into using xdrmem.
 152  153   * There is one transport record per user process which implements a
 153  154   * set of services.
 154  155   */
 155  156  /* ARGSUSED */
 156  157  int
 157  158  svc_clts_kcreate(file_t *fp, uint_t sendsz, struct T_info_ack *tinfo,
 158  159      SVCMASTERXPRT **nxprt)
 159  160  {
 160  161          SVCMASTERXPRT *xprt;
 161  162          struct rpcstat *rpcstat;
 162  163  
 163  164          if (nxprt == NULL)
 164  165                  return (EINVAL);
 165  166  
 166  167          rpcstat = zone_getspecific(rpcstat_zone_key, curproc->p_zone);
 167  168          ASSERT(rpcstat != NULL);
 168  169  
 169  170          xprt = kmem_zalloc(sizeof (*xprt), KM_SLEEP);
 170  171          xprt->xp_lcladdr.buf = kmem_zalloc(sizeof (sin6_t), KM_SLEEP);
 171  172          xprt->xp_p2 = (caddr_t)rpcstat->rpc_clts_server;
 172  173          xprt->xp_ops = &svc_clts_op;
 173  174          xprt->xp_msg_size = tinfo->TSDU_size;
 174  175  
 175  176          xprt->xp_rtaddr.buf = NULL;
 176  177          xprt->xp_rtaddr.maxlen = tinfo->ADDR_size;
 177  178          xprt->xp_rtaddr.len = 0;
 178  179  
 179  180          *nxprt = xprt;
 180  181  
 181  182          return (0);
 182  183  }
 183  184  
 184  185  /*
 185  186   * Destroy a transport record.
 186  187   * Frees the space allocated for a transport record.
 187  188   */
 188  189  static void
 189  190  svc_clts_kdestroy(SVCMASTERXPRT *xprt)
 190  191  {
 191  192          if (xprt->xp_netid)
 192  193                  kmem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
 193  194          if (xprt->xp_addrmask.maxlen)
 194  195                  kmem_free(xprt->xp_addrmask.buf, xprt->xp_addrmask.maxlen);
 195  196  
 196  197          mutex_destroy(&xprt->xp_req_lock);
 197  198          mutex_destroy(&xprt->xp_thread_lock);
 198  199  
 199  200          kmem_free(xprt->xp_lcladdr.buf, sizeof (sin6_t));
 200  201          kmem_free(xprt, sizeof (SVCMASTERXPRT));
 201  202  }
 202  203  
 203  204  /*
 204  205   * Transport-type specific part of svc_xprt_cleanup().
 205  206   * Frees the message buffer space allocated for a clone of a transport record
 206  207   */
 207  208  static void
 208  209  svc_clts_kclone_destroy(SVCXPRT *clone_xprt)
 209  210  {
 210  211          /* LINTED pointer alignment */
 211  212          struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf;
 212  213  
 213  214          if (ud->ud_resp) {
 214  215                  /*
 215  216                   * There should not be any left over results buffer.
 216  217                   */
 217  218                  ASSERT(ud->ud_resp->b_cont == NULL);
 218  219  
 219  220                  /*
 220  221                   * Free the T_UNITDATA_{REQ/IND} that svc_clts_krecv
 221  222                   * saved.
 222  223                   */
 223  224                  freeb(ud->ud_resp);
 224  225          }
 225  226          if (ud->ud_inmp)
 226  227                  freemsg(ud->ud_inmp);
 227  228  }
 228  229  
 229  230  /*
 230  231   * svc_tli_kcreate() calls this function at the end to tell
 231  232   * rpcmod that the transport is ready to receive requests.
 232  233   */
 233  234  /* ARGSUSED */
 234  235  static void
 235  236  svc_clts_kstart(SVCMASTERXPRT *xprt)
 236  237  {
 237  238  }
 238  239  
 239  240  static void
 240  241  svc_clts_kclone_xprt(SVCXPRT *src_xprt, SVCXPRT *dst_xprt)
 241  242  {
 242  243          struct udp_data *ud_src =
 243  244              (struct udp_data *)src_xprt->xp_p2buf;
 244  245          struct udp_data *ud_dst =
 245  246              (struct udp_data *)dst_xprt->xp_p2buf;
 246  247  
 247  248          if (ud_src->ud_resp)
 248  249                  ud_dst->ud_resp = dupb(ud_src->ud_resp);
 249  250  
 250  251  }
 251  252  
 252  253  static void
 253  254  svc_clts_ktattrs(SVCXPRT *clone_xprt, int attrflag, void **tattr)
 254  255  {
 255  256          *tattr = NULL;
 256  257  
 257  258          switch (attrflag) {
 258  259          case SVC_TATTR_ADDRMASK:
 259  260                  *tattr = (void *)&clone_xprt->xp_master->xp_addrmask;
 260  261          }
 261  262  }
 262  263  
 263  264  /*
 264  265   * Receive rpc requests.
 265  266   * Pulls a request in off the socket, checks if the packet is intact,
 266  267   * and deserializes the call packet.
 267  268   */
 268  269  static bool_t
 269  270  svc_clts_krecv(SVCXPRT *clone_xprt, mblk_t *mp, struct rpc_msg *msg)
 270  271  {
 271  272          /* LINTED pointer alignment */
 272  273          struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf;
 273  274          XDR *xdrs = &clone_xprt->xp_xdrin;
 274  275          struct rpc_clts_server *stats = CLONE2STATS(clone_xprt);
 275  276          union T_primitives *pptr;
 276  277          int hdrsz;
 277  278          cred_t *cr;
 278  279  
 279  280          TRACE_0(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_START,
 280  281              "svc_clts_krecv_start:");
 281  282  
 282  283          RSSTAT_INCR(stats, rscalls);
 283  284  
 284  285          /*
 285  286           * The incoming request should start with an M_PROTO message.
 286  287           */
 287  288          if (mp->b_datap->db_type != M_PROTO) {
 288  289                  goto bad;
 289  290          }
 290  291  
 291  292          /*
 292  293           * The incoming request should be an T_UNITDTA_IND.  There
 293  294           * might be other messages coming up the stream, but we can
 294  295           * ignore them.
 295  296           */
 296  297          pptr = (union T_primitives *)mp->b_rptr;
 297  298          if (pptr->type != T_UNITDATA_IND) {
 298  299                  goto bad;
 299  300          }
 300  301          /*
 301  302           * Do some checking to make sure that the header at least looks okay.
 302  303           */
 303  304          hdrsz = (int)(mp->b_wptr - mp->b_rptr);
 304  305          if (hdrsz < TUNITDATAINDSZ ||
 305  306              hdrsz < (pptr->unitdata_ind.OPT_offset +
 306  307              pptr->unitdata_ind.OPT_length) ||
 307  308              hdrsz < (pptr->unitdata_ind.SRC_offset +
 308  309              pptr->unitdata_ind.SRC_length)) {
 309  310                  goto bad;
 310  311          }
 311  312  
 312  313          /*
 313  314           * Make sure that the transport provided a usable address.
 314  315           */
 315  316          if (pptr->unitdata_ind.SRC_length <= 0) {
 316  317                  goto bad;
 317  318          }
 318  319          /*
 319  320           * Point the remote transport address in the service_transport
 320  321           * handle at the address in the request.
 321  322           */
 322  323          clone_xprt->xp_rtaddr.buf = (char *)mp->b_rptr +
 323  324              pptr->unitdata_ind.SRC_offset;
 324  325          clone_xprt->xp_rtaddr.len = pptr->unitdata_ind.SRC_length;
 325  326  
 326  327          /*
 327  328           * Copy the local transport address in the service_transport
 328  329           * handle at the address in the request. We will have only
 329  330           * the local IP address in options.
 330  331           */
 331  332          ((sin_t *)(clone_xprt->xp_lcladdr.buf))->sin_family = AF_UNSPEC;
 332  333          if (pptr->unitdata_ind.OPT_length && pptr->unitdata_ind.OPT_offset) {
 333  334                  char *dstopt = (char *)mp->b_rptr +
 334  335                      pptr->unitdata_ind.OPT_offset;
 335  336                  struct T_opthdr *toh = (struct T_opthdr *)dstopt;
 336  337  
 337  338                  if (toh->level == IPPROTO_IPV6 && toh->status == 0 &&
 338  339                      toh->name == IPV6_PKTINFO) {
 339  340                          struct in6_pktinfo *pkti;
 340  341  
 341  342                          dstopt += sizeof (struct T_opthdr);
 342  343                          pkti = (struct in6_pktinfo *)dstopt;
 343  344                          ((sin6_t *)(clone_xprt->xp_lcladdr.buf))->sin6_addr
 344  345                              = pkti->ipi6_addr;
 345  346                          ((sin6_t *)(clone_xprt->xp_lcladdr.buf))->sin6_family
 346  347                              = AF_INET6;
 347  348                  } else if (toh->level == IPPROTO_IP && toh->status == 0 &&
 348  349                      toh->name == IP_RECVDSTADDR) {
 349  350                          dstopt += sizeof (struct T_opthdr);
 350  351                          ((sin_t *)(clone_xprt->xp_lcladdr.buf))->sin_addr
 351  352                              = *(struct in_addr *)dstopt;
 352  353                          ((sin_t *)(clone_xprt->xp_lcladdr.buf))->sin_family
 353  354                              = AF_INET;
 354  355                  }
 355  356          }
 356  357  
 357  358          /*
 358  359           * Save the first mblk which contains the T_unidata_ind in
 359  360           * ud_resp.  It will be used to generate the T_unitdata_req
 360  361           * during the reply.
 361  362           * We reuse any options in the T_unitdata_ind for the T_unitdata_req
 362  363           * since we must pass any SCM_UCRED across in order for TX to
 363  364           * work. We also make sure any cred_t is carried across.
 364  365           */
 365  366          if (ud->ud_resp) {
 366  367                  if (ud->ud_resp->b_cont != NULL) {
 367  368                          cmn_err(CE_WARN, "svc_clts_krecv: ud_resp %p, "
 368  369                              "b_cont %p", (void *)ud->ud_resp,
 369  370                              (void *)ud->ud_resp->b_cont);
 370  371                  }
 371  372                  freeb(ud->ud_resp);
 372  373          }
 373  374          /* Move any cred_t to the first mblk in the message */
 374  375          cr = msg_getcred(mp, NULL);
 375  376          if (cr != NULL)
 376  377                  mblk_setcred(mp, cr, NOPID);
 377  378  
 378  379          ud->ud_resp = mp;
 379  380          mp = mp->b_cont;
 380  381          ud->ud_resp->b_cont = NULL;
 381  382  
 382  383          xdrmblk_init(xdrs, mp, XDR_DECODE, 0);
 383  384  
 384  385          TRACE_0(TR_FAC_KRPC, TR_XDR_CALLMSG_START,
 385  386              "xdr_callmsg_start:");
 386  387          if (! xdr_callmsg(xdrs, msg)) {
 387  388                  XDR_DESTROY(xdrs);
 388  389                  TRACE_1(TR_FAC_KRPC, TR_XDR_CALLMSG_END,
 389  390                      "xdr_callmsg_end:(%S)", "bad");
 390  391                  RSSTAT_INCR(stats, rsxdrcall);
 391  392                  goto bad;
 392  393          }
 393  394          TRACE_1(TR_FAC_KRPC, TR_XDR_CALLMSG_END,
 394  395              "xdr_callmsg_end:(%S)", "good");
 395  396  
 396  397          clone_xprt->xp_xid = msg->rm_xid;
 397  398          ud->ud_inmp = mp;
 398  399  
 399  400          TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_END,
 400  401              "svc_clts_krecv_end:(%S)", "good");
 401  402          return (TRUE);
 402  403  
 403  404  bad:
 404  405          freemsg(mp);
 405  406          if (ud->ud_resp) {
 406  407                  /*
 407  408                   * There should not be any left over results buffer.
 408  409                   */
 409  410                  ASSERT(ud->ud_resp->b_cont == NULL);
 410  411                  freeb(ud->ud_resp);
 411  412                  ud->ud_resp = NULL;
 412  413          }
 413  414  
 414  415          RSSTAT_INCR(stats, rsbadcalls);
 415  416          TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KRECV_END,
 416  417              "svc_clts_krecv_end:(%S)", "bad");
 417  418          return (FALSE);
 418  419  }
 419  420  
 420  421  /*
 421  422   * Send rpc reply.
 422  423   * Serialize the reply packet into the output buffer then
 423  424   * call t_ksndudata to send it.
 424  425   */
 425  426  static bool_t
 426  427  svc_clts_ksend(SVCXPRT *clone_xprt, struct rpc_msg *msg)
 427  428  {
 428  429          /* LINTED pointer alignment */
 429  430          struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf;
 430  431          XDR *xdrs = &clone_xprt->xp_xdrout;
 431  432          int stat = FALSE;
 432  433          mblk_t *mp;
 433  434          int msgsz;
 434  435          struct T_unitdata_req *udreq;
 435  436          xdrproc_t xdr_results;
 436  437          caddr_t xdr_location;
 437  438          bool_t has_args;
 438  439  
 439  440          TRACE_0(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_START,
 440  441              "svc_clts_ksend_start:");
 441  442  
 442  443          ASSERT(ud->ud_resp != NULL);
 443  444  
 444  445          /*
 445  446           * If there is a result procedure specified in the reply message,
 446  447           * it will be processed in the xdr_replymsg and SVCAUTH_WRAP.
 447  448           * We need to make sure it won't be processed twice, so we null
 448  449           * it for xdr_replymsg here.
 449  450           */
 450  451          has_args = FALSE;
 451  452          if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
 452  453              msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
 453  454                  if ((xdr_results = msg->acpted_rply.ar_results.proc) != NULL) {
 454  455                          has_args = TRUE;
 455  456                          xdr_location = msg->acpted_rply.ar_results.where;
 456  457                          msg->acpted_rply.ar_results.proc = xdr_void;
 457  458                          msg->acpted_rply.ar_results.where = NULL;
 458  459                  }
 459  460          }
 460  461  
 461  462          if (ud->ud_resp->b_cont == NULL) {
 462  463                  /*
 463  464                   * Allocate an initial mblk for the response data.
 464  465                   */
 465  466                  while ((mp = allocb(UD_INITSIZE, BPRI_LO)) == NULL) {
 466  467                          if (strwaitbuf(UD_INITSIZE, BPRI_LO)) {
 467  468                                  TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_END,
 468  469                                      "svc_clts_ksend_end:(%S)", "strwaitbuf");
 469  470                                  return (FALSE);
 470  471                          }
 471  472                  }
 472  473  
 473  474                  /*
 474  475                   * Initialize the XDR encode stream.  Additional mblks
 475  476                   * will be allocated if necessary.  They will be UD_MAXSIZE
 476  477                   * sized.
 477  478                   */
 478  479                  xdrmblk_init(xdrs, mp, XDR_ENCODE, UD_MAXSIZE);
 479  480  
 480  481                  /*
 481  482                   * Leave some space for protocol headers.
 482  483                   */
 483  484                  (void) XDR_SETPOS(xdrs, 512);
 484  485                  mp->b_rptr += 512;
 485  486  
 486  487                  msg->rm_xid = clone_xprt->xp_xid;
 487  488  
 488  489                  ud->ud_resp->b_cont = mp;
 489  490  
 490  491                  TRACE_0(TR_FAC_KRPC, TR_XDR_REPLYMSG_START,
 491  492                      "xdr_replymsg_start:");
 492  493                  if (!(xdr_replymsg(xdrs, msg) &&
 493  494                      (!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs,
 494  495                      xdr_results, xdr_location)))) {
 495  496                          XDR_DESTROY(xdrs);
 496  497                          TRACE_1(TR_FAC_KRPC, TR_XDR_REPLYMSG_END,
 497  498                              "xdr_replymsg_end:(%S)", "bad");
 498  499                          RPCLOG0(1, "xdr_replymsg/SVCAUTH_WRAP failed\n");
 499  500                          goto out;
 500  501                  }
 501  502                  TRACE_1(TR_FAC_KRPC, TR_XDR_REPLYMSG_END,
 502  503                      "xdr_replymsg_end:(%S)", "good");
 503  504  
 504  505          } else if (!(xdr_replymsg_body(xdrs, msg) &&
 505  506              (!has_args || SVCAUTH_WRAP(&clone_xprt->xp_auth, xdrs,
 506  507              xdr_results, xdr_location)))) {
 507  508                  XDR_DESTROY(xdrs);
 508  509                  RPCLOG0(1, "xdr_replymsg_body/SVCAUTH_WRAP failed\n");
 509  510                  goto out;
 510  511          }
 511  512  
 512  513          XDR_DESTROY(xdrs);
 513  514  
 514  515          msgsz = (int)xmsgsize(ud->ud_resp->b_cont);
 515  516  
 516  517          if (msgsz <= 0 || (clone_xprt->xp_msg_size != -1 &&
 517  518              msgsz > clone_xprt->xp_msg_size)) {
 518  519  #ifdef  DEBUG
 519  520                  cmn_err(CE_NOTE,
 520  521  "KRPC: server response message of %d bytes; transport limits are [0, %d]",
 521  522                      msgsz, clone_xprt->xp_msg_size);
 522  523  #endif
 523  524                  goto out;
 524  525          }
 525  526  
 526  527          /*
 527  528           * Construct the T_unitdata_req.  We take advantage of the fact that
 528  529           * T_unitdata_ind looks just like T_unitdata_req, except for the
 529  530           * primitive type.  Reusing it means we preserve the SCM_UCRED, and
 530  531           * we must preserve it for TX to work.
 531  532           *
 532  533           * This has the side effect that we can also pass certain receive-side
 533  534           * options like IPV6_PKTINFO back down the send side.  This implies
 534  535           * that we can not ASSERT on a non-NULL db_credp when we have send-side
 535  536           * options in UDP.
 536  537           */
 537  538          ASSERT(MBLKL(ud->ud_resp) >= TUNITDATAREQSZ);
 538  539          udreq = (struct T_unitdata_req *)ud->ud_resp->b_rptr;
 539  540          ASSERT(udreq->PRIM_type == T_UNITDATA_IND);
 540  541          udreq->PRIM_type = T_UNITDATA_REQ;
 541  542  
 542  543          /*
 543  544           * If the local IPv4 transport address is known use it as a source
 544  545           * address for the outgoing UDP packet.
 545  546           */
 546  547          if (((sin_t *)(clone_xprt->xp_lcladdr.buf))->sin_family == AF_INET) {
 547  548                  struct T_opthdr *opthdr;
 548  549                  in_pktinfo_t *pktinfo;
 549  550                  size_t size;
 550  551  
 551  552                  if (udreq->DEST_length == 0)
 552  553                          udreq->OPT_offset = _TPI_ALIGN_TOPT(TUNITDATAREQSZ);
 553  554                  else
 554  555                          udreq->OPT_offset = _TPI_ALIGN_TOPT(udreq->DEST_offset +
 555  556                              udreq->DEST_length);
 556  557  
 557  558                  udreq->OPT_length = sizeof (struct T_opthdr) +
 558  559                      sizeof (in_pktinfo_t);
 559  560  
 560  561                  size = udreq->OPT_length + udreq->OPT_offset;
 561  562  
 562  563                  /* make sure we have enough space for the option data */
 563  564                  mp = reallocb(ud->ud_resp, size, 1);
 564  565                  if (mp == NULL)
 565  566                          goto out;
 566  567                  ud->ud_resp = mp;
 567  568                  udreq = (struct T_unitdata_req *)mp->b_rptr;
 568  569  
 569  570                  /* set desired option header */
 570  571                  opthdr = (struct T_opthdr *)(mp->b_rptr + udreq->OPT_offset);
 571  572                  opthdr->len = udreq->OPT_length;
 572  573                  opthdr->level = IPPROTO_IP;
 573  574                  opthdr->name = IP_PKTINFO;
 574  575  
 575  576                  /*
 576  577                   * 1. set source IP of outbound packet
 577  578                   * 2. value '0' for index means IP layer uses this as source
 578  579                   *    address
 579  580                   */
 580  581                  pktinfo = (in_pktinfo_t *)(opthdr + 1);
 581  582                  (void) memset(pktinfo, 0, sizeof (in_pktinfo_t));
 582  583                  pktinfo->ipi_spec_dst.s_addr =
 583  584                      ((sin_t *)(clone_xprt->xp_lcladdr.buf))->sin_addr.s_addr;
 584  585                  pktinfo->ipi_ifindex = 0;
 585  586  
 586  587                  /* adjust the end of active data */
 587  588                  mp->b_wptr = mp->b_rptr + size;
 588  589          }
 589  590  
 590  591          put(clone_xprt->xp_wq, ud->ud_resp);
 591  592          stat = TRUE;
 592  593          ud->ud_resp = NULL;
 593  594  
 594  595  out:
 595  596          if (stat == FALSE) {
 596  597                  freemsg(ud->ud_resp);
 597  598                  ud->ud_resp = NULL;
 598  599          }
 599  600  
 600  601          /*
 601  602           * This is completely disgusting.  If public is set it is
 602  603           * a pointer to a structure whose first field is the address
 603  604           * of the function to free that structure and any related
 604  605           * stuff.  (see rrokfree in nfs_xdr.c).
 605  606           */
 606  607          if (xdrs->x_public) {
 607  608                  /* LINTED pointer alignment */
 608  609                  (**((int (**)())xdrs->x_public))(xdrs->x_public);
 609  610          }
 610  611  
 611  612          TRACE_1(TR_FAC_KRPC, TR_SVC_CLTS_KSEND_END,
 612  613              "svc_clts_ksend_end:(%S)", "done");
 613  614          return (stat);
 614  615  }
 615  616  
 616  617  /*
 617  618   * Deserialize arguments.
 618  619   */
 619  620  static bool_t
 620  621  svc_clts_kgetargs(SVCXPRT *clone_xprt, xdrproc_t xdr_args,
 621  622      caddr_t args_ptr)
 622  623  {
 623  624  
 624  625          /* LINTED pointer alignment */
 625  626          return (SVCAUTH_UNWRAP(&clone_xprt->xp_auth, &clone_xprt->xp_xdrin,
 626  627              xdr_args, args_ptr));
 627  628  
 628  629  }
 629  630  
 630  631  static bool_t
 631  632  svc_clts_kfreeargs(SVCXPRT *clone_xprt, xdrproc_t xdr_args,
 632  633      caddr_t args_ptr)
 633  634  {
 634  635          /* LINTED pointer alignment */
 635  636          struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf;
 636  637          XDR *xdrs = &clone_xprt->xp_xdrin;
 637  638          bool_t retval;
 638  639  
 639  640          if (args_ptr) {
 640  641                  xdrs->x_op = XDR_FREE;
 641  642                  retval = (*xdr_args)(xdrs, args_ptr);
 642  643          } else
 643  644                  retval = TRUE;
 644  645  
 645  646          XDR_DESTROY(xdrs);
 646  647  
 647  648          if (ud->ud_inmp) {
 648  649                  freemsg(ud->ud_inmp);
 649  650                  ud->ud_inmp = NULL;
 650  651          }
 651  652  
 652  653          return (retval);
 653  654  }
 654  655  
 655  656  static int32_t *
 656  657  svc_clts_kgetres(SVCXPRT *clone_xprt, int size)
 657  658  {
 658  659          /* LINTED pointer alignment */
 659  660          struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf;
 660  661          XDR *xdrs = &clone_xprt->xp_xdrout;
 661  662          mblk_t *mp;
 662  663          int32_t *buf;
 663  664          struct rpc_msg rply;
 664  665  
 665  666          /*
 666  667           * Allocate an initial mblk for the response data.
 667  668           */
 668  669          while ((mp = allocb(UD_INITSIZE, BPRI_LO)) == NULL) {
 669  670                  if (strwaitbuf(UD_INITSIZE, BPRI_LO)) {
 670  671                          return (NULL);
 671  672                  }
 672  673          }
 673  674  
 674  675          mp->b_cont = NULL;
 675  676  
 676  677          /*
 677  678           * Initialize the XDR encode stream.  Additional mblks
 678  679           * will be allocated if necessary.  They will be UD_MAXSIZE
 679  680           * sized.
 680  681           */
 681  682          xdrmblk_init(xdrs, mp, XDR_ENCODE, UD_MAXSIZE);
 682  683  
 683  684          /*
 684  685           * Leave some space for protocol headers.
 685  686           */
 686  687          (void) XDR_SETPOS(xdrs, 512);
 687  688          mp->b_rptr += 512;
 688  689  
 689  690          /*
 690  691           * Assume a successful RPC since most of them are.
 691  692           */
 692  693          rply.rm_xid = clone_xprt->xp_xid;
 693  694          rply.rm_direction = REPLY;
 694  695          rply.rm_reply.rp_stat = MSG_ACCEPTED;
 695  696          rply.acpted_rply.ar_verf = clone_xprt->xp_verf;
 696  697          rply.acpted_rply.ar_stat = SUCCESS;
 697  698  
 698  699          if (!xdr_replymsg_hdr(xdrs, &rply)) {
 699  700                  XDR_DESTROY(xdrs);
 700  701                  freeb(mp);
 701  702                  return (NULL);
 702  703          }
 703  704  
 704  705          buf = XDR_INLINE(xdrs, size);
 705  706  
 706  707          if (buf == NULL) {
 707  708                  XDR_DESTROY(xdrs);
 708  709                  freeb(mp);
 709  710          } else {
 710  711                  ud->ud_resp->b_cont = mp;
 711  712          }
 712  713  
 713  714          return (buf);
 714  715  }
 715  716  
 716  717  static void
 717  718  svc_clts_kfreeres(SVCXPRT *clone_xprt)
 718  719  {
 719  720          /* LINTED pointer alignment */
 720  721          struct udp_data *ud = (struct udp_data *)clone_xprt->xp_p2buf;
 721  722  
 722  723          if (ud->ud_resp == NULL || ud->ud_resp->b_cont == NULL)
 723  724                  return;
 724  725  
 725  726          XDR_DESTROY(&clone_xprt->xp_xdrout);
 726  727  
 727  728          /*
 728  729           * SVC_FREERES() is called whenever the server decides not to
 729  730           * send normal reply. Thus, we expect only one mblk to be allocated,
 730  731           * because we have not attempted any XDR encoding.
 731  732           * If we do any XDR encoding and we get an error, then SVC_REPLY()
 732  733           * will freemsg(ud->ud_resp);
 733  734           */
 734  735          ASSERT(ud->ud_resp->b_cont->b_cont == NULL);
 735  736          freeb(ud->ud_resp->b_cont);
 736  737          ud->ud_resp->b_cont = NULL;
 737  738  }
 738  739  
 739  740  /*
  
    | 
      ↓ open down ↓ | 
    705 lines elided | 
    
      ↑ open up ↑ | 
  
 740  741   * the dup cacheing routines below provide a cache of non-failure
 741  742   * transaction id's.  rpc service routines can use this to detect
 742  743   * retransmissions and re-send a non-failure response.
 743  744   */
 744  745  
 745  746  /*
 746  747   * MAXDUPREQS is the number of cached items.  It should be adjusted
 747  748   * to the service load so that there is likely to be a response entry
 748  749   * when the first retransmission comes in.
 749  750   */
 750      -#define MAXDUPREQS      1024
      751 +#define MAXDUPREQS      8192
 751  752  
 752  753  /*
 753  754   * This should be appropriately scaled to MAXDUPREQS.
 754  755   */
 755      -#define DRHASHSZ        257
      756 +#define DRHASHSZ        2053
 756  757  
 757  758  #if ((DRHASHSZ & (DRHASHSZ - 1)) == 0)
 758  759  #define XIDHASH(xid)    ((xid) & (DRHASHSZ - 1))
 759  760  #else
 760  761  #define XIDHASH(xid)    ((xid) % DRHASHSZ)
 761  762  #endif
 762  763  #define DRHASH(dr)      XIDHASH((dr)->dr_xid)
 763  764  #define REQTOXID(req)   ((req)->rq_xprt->xp_xid)
 764  765  
 765  766  static int      ndupreqs = 0;
 766  767  int     maxdupreqs = MAXDUPREQS;
 767  768  static kmutex_t dupreq_lock;
 768  769  static struct dupreq *drhashtbl[DRHASHSZ];
 769  770  static int      drhashstat[DRHASHSZ];
 770  771  
 771  772  static void unhash(struct dupreq *);
 772  773  
 773  774  /*
 774  775   * drmru points to the head of a circular linked list in lru order.
 775  776   * drmru->dr_next == drlru
 776  777   */
 777  778  struct dupreq *drmru;
 778  779  
 779  780  /*
 780  781   * PSARC 2003/523 Contract Private Interface
 781  782   * svc_clts_kdup
 782  783   * Changes must be reviewed by Solaris File Sharing
 783  784   * Changes must be communicated to contract-2003-523@sun.com
 784  785   *
 785  786   * svc_clts_kdup searches the request cache and returns 0 if the
 786  787   * request is not found in the cache.  If it is found, then it
 787  788   * returns the state of the request (in progress or done) and
 788  789   * the status or attributes that were part of the original reply.
 789  790   *
 790  791   * If DUP_DONE (there is a duplicate) svc_clts_kdup copies over the
 791  792   * value of the response. In that case, also return in *dupcachedp
 792  793   * whether the response free routine is cached in the dupreq - in which case
 793  794   * the caller should not be freeing it, because it will be done later
 794  795   * in the svc_clts_kdup code when the dupreq is reused.
 795  796   */
 796  797  static int
 797  798  svc_clts_kdup(struct svc_req *req, caddr_t res, int size, struct dupreq **drpp,
 798  799          bool_t *dupcachedp)
 799  800  {
 800  801          struct rpc_clts_server *stats = CLONE2STATS(req->rq_xprt);
 801  802          struct dupreq *dr;
 802  803          uint32_t xid;
 803  804          uint32_t drhash;
 804  805          int status;
 805  806  
 806  807          xid = REQTOXID(req);
 807  808          mutex_enter(&dupreq_lock);
 808  809          RSSTAT_INCR(stats, rsdupchecks);
 809  810          /*
 810  811           * Check to see whether an entry already exists in the cache.
 811  812           */
 812  813          dr = drhashtbl[XIDHASH(xid)];
 813  814          while (dr != NULL) {
 814  815                  if (dr->dr_xid == xid &&
 815  816                      dr->dr_proc == req->rq_proc &&
 816  817                      dr->dr_prog == req->rq_prog &&
 817  818                      dr->dr_vers == req->rq_vers &&
 818  819                      dr->dr_addr.len == req->rq_xprt->xp_rtaddr.len &&
 819  820                      bcmp(dr->dr_addr.buf, req->rq_xprt->xp_rtaddr.buf,
 820  821                      dr->dr_addr.len) == 0) {
 821  822                          status = dr->dr_status;
 822  823                          if (status == DUP_DONE) {
 823  824                                  bcopy(dr->dr_resp.buf, res, size);
 824  825                                  if (dupcachedp != NULL)
 825  826                                          *dupcachedp = (dr->dr_resfree != NULL);
 826  827                          } else {
 827  828                                  dr->dr_status = DUP_INPROGRESS;
 828  829                                  *drpp = dr;
 829  830                          }
 830  831                          RSSTAT_INCR(stats, rsdupreqs);
 831  832                          mutex_exit(&dupreq_lock);
 832  833                          return (status);
 833  834                  }
 834  835                  dr = dr->dr_chain;
 835  836          }
 836  837  
 837  838          /*
 838  839           * There wasn't an entry, either allocate a new one or recycle
 839  840           * an old one.
 840  841           */
 841  842          if (ndupreqs < maxdupreqs) {
 842  843                  dr = kmem_alloc(sizeof (*dr), KM_NOSLEEP);
 843  844                  if (dr == NULL) {
 844  845                          mutex_exit(&dupreq_lock);
 845  846                          return (DUP_ERROR);
 846  847                  }
 847  848                  dr->dr_resp.buf = NULL;
 848  849                  dr->dr_resp.maxlen = 0;
 849  850                  dr->dr_addr.buf = NULL;
 850  851                  dr->dr_addr.maxlen = 0;
 851  852                  if (drmru) {
 852  853                          dr->dr_next = drmru->dr_next;
 853  854                          drmru->dr_next = dr;
 854  855                  } else {
 855  856                          dr->dr_next = dr;
 856  857                  }
 857  858                  ndupreqs++;
 858  859          } else {
 859  860                  dr = drmru->dr_next;
 860  861                  while (dr->dr_status == DUP_INPROGRESS) {
 861  862                          dr = dr->dr_next;
 862  863                          if (dr == drmru->dr_next) {
 863  864                                  cmn_err(CE_WARN, "svc_clts_kdup no slots free");
 864  865                                  mutex_exit(&dupreq_lock);
 865  866                                  return (DUP_ERROR);
 866  867                          }
 867  868                  }
 868  869                  unhash(dr);
 869  870                  if (dr->dr_resfree) {
 870  871                          (*dr->dr_resfree)(dr->dr_resp.buf);
 871  872                  }
 872  873          }
 873  874          dr->dr_resfree = NULL;
 874  875          drmru = dr;
 875  876  
 876  877          dr->dr_xid = REQTOXID(req);
 877  878          dr->dr_prog = req->rq_prog;
 878  879          dr->dr_vers = req->rq_vers;
 879  880          dr->dr_proc = req->rq_proc;
 880  881          if (dr->dr_addr.maxlen < req->rq_xprt->xp_rtaddr.len) {
 881  882                  if (dr->dr_addr.buf != NULL)
 882  883                          kmem_free(dr->dr_addr.buf, dr->dr_addr.maxlen);
 883  884                  dr->dr_addr.maxlen = req->rq_xprt->xp_rtaddr.len;
 884  885                  dr->dr_addr.buf = kmem_alloc(dr->dr_addr.maxlen,
 885  886                      KM_NOSLEEP);
 886  887                  if (dr->dr_addr.buf == NULL) {
 887  888                          dr->dr_addr.maxlen = 0;
 888  889                          dr->dr_status = DUP_DROP;
 889  890                          mutex_exit(&dupreq_lock);
 890  891                          return (DUP_ERROR);
 891  892                  }
 892  893          }
 893  894          dr->dr_addr.len = req->rq_xprt->xp_rtaddr.len;
 894  895          bcopy(req->rq_xprt->xp_rtaddr.buf, dr->dr_addr.buf, dr->dr_addr.len);
 895  896          if (dr->dr_resp.maxlen < size) {
 896  897                  if (dr->dr_resp.buf != NULL)
 897  898                          kmem_free(dr->dr_resp.buf, dr->dr_resp.maxlen);
 898  899                  dr->dr_resp.maxlen = (unsigned int)size;
 899  900                  dr->dr_resp.buf = kmem_alloc(size, KM_NOSLEEP);
 900  901                  if (dr->dr_resp.buf == NULL) {
 901  902                          dr->dr_resp.maxlen = 0;
 902  903                          dr->dr_status = DUP_DROP;
 903  904                          mutex_exit(&dupreq_lock);
 904  905                          return (DUP_ERROR);
 905  906                  }
 906  907          }
 907  908          dr->dr_status = DUP_INPROGRESS;
 908  909  
 909  910          drhash = (uint32_t)DRHASH(dr);
 910  911          dr->dr_chain = drhashtbl[drhash];
 911  912          drhashtbl[drhash] = dr;
 912  913          drhashstat[drhash]++;
 913  914          mutex_exit(&dupreq_lock);
 914  915          *drpp = dr;
 915  916          return (DUP_NEW);
 916  917  }
 917  918  
 918  919  /*
 919  920   * PSARC 2003/523 Contract Private Interface
 920  921   * svc_clts_kdupdone
 921  922   * Changes must be reviewed by Solaris File Sharing
 922  923   * Changes must be communicated to contract-2003-523@sun.com
 923  924   *
 924  925   * svc_clts_kdupdone marks the request done (DUP_DONE or DUP_DROP)
 925  926   * and stores the response.
 926  927   */
 927  928  static void
 928  929  svc_clts_kdupdone(struct dupreq *dr, caddr_t res, void (*dis_resfree)(),
 929  930          int size, int status)
 930  931  {
 931  932  
 932  933          ASSERT(dr->dr_resfree == NULL);
 933  934          if (status == DUP_DONE) {
 934  935                  bcopy(res, dr->dr_resp.buf, size);
 935  936                  dr->dr_resfree = dis_resfree;
 936  937          }
 937  938          dr->dr_status = status;
 938  939  }
 939  940  
 940  941  /*
 941  942   * This routine expects that the mutex, dupreq_lock, is already held.
 942  943   */
 943  944  static void
 944  945  unhash(struct dupreq *dr)
 945  946  {
 946  947          struct dupreq *drt;
 947  948          struct dupreq *drtprev = NULL;
 948  949          uint32_t drhash;
 949  950  
 950  951          ASSERT(MUTEX_HELD(&dupreq_lock));
 951  952  
 952  953          drhash = (uint32_t)DRHASH(dr);
 953  954          drt = drhashtbl[drhash];
 954  955          while (drt != NULL) {
 955  956                  if (drt == dr) {
 956  957                          drhashstat[drhash]--;
 957  958                          if (drtprev == NULL) {
 958  959                                  drhashtbl[drhash] = drt->dr_chain;
 959  960                          } else {
 960  961                                  drtprev->dr_chain = drt->dr_chain;
 961  962                          }
 962  963                          return;
 963  964                  }
 964  965                  drtprev = drt;
 965  966                  drt = drt->dr_chain;
 966  967          }
 967  968  }
 968  969  
 969  970  void
 970  971  svc_clts_stats_init(zoneid_t zoneid, struct rpc_clts_server **statsp)
 971  972  {
 972  973          kstat_t *ksp;
 973  974          kstat_named_t *knp;
 974  975  
 975  976          knp = rpcstat_zone_init_common(zoneid, "unix", "rpc_clts_server",
 976  977              (const kstat_named_t *)&clts_rsstat_tmpl,
 977  978              sizeof (clts_rsstat_tmpl));
 978  979          /*
 979  980           * Backwards compatibility for old kstat clients
 980  981           */
 981  982          ksp = kstat_create_zone("unix", 0, "rpc_server", "rpc",
 982  983              KSTAT_TYPE_NAMED, clts_rsstat_ndata,
 983  984              KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE, zoneid);
 984  985          if (ksp) {
 985  986                  ksp->ks_data = knp;
 986  987                  kstat_install(ksp);
 987  988          }
 988  989          *statsp = (struct rpc_clts_server *)knp;
 989  990  }
 990  991  
 991  992  void
 992  993  svc_clts_stats_fini(zoneid_t zoneid, struct rpc_clts_server **statsp)
 993  994  {
 994  995          rpcstat_zone_fini_common(zoneid, "unix", "rpc_clts_server");
 995  996          kstat_delete_byname_zone("unix", 0, "rpc_server", zoneid);
 996  997          kmem_free(*statsp, sizeof (clts_rsstat_tmpl));
 997  998  }
 998  999  
 999 1000  void
1000 1001  svc_clts_init()
1001 1002  {
1002 1003          /*
1003 1004           * Check to make sure that the clts private data will fit into
1004 1005           * the stack buffer allocated by svc_run.  The compiler should
1005 1006           * remove this check, but it's a safety net if the udp_data
1006 1007           * structure ever changes.
1007 1008           */
1008 1009          /*CONSTANTCONDITION*/
1009 1010          ASSERT(sizeof (struct udp_data) <= SVC_P2LEN);
1010 1011  
1011 1012          mutex_init(&dupreq_lock, NULL, MUTEX_DEFAULT, NULL);
1012 1013  }
  
    | 
      ↓ open down ↓ | 
    247 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX