3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   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 2015 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
  25  * Copyright (c) 2013 by Delphix. All rights reserved.
  26  */
  27 
  28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  29 /* All Rights Reserved */
  30 
  31 #include <sys/param.h>
  32 #include <sys/types.h>
  33 #include <sys/systm.h>
  34 #include <sys/cred.h>
  35 #include <sys/buf.h>
  36 #include <sys/vfs.h>
  37 #include <sys/vnode.h>
  38 #include <sys/uio.h>
  39 #include <sys/errno.h>
  40 #include <sys/sysmacros.h>
  41 #include <sys/statvfs.h>
  42 #include <sys/kmem.h>
  43 #include <sys/dirent.h>
  44 #include <sys/cmn_err.h>
  45 #include <sys/debug.h>
  46 #include <sys/systeminfo.h>
  47 #include <sys/flock.h>
  48 #include <sys/nbmlock.h>
  49 #include <sys/policy.h>
  50 #include <sys/sdt.h>
  51 
  52 #include <rpc/types.h>
  53 #include <rpc/auth.h>
  54 #include <rpc/svc.h>
  55 #include <rpc/rpc_rdma.h>
  56 
  57 #include <nfs/nfs.h>
  58 #include <nfs/export.h>
  59 #include <nfs/nfs_cmd.h>
  60 
  61 #include <sys/strsubr.h>
  62 #include <sys/tsol/label.h>
  63 #include <sys/tsol/tndb.h>
  64 
  65 #include <sys/zone.h>
  66 
  67 #include <inet/ip.h>
  68 #include <inet/ip6.h>
  69 
  70 /*
  71  * These are the interface routines for the server side of the
  72  * Network File System.  See the NFS version 3 protocol specification
  73  * for a description of this interface.
  74  */
  75 
  76 static writeverf3 write3verf;
  77 
  78 static int      sattr3_to_vattr(sattr3 *, struct vattr *);
  79 static int      vattr_to_fattr3(struct vattr *, fattr3 *);
  80 static int      vattr_to_wcc_attr(struct vattr *, wcc_attr *);
  81 static void     vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
  82 static void     vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
  83 static int      rdma_setup_read_data3(READ3args *, READ3resok *);
  84 
  85 extern int nfs_loaned_buffers;
  86 
  87 u_longlong_t nfs3_srv_caller_id;
  88 
  89 /* ARGSUSED */
  90 void
  91 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
  92     struct svc_req *req, cred_t *cr, bool_t ro)
  93 {
  94         int error;
  95         vnode_t *vp;
  96         struct vattr va;
  97 
  98         vp = nfs3_fhtovp(&args->object, exi);
  99 
 100         DTRACE_NFSV3_4(op__getattr__start, struct svc_req *, req,
 101             cred_t *, cr, vnode_t *, vp, GETATTR3args *, args);
 102 
 103         if (vp == NULL) {
 104                 error = ESTALE;
 105                 goto out;
 106         }
 107 
 108         va.va_mask = AT_ALL;
 109         error = rfs4_delegated_getattr(vp, &va, 0, cr);
 110 
 111         if (!error) {
 112                 /* Lie about the object type for a referral */
 113                 if (vn_is_nfs_reparse(vp, cr))
 114                         va.va_type = VLNK;
 115 
 116                 /* overflow error if time or size is out of range */
 117                 error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
 118                 if (error)
 119                         goto out;
 120                 resp->status = NFS3_OK;
 121 
 122                 DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
 123                     cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
 124 
 125                 VN_RELE(vp);
 126 
 127                 return;
 128         }
 129 
 130 out:
 131         if (curthread->t_flag & T_WOULDBLOCK) {
 132                 curthread->t_flag &= ~T_WOULDBLOCK;
 133                 resp->status = NFS3ERR_JUKEBOX;
 134         } else
 135                 resp->status = puterrno3(error);
 136 
 137         DTRACE_NFSV3_4(op__getattr__done, struct svc_req *, req,
 138             cred_t *, cr, vnode_t *, vp, GETATTR3res *, resp);
 139 
 140         if (vp != NULL)
 141                 VN_RELE(vp);
 142 }
 143 
 144 void *
 145 rfs3_getattr_getfh(GETATTR3args *args)
 146 {
 147 
 148         return (&args->object);
 149 }
 150 
 151 void
 152 rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
 153     struct svc_req *req, cred_t *cr, bool_t ro)
 154 {
 155         int error;
 156         vnode_t *vp;
 157         struct vattr *bvap;
 158         struct vattr bva;
 159         struct vattr *avap;
 160         struct vattr ava;
 161         int flag;
 162         int in_crit = 0;
 163         struct flock64 bf;
 164         caller_context_t ct;
 165 
 166         bvap = NULL;
 167         avap = NULL;
 168 
 169         vp = nfs3_fhtovp(&args->object, exi);
 170 
 171         DTRACE_NFSV3_4(op__setattr__start, struct svc_req *, req,
 172             cred_t *, cr, vnode_t *, vp, SETATTR3args *, args);
 173 
 174         if (vp == NULL) {
 175                 error = ESTALE;
 176                 goto out;
 177         }
 178 
 179         error = sattr3_to_vattr(&args->new_attributes, &ava);
 180         if (error)
 181                 goto out;
 182 
 183         if (is_system_labeled()) {
 184                 bslabel_t *clabel = req->rq_label;
 185 
 186                 ASSERT(clabel != NULL);
 187                 DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
 188                     "got client label from request(1)", struct svc_req *, req);
 189 
 190                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
 191                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
 192                             exi)) {
 
 313                 goto out1;
 314         }
 315 
 316         ava.va_mask = AT_ALL;
 317         avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
 318 
 319         /*
 320          * Force modified metadata out to stable storage.
 321          */
 322         (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
 323 
 324         if (error)
 325                 goto out;
 326 
 327         if (in_crit)
 328                 nbl_end_crit(vp);
 329 
 330         resp->status = NFS3_OK;
 331         vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
 332 
 333         DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
 334             cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
 335 
 336         VN_RELE(vp);
 337 
 338         return;
 339 
 340 out:
 341         if (curthread->t_flag & T_WOULDBLOCK) {
 342                 curthread->t_flag &= ~T_WOULDBLOCK;
 343                 resp->status = NFS3ERR_JUKEBOX;
 344         } else
 345                 resp->status = puterrno3(error);
 346 out1:
 347         DTRACE_NFSV3_4(op__setattr__done, struct svc_req *, req,
 348             cred_t *, cr, vnode_t *, vp, SETATTR3res *, resp);
 349 
 350         if (vp != NULL) {
 351                 if (in_crit)
 352                         nbl_end_crit(vp);
 353                 VN_RELE(vp);
 354         }
 355         vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
 356 }
 357 
 358 void *
 359 rfs3_setattr_getfh(SETATTR3args *args)
 360 {
 361 
 362         return (&args->object);
 363 }
 364 
 365 /* ARGSUSED */
 366 void
 367 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 368     struct svc_req *req, cred_t *cr, bool_t ro)
 369 {
 370         int error;
 371         vnode_t *vp;
 372         vnode_t *dvp;
 373         struct vattr *vap;
 374         struct vattr va;
 375         struct vattr *dvap;
 376         struct vattr dva;
 377         nfs_fh3 *fhp;
 378         struct sec_ol sec = {0, 0};
 379         bool_t publicfh_flag = FALSE, auth_weak = FALSE;
 380         struct sockaddr *ca;
 381         char *name = NULL;
 382 
 383         dvap = NULL;
 384 
 385         /*
 386          * Allow lookups from the root - the default
 387          * location of the public filehandle.
 388          */
 389         if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
 390                 dvp = rootdir;
 391                 VN_HOLD(dvp);
 392 
 393                 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
 394                     cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
 395         } else {
 396                 dvp = nfs3_fhtovp(&args->what.dir, exi);
 397 
 398                 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
 399                     cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
 400 
 401                 if (dvp == NULL) {
 402                         error = ESTALE;
 403                         goto out;
 404                 }
 405         }
 406 
 407         dva.va_mask = AT_ALL;
 408         dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 409 
 410         if (args->what.name == nfs3nametoolong) {
 411                 resp->status = NFS3ERR_NAMETOOLONG;
 412                 goto out1;
 413         }
 414 
 415         if (args->what.name == NULL || *(args->what.name) == '\0') {
 416                 resp->status = NFS3ERR_ACCES;
 417                 goto out1;
 418         }
 419 
 420         fhp = &args->what.dir;
 421         if (strcmp(args->what.name, "..") == 0 &&
 422             EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
 423                 resp->status = NFS3ERR_NOENT;
 424                 goto out1;
 425         }
 426 
 427         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 428         name = nfscmd_convname(ca, exi, args->what.name,
 429             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
 430 
 431         if (name == NULL) {
 432                 resp->status = NFS3ERR_ACCES;
 433                 goto out1;
 434         }
 435 
 436         /*
 437          * If the public filehandle is used then allow
 438          * a multi-component lookup
 439          */
 440         if (PUBLIC_FH3(&args->what.dir)) {
 441                 publicfh_flag = TRUE;
 442                 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
 443                     &exi, &sec);
 444                 if (error && exi != NULL)
 445                         exi_rele(exi); /* See comment below Re: publicfh_flag */
 446                 /*
 447                  * Since WebNFS may bypass MOUNT, we need to ensure this
 448                  * request didn't come from an unlabeled admin_low client.
 449                  */
 450                 if (is_system_labeled() && error == 0) {
 451                         int             addr_type;
 452                         void            *ipaddr;
 453                         tsol_tpc_t      *tp;
 454 
 455                         if (ca->sa_family == AF_INET) {
 456                                 addr_type = IPV4_VERSION;
 457                                 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
 458                         } else if (ca->sa_family == AF_INET6) {
 459                                 addr_type = IPV6_VERSION;
 460                                 ipaddr = &((struct sockaddr_in6 *)
 461                                     ca)->sin6_addr;
 462                         }
 463                         tp = find_tpc(ipaddr, addr_type, B_FALSE);
 464                         if (tp == NULL || tp->tpc_tp.tp_doi !=
 465                             l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
 466                             SUN_CIPSO) {
 467                                 if (exi != NULL)
 468                                         exi_rele(exi);
 469                                 VN_RELE(vp);
 470                                 error = EACCES;
 471                         }
 472                         if (tp != NULL)
 473                                 TPC_RELE(tp);
 474                 }
 475         } else {
 476                 error = VOP_LOOKUP(dvp, name, &vp,
 477                     NULL, 0, NULL, cr, NULL, NULL, NULL);
 478         }
 479 
 480         if (name != args->what.name)
 481                 kmem_free(name, MAXPATHLEN + 1);
 482 
 483         if (is_system_labeled() && error == 0) {
 484                 bslabel_t *clabel = req->rq_label;
 485 
 486                 ASSERT(clabel != NULL);
 487                 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
 488                     "got client label from request(1)", struct svc_req *, req);
 489 
 490                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
 491                         if (!do_rfs_label_check(clabel, dvp,
 492                             DOMINANCE_CHECK, exi)) {
 493                                 if (publicfh_flag && exi != NULL)
 494                                         exi_rele(exi);
 495                                 VN_RELE(vp);
 496                                 error = EACCES;
 497                         }
 498                 }
 499         }
 500 
 501         dva.va_mask = AT_ALL;
 502         dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 503 
 504         if (error)
 505                 goto out;
 506 
 507         if (sec.sec_flags & SEC_QUERY) {
 508                 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
 509         } else {
 510                 error = makefh3(&resp->resok.object, vp, exi);
 511                 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
 512                         auth_weak = TRUE;
 513         }
 514 
 515         /*
 516          * If publicfh_flag is true then we have called rfs_publicfh_mclookup
 517          * and have obtained a new exportinfo in exi which needs to be
 518          * released. Note that the original exportinfo pointed to by exi
 519          * will be released by the caller, common_dispatch.
 520          */
 521         if (publicfh_flag)
 522                 exi_rele(exi);
 523 
 524         if (error) {
 525                 VN_RELE(vp);
 526                 goto out;
 527         }
 528 
 529         va.va_mask = AT_ALL;
 530         vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 531 
 532         VN_RELE(vp);
 533 
 534         resp->status = NFS3_OK;
 535         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 536         vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
 537 
 538         /*
 539          * If it's public fh, no 0x81, and client's flavor is
 540          * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
 541          * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
 542          */
 543         if (auth_weak)
 544                 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
 545 
 546         DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
 547             cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
 548         VN_RELE(dvp);
 549 
 550         return;
 551 
 552 out:
 553         if (curthread->t_flag & T_WOULDBLOCK) {
 554                 curthread->t_flag &= ~T_WOULDBLOCK;
 555                 resp->status = NFS3ERR_JUKEBOX;
 556         } else
 557                 resp->status = puterrno3(error);
 558 out1:
 559         DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
 560             cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
 561 
 562         if (dvp != NULL)
 563                 VN_RELE(dvp);
 564         vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
 565 
 566 }
 567 
 568 void *
 569 rfs3_lookup_getfh(LOOKUP3args *args)
 570 {
 571 
 572         return (&args->what.dir);
 573 }
 574 
 575 /* ARGSUSED */
 576 void
 577 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
 578     struct svc_req *req, cred_t *cr, bool_t ro)
 579 {
 580         int error;
 581         vnode_t *vp;
 582         struct vattr *vap;
 583         struct vattr va;
 584         int checkwriteperm;
 585         boolean_t dominant_label = B_FALSE;
 586         boolean_t equal_label = B_FALSE;
 587         boolean_t admin_low_client;
 588 
 589         vap = NULL;
 590 
 591         vp = nfs3_fhtovp(&args->object, exi);
 592 
 593         DTRACE_NFSV3_4(op__access__start, struct svc_req *, req,
 594             cred_t *, cr, vnode_t *, vp, ACCESS3args *, args);
 595 
 596         if (vp == NULL) {
 597                 error = ESTALE;
 598                 goto out;
 599         }
 600 
 601         /*
 602          * If the file system is exported read only, it is not appropriate
 603          * to check write permissions for regular files and directories.
 604          * Special files are interpreted by the client, so the underlying
 605          * permissions are sent back to the client for interpretation.
 606          */
 607         if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
 608                 checkwriteperm = 0;
 609         else
 610                 checkwriteperm = 1;
 611 
 612         /*
 613          * We need the mode so that we can correctly determine access
 614          * permissions relative to a mandatory lock file.  Access to
 
 684                     equal_label)
 685                         resp->resok.access |= ACCESS3_DELETE;
 686         }
 687         if (args->access & ACCESS3_EXECUTE) {
 688                 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
 689                 if (error) {
 690                         if (curthread->t_flag & T_WOULDBLOCK)
 691                                 goto out;
 692                 } else if (!MANDLOCK(vp, va.va_mode) &&
 693                     (!is_system_labeled() || admin_low_client ||
 694                     dominant_label))
 695                         resp->resok.access |= ACCESS3_EXECUTE;
 696         }
 697 
 698         va.va_mask = AT_ALL;
 699         vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 700 
 701         resp->status = NFS3_OK;
 702         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 703 
 704         DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
 705             cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
 706 
 707         VN_RELE(vp);
 708 
 709         return;
 710 
 711 out:
 712         if (curthread->t_flag & T_WOULDBLOCK) {
 713                 curthread->t_flag &= ~T_WOULDBLOCK;
 714                 resp->status = NFS3ERR_JUKEBOX;
 715         } else
 716                 resp->status = puterrno3(error);
 717         DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
 718             cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
 719         if (vp != NULL)
 720                 VN_RELE(vp);
 721         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
 722 }
 723 
 724 void *
 725 rfs3_access_getfh(ACCESS3args *args)
 726 {
 727 
 728         return (&args->object);
 729 }
 730 
 731 /* ARGSUSED */
 732 void
 733 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
 734     struct svc_req *req, cred_t *cr, bool_t ro)
 735 {
 736         int error;
 737         vnode_t *vp;
 738         struct vattr *vap;
 739         struct vattr va;
 740         struct iovec iov;
 741         struct uio uio;
 742         char *data;
 743         struct sockaddr *ca;
 744         char *name = NULL;
 745         int is_referral = 0;
 746 
 747         vap = NULL;
 748 
 749         vp = nfs3_fhtovp(&args->symlink, exi);
 750 
 751         DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
 752             cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
 753 
 754         if (vp == NULL) {
 755                 error = ESTALE;
 756                 goto out;
 757         }
 758 
 759         va.va_mask = AT_ALL;
 760         error = VOP_GETATTR(vp, &va, 0, cr, NULL);
 761         if (error)
 762                 goto out;
 763 
 764         vap = &va;
 765 
 766         /* We lied about the object type for a referral */
 767         if (vn_is_nfs_reparse(vp, cr))
 768                 is_referral = 1;
 769 
 770         if (vp->v_type != VLNK && !is_referral) {
 771                 resp->status = NFS3ERR_INVAL;
 772                 goto out1;
 
 852                 kmem_free(data, MAXPATHLEN + 1);
 853                 goto out;
 854         }
 855 
 856         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 857         name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
 858             MAXPATHLEN + 1);
 859 
 860         if (name == NULL) {
 861                 /*
 862                  * Even though the conversion failed, we return
 863                  * something. We just don't translate it.
 864                  */
 865                 name = data;
 866         }
 867 
 868         resp->status = NFS3_OK;
 869         vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
 870         resp->resok.data = name;
 871 
 872         DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
 873             cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
 874         VN_RELE(vp);
 875 
 876         if (name != data)
 877                 kmem_free(data, MAXPATHLEN + 1);
 878 
 879         return;
 880 
 881 out:
 882         if (curthread->t_flag & T_WOULDBLOCK) {
 883                 curthread->t_flag &= ~T_WOULDBLOCK;
 884                 resp->status = NFS3ERR_JUKEBOX;
 885         } else
 886                 resp->status = puterrno3(error);
 887 out1:
 888         DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
 889             cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
 890         if (vp != NULL)
 891                 VN_RELE(vp);
 892         vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
 893 }
 894 
 895 void *
 896 rfs3_readlink_getfh(READLINK3args *args)
 897 {
 898 
 899         return (&args->symlink);
 900 }
 901 
 902 void
 903 rfs3_readlink_free(READLINK3res *resp)
 904 {
 905 
 906         if (resp->status == NFS3_OK)
 907                 kmem_free(resp->resok.data, MAXPATHLEN + 1);
 908 }
 909 
 910 /*
 911  * Server routine to handle read
 912  * May handle RDMA data as well as mblks
 913  */
 914 /* ARGSUSED */
 915 void
 916 rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
 917     struct svc_req *req, cred_t *cr, bool_t ro)
 918 {
 919         int error;
 920         vnode_t *vp;
 921         struct vattr *vap;
 922         struct vattr va;
 923         struct iovec iov, *iovp = NULL;
 924         int iovcnt;
 925         struct uio uio;
 926         u_offset_t offset;
 927         mblk_t *mp = NULL;
 928         int in_crit = 0;
 929         int need_rwunlock = 0;
 930         caller_context_t ct;
 931         int rdma_used = 0;
 932         int loaned_buffers;
 933         struct uio *uiop;
 934 
 935         vap = NULL;
 936 
 937         vp = nfs3_fhtovp(&args->file, exi);
 938 
 939         DTRACE_NFSV3_4(op__read__start, struct svc_req *, req,
 940             cred_t *, cr, vnode_t *, vp, READ3args *, args);
 941 
 942         if (vp == NULL) {
 943                 error = ESTALE;
 944                 goto out;
 945         }
 946 
 947         if (args->wlist) {
 948                 if (args->count > clist_len(args->wlist)) {
 949                         error = EINVAL;
 950                         goto out;
 951                 }
 952                 rdma_used = 1;
 953         }
 954 
 955         /* use loaned buffers for TCP */
 956         loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
 957 
 958         if (is_system_labeled()) {
 959                 bslabel_t *clabel = req->rq_label;
 960 
 961                 ASSERT(clabel != NULL);
 
1175                 resp->resok.eof = FALSE;
1176         resp->resok.data.data_len = resp->resok.count;
1177 
1178         if (mp)
1179                 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1180 
1181         resp->resok.data.mp = mp;
1182         resp->resok.size = (uint_t)args->count;
1183 
1184         if (rdma_used) {
1185                 resp->resok.data.data_val = (caddr_t)iov.iov_base;
1186                 if (!rdma_setup_read_data3(args, &(resp->resok))) {
1187                         resp->status = NFS3ERR_INVAL;
1188                 }
1189         } else {
1190                 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1191                 (resp->resok).wlist = NULL;
1192         }
1193 
1194 done:
1195         DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1196             cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1197 
1198         VN_RELE(vp);
1199 
1200         if (iovp != NULL)
1201                 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1202 
1203         return;
1204 
1205 out:
1206         if (curthread->t_flag & T_WOULDBLOCK) {
1207                 curthread->t_flag &= ~T_WOULDBLOCK;
1208                 resp->status = NFS3ERR_JUKEBOX;
1209         } else
1210                 resp->status = puterrno3(error);
1211 out1:
1212         DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1213             cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1214 
1215         if (vp != NULL) {
1216                 if (need_rwunlock)
1217                         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1218                 if (in_crit)
1219                         nbl_end_crit(vp);
1220                 VN_RELE(vp);
1221         }
1222         vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1223 
1224         if (iovp != NULL)
1225                 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1226 }
1227 
1228 void
1229 rfs3_read_free(READ3res *resp)
1230 {
1231         mblk_t *mp;
1232 
1233         if (resp->status == NFS3_OK) {
1234                 mp = resp->resok.data.mp;
1235                 if (mp != NULL)
1236                         freemsg(mp);
1237         }
1238 }
1239 
1240 void *
1241 rfs3_read_getfh(READ3args *args)
1242 {
1243 
1244         return (&args->file);
1245 }
1246 
1247 #define MAX_IOVECS      12
1248 
1249 #ifdef DEBUG
1250 static int rfs3_write_hits = 0;
1251 static int rfs3_write_misses = 0;
1252 #endif
1253 
1254 void
1255 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1256     struct svc_req *req, cred_t *cr, bool_t ro)
1257 {
1258         int error;
1259         vnode_t *vp;
1260         struct vattr *bvap = NULL;
1261         struct vattr bva;
1262         struct vattr *avap = NULL;
1263         struct vattr ava;
1264         u_offset_t rlimit;
1265         struct uio uio;
1266         struct iovec iov[MAX_IOVECS];
1267         mblk_t *m;
1268         struct iovec *iovp;
1269         int iovcnt;
1270         int ioflag;
1271         cred_t *savecred;
1272         int in_crit = 0;
1273         int rwlock_ret = -1;
1274         caller_context_t ct;
1275 
1276         vp = nfs3_fhtovp(&args->file, exi);
1277 
1278         DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
1279             cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
1280 
1281         if (vp == NULL) {
1282                 error = ESTALE;
1283                 goto err;
1284         }
1285 
1286         if (is_system_labeled()) {
1287                 bslabel_t *clabel = req->rq_label;
1288 
1289                 ASSERT(clabel != NULL);
1290                 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1291                     "got client label from request(1)", struct svc_req *, req);
1292 
1293                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1294                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1295                             exi)) {
1296                                 resp->status = NFS3ERR_ACCES;
1297                                 goto err1;
1298                         }
1299                 }
1300         }
1301 
1302         ct.cc_sysid = 0;
1303         ct.cc_pid = 0;
1304         ct.cc_caller_id = nfs3_srv_caller_id;
1305         ct.cc_flags = CC_DONTBLOCK;
 
1353 
1354         if (vp->v_type != VREG) {
1355                 resp->status = NFS3ERR_INVAL;
1356                 goto err1;
1357         }
1358 
1359         if (crgetuid(cr) != bva.va_uid &&
1360             (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1361                 goto err;
1362 
1363         if (MANDLOCK(vp, bva.va_mode)) {
1364                 resp->status = NFS3ERR_ACCES;
1365                 goto err1;
1366         }
1367 
1368         if (args->count == 0) {
1369                 resp->status = NFS3_OK;
1370                 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1371                 resp->resok.count = 0;
1372                 resp->resok.committed = args->stable;
1373                 resp->resok.verf = write3verf;
1374                 goto out;
1375         }
1376 
1377         if (args->mblk != NULL) {
1378                 iovcnt = 0;
1379                 for (m = args->mblk; m != NULL; m = m->b_cont)
1380                         iovcnt++;
1381                 if (iovcnt <= MAX_IOVECS) {
1382 #ifdef DEBUG
1383                         rfs3_write_hits++;
1384 #endif
1385                         iovp = iov;
1386                 } else {
1387 #ifdef DEBUG
1388                         rfs3_write_misses++;
1389 #endif
1390                         iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1391                 }
1392                 mblk_to_iov(args->mblk, iovcnt, iovp);
1393 
 
1455 
1456         /*
1457          * If we were unable to get the V_WRITELOCK_TRUE, then we
1458          * may not have accurate after attrs, so check if
1459          * we have both attributes, they have a non-zero va_seq, and
1460          * va_seq has changed by exactly one,
1461          * if not, turn off the before attr.
1462          */
1463         if (rwlock_ret != V_WRITELOCK_TRUE) {
1464                 if (bvap == NULL || avap == NULL ||
1465                     bvap->va_seq == 0 || avap->va_seq == 0 ||
1466                     avap->va_seq != (bvap->va_seq + 1)) {
1467                         bvap = NULL;
1468                 }
1469         }
1470 
1471         resp->status = NFS3_OK;
1472         vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1473         resp->resok.count = args->count - uio.uio_resid;
1474         resp->resok.committed = args->stable;
1475         resp->resok.verf = write3verf;
1476         goto out;
1477 
1478 err:
1479         if (curthread->t_flag & T_WOULDBLOCK) {
1480                 curthread->t_flag &= ~T_WOULDBLOCK;
1481                 resp->status = NFS3ERR_JUKEBOX;
1482         } else
1483                 resp->status = puterrno3(error);
1484 err1:
1485         vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1486 out:
1487         DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
1488             cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
1489 
1490         if (vp != NULL) {
1491                 if (rwlock_ret != -1)
1492                         VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1493                 if (in_crit)
1494                         nbl_end_crit(vp);
1495                 VN_RELE(vp);
1496         }
1497 }
1498 
1499 void *
1500 rfs3_write_getfh(WRITE3args *args)
1501 {
1502 
1503         return (&args->file);
1504 }
1505 
1506 void
1507 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1508     struct svc_req *req, cred_t *cr, bool_t ro)
1509 {
1510         int error;
1511         int in_crit = 0;
1512         vnode_t *vp;
1513         vnode_t *tvp = NULL;
1514         vnode_t *dvp;
1515         struct vattr *vap;
1516         struct vattr va;
1517         struct vattr *dbvap;
1518         struct vattr dbva;
1519         struct vattr *davap;
1520         struct vattr dava;
1521         enum vcexcl excl;
1522         nfstime3 *mtime;
1523         len_t reqsize;
1524         bool_t trunc;
1525         struct sockaddr *ca;
1526         char *name = NULL;
1527 
1528         dbvap = NULL;
1529         davap = NULL;
1530 
1531         dvp = nfs3_fhtovp(&args->where.dir, exi);
1532 
1533         DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
1534             cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
1535 
1536         if (dvp == NULL) {
1537                 error = ESTALE;
1538                 goto out;
1539         }
1540 
1541         dbva.va_mask = AT_ALL;
1542         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1543         davap = dbvap;
1544 
1545         if (args->where.name == nfs3nametoolong) {
1546                 resp->status = NFS3ERR_NAMETOOLONG;
1547                 goto out1;
1548         }
1549 
1550         if (args->where.name == NULL || *(args->where.name) == '\0') {
1551                 resp->status = NFS3ERR_ACCES;
1552                 goto out1;
1553         }
1554 
1555         if (rdonly(ro, dvp)) {
1556                 resp->status = NFS3ERR_ROFS;
1557                 goto out1;
1558         }
1559 
1560         if (is_system_labeled()) {
1561                 bslabel_t *clabel = req->rq_label;
1562 
1563                 ASSERT(clabel != NULL);
1564                 DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
1565                     "got client label from request(1)", struct svc_req *, req);
1566 
1567                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1568                         if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1569                             exi)) {
1570                                 resp->status = NFS3ERR_ACCES;
1571                                 goto out1;
1572                         }
1573                 }
1574         }
1575 
1576         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1577         name = nfscmd_convname(ca, exi, args->where.name,
1578             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1579 
 
1813         else
1814                 resp->resok.obj.handle_follows = TRUE;
1815 
1816         /*
1817          * Force modified data and metadata out to stable storage.
1818          */
1819         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1820         (void) VOP_FSYNC(dvp, 0, cr, NULL);
1821 
1822         VN_RELE(vp);
1823         if (tvp != NULL) {
1824                 if (in_crit)
1825                         nbl_end_crit(tvp);
1826                 VN_RELE(tvp);
1827         }
1828 
1829         resp->status = NFS3_OK;
1830         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1831         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1832 
1833         DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1834             cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1835 
1836         VN_RELE(dvp);
1837         return;
1838 
1839 out:
1840         if (curthread->t_flag & T_WOULDBLOCK) {
1841                 curthread->t_flag &= ~T_WOULDBLOCK;
1842                 resp->status = NFS3ERR_JUKEBOX;
1843         } else
1844                 resp->status = puterrno3(error);
1845 out1:
1846         DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1847             cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1848 
1849         if (name != NULL && name != args->where.name)
1850                 kmem_free(name, MAXPATHLEN + 1);
1851 
1852         if (tvp != NULL) {
1853                 if (in_crit)
1854                         nbl_end_crit(tvp);
1855                 VN_RELE(tvp);
1856         }
1857         if (dvp != NULL)
1858                 VN_RELE(dvp);
1859         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1860 }
1861 
1862 void *
1863 rfs3_create_getfh(CREATE3args *args)
1864 {
1865 
1866         return (&args->where.dir);
1867 }
1868 
1869 void
1870 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1871     struct svc_req *req, cred_t *cr, bool_t ro)
1872 {
1873         int error;
1874         vnode_t *vp = NULL;
1875         vnode_t *dvp;
1876         struct vattr *vap;
1877         struct vattr va;
1878         struct vattr *dbvap;
1879         struct vattr dbva;
1880         struct vattr *davap;
1881         struct vattr dava;
1882         struct sockaddr *ca;
1883         char *name = NULL;
1884 
1885         dbvap = NULL;
1886         davap = NULL;
1887 
1888         dvp = nfs3_fhtovp(&args->where.dir, exi);
1889 
1890         DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
1891             cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
1892 
1893         if (dvp == NULL) {
1894                 error = ESTALE;
1895                 goto out;
1896         }
1897 
1898         dbva.va_mask = AT_ALL;
1899         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1900         davap = dbvap;
1901 
1902         if (args->where.name == nfs3nametoolong) {
1903                 resp->status = NFS3ERR_NAMETOOLONG;
1904                 goto out1;
1905         }
1906 
1907         if (args->where.name == NULL || *(args->where.name) == '\0') {
1908                 resp->status = NFS3ERR_ACCES;
1909                 goto out1;
1910         }
1911 
1912         if (rdonly(ro, dvp)) {
1913                 resp->status = NFS3ERR_ROFS;
1914                 goto out1;
1915         }
1916 
1917         if (is_system_labeled()) {
1918                 bslabel_t *clabel = req->rq_label;
1919 
1920                 ASSERT(clabel != NULL);
1921                 DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
1922                     "got client label from request(1)", struct svc_req *, req);
1923 
1924                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1925                         if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1926                             exi)) {
1927                                 resp->status = NFS3ERR_ACCES;
1928                                 goto out1;
1929                         }
1930                 }
1931         }
1932 
1933         error = sattr3_to_vattr(&args->attributes, &va);
1934         if (error)
1935                 goto out;
1936 
 
1970         error = makefh3(&resp->resok.obj.handle, vp, exi);
1971         if (error)
1972                 resp->resok.obj.handle_follows = FALSE;
1973         else
1974                 resp->resok.obj.handle_follows = TRUE;
1975 
1976         va.va_mask = AT_ALL;
1977         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1978 
1979         /*
1980          * Force modified data and metadata out to stable storage.
1981          */
1982         (void) VOP_FSYNC(vp, 0, cr, NULL);
1983 
1984         VN_RELE(vp);
1985 
1986         resp->status = NFS3_OK;
1987         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1988         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1989 
1990         DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
1991             cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
1992         VN_RELE(dvp);
1993 
1994         return;
1995 
1996 out:
1997         if (curthread->t_flag & T_WOULDBLOCK) {
1998                 curthread->t_flag &= ~T_WOULDBLOCK;
1999                 resp->status = NFS3ERR_JUKEBOX;
2000         } else
2001                 resp->status = puterrno3(error);
2002 out1:
2003         DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2004             cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2005         if (dvp != NULL)
2006                 VN_RELE(dvp);
2007         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2008 }
2009 
2010 void *
2011 rfs3_mkdir_getfh(MKDIR3args *args)
2012 {
2013 
2014         return (&args->where.dir);
2015 }
2016 
2017 void
2018 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2019     struct svc_req *req, cred_t *cr, bool_t ro)
2020 {
2021         int error;
2022         vnode_t *vp;
2023         vnode_t *dvp;
2024         struct vattr *vap;
2025         struct vattr va;
2026         struct vattr *dbvap;
2027         struct vattr dbva;
2028         struct vattr *davap;
2029         struct vattr dava;
2030         struct sockaddr *ca;
2031         char *name = NULL;
2032         char *symdata = NULL;
2033 
2034         dbvap = NULL;
2035         davap = NULL;
2036 
2037         dvp = nfs3_fhtovp(&args->where.dir, exi);
2038 
2039         DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
2040             cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
2041 
2042         if (dvp == NULL) {
2043                 error = ESTALE;
2044                 goto err;
2045         }
2046 
2047         dbva.va_mask = AT_ALL;
2048         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2049         davap = dbvap;
2050 
2051         if (args->where.name == nfs3nametoolong) {
2052                 resp->status = NFS3ERR_NAMETOOLONG;
2053                 goto err1;
2054         }
2055 
2056         if (args->where.name == NULL || *(args->where.name) == '\0') {
2057                 resp->status = NFS3ERR_ACCES;
2058                 goto err1;
2059         }
2060 
2061         if (rdonly(ro, dvp)) {
2062                 resp->status = NFS3ERR_ROFS;
2063                 goto err1;
2064         }
2065 
2066         if (is_system_labeled()) {
2067                 bslabel_t *clabel = req->rq_label;
2068 
2069                 ASSERT(clabel != NULL);
2070                 DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
2071                     "got client label from request(1)", struct svc_req *, req);
2072 
2073                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2074                         if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2075                             exi)) {
2076                                 resp->status = NFS3ERR_ACCES;
2077                                 goto err1;
2078                         }
2079                 }
2080         }
2081 
2082         error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
2083         if (error)
2084                 goto err;
2085 
 
2157         VN_RELE(vp);
2158 
2159         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2160         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2161         goto out;
2162 
2163 err:
2164         if (curthread->t_flag & T_WOULDBLOCK) {
2165                 curthread->t_flag &= ~T_WOULDBLOCK;
2166                 resp->status = NFS3ERR_JUKEBOX;
2167         } else
2168                 resp->status = puterrno3(error);
2169 err1:
2170         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2171 out:
2172         if (name != NULL && name != args->where.name)
2173                 kmem_free(name, MAXPATHLEN + 1);
2174         if (symdata != NULL && symdata != args->symlink.symlink_data)
2175                 kmem_free(symdata, MAXPATHLEN + 1);
2176 
2177         DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
2178             cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
2179 
2180         if (dvp != NULL)
2181                 VN_RELE(dvp);
2182 }
2183 
2184 void *
2185 rfs3_symlink_getfh(SYMLINK3args *args)
2186 {
2187 
2188         return (&args->where.dir);
2189 }
2190 
2191 void
2192 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2193     struct svc_req *req, cred_t *cr, bool_t ro)
2194 {
2195         int error;
2196         vnode_t *vp;
2197         vnode_t *realvp;
2198         vnode_t *dvp;
2199         struct vattr *vap;
2200         struct vattr va;
2201         struct vattr *dbvap;
2202         struct vattr dbva;
2203         struct vattr *davap;
2204         struct vattr dava;
2205         int mode;
2206         enum vcexcl excl;
2207         struct sockaddr *ca;
2208         char *name = NULL;
2209 
2210         dbvap = NULL;
2211         davap = NULL;
2212 
2213         dvp = nfs3_fhtovp(&args->where.dir, exi);
2214 
2215         DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
2216             cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
2217 
2218         if (dvp == NULL) {
2219                 error = ESTALE;
2220                 goto out;
2221         }
2222 
2223         dbva.va_mask = AT_ALL;
2224         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2225         davap = dbvap;
2226 
2227         if (args->where.name == nfs3nametoolong) {
2228                 resp->status = NFS3ERR_NAMETOOLONG;
2229                 goto out1;
2230         }
2231 
2232         if (args->where.name == NULL || *(args->where.name) == '\0') {
2233                 resp->status = NFS3ERR_ACCES;
2234                 goto out1;
2235         }
2236 
2237         if (rdonly(ro, dvp)) {
2238                 resp->status = NFS3ERR_ROFS;
2239                 goto out1;
2240         }
2241 
2242         if (is_system_labeled()) {
2243                 bslabel_t *clabel = req->rq_label;
2244 
2245                 ASSERT(clabel != NULL);
2246                 DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
2247                     "got client label from request(1)", struct svc_req *, req);
2248 
2249                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2250                         if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2251                             exi)) {
2252                                 resp->status = NFS3ERR_ACCES;
2253                                 goto out1;
2254                         }
2255                 }
2256         }
2257 
2258         switch (args->what.type) {
2259         case NF3CHR:
2260         case NF3BLK:
2261                 error = sattr3_to_vattr(
 
2342         else
2343                 resp->resok.obj.handle_follows = TRUE;
2344 
2345         va.va_mask = AT_ALL;
2346         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2347 
2348         /*
2349          * Force modified metadata out to stable storage.
2350          *
2351          * if a underlying vp exists, pass it to VOP_FSYNC
2352          */
2353         if (VOP_REALVP(vp, &realvp, NULL) == 0)
2354                 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2355         else
2356                 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2357 
2358         VN_RELE(vp);
2359 
2360         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2361         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2362         DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2363             cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2364         VN_RELE(dvp);
2365         return;
2366 
2367 out:
2368         if (curthread->t_flag & T_WOULDBLOCK) {
2369                 curthread->t_flag &= ~T_WOULDBLOCK;
2370                 resp->status = NFS3ERR_JUKEBOX;
2371         } else
2372                 resp->status = puterrno3(error);
2373 out1:
2374         DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2375             cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2376         if (dvp != NULL)
2377                 VN_RELE(dvp);
2378         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2379 }
2380 
2381 void *
2382 rfs3_mknod_getfh(MKNOD3args *args)
2383 {
2384 
2385         return (&args->where.dir);
2386 }
2387 
2388 void
2389 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2390     struct svc_req *req, cred_t *cr, bool_t ro)
2391 {
2392         int error = 0;
2393         vnode_t *vp;
2394         struct vattr *bvap;
2395         struct vattr bva;
2396         struct vattr *avap;
2397         struct vattr ava;
2398         vnode_t *targvp = NULL;
2399         struct sockaddr *ca;
2400         char *name = NULL;
2401 
2402         bvap = NULL;
2403         avap = NULL;
2404 
2405         vp = nfs3_fhtovp(&args->object.dir, exi);
2406 
2407         DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
2408             cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
2409 
2410         if (vp == NULL) {
2411                 error = ESTALE;
2412                 goto err;
2413         }
2414 
2415         bva.va_mask = AT_ALL;
2416         bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2417         avap = bvap;
2418 
2419         if (vp->v_type != VDIR) {
2420                 resp->status = NFS3ERR_NOTDIR;
2421                 goto err1;
2422         }
2423 
2424         if (args->object.name == nfs3nametoolong) {
2425                 resp->status = NFS3ERR_NAMETOOLONG;
2426                 goto err1;
2427         }
2428 
 
2496          * Force modified data and metadata out to stable storage.
2497          */
2498         (void) VOP_FSYNC(vp, 0, cr, NULL);
2499 
2500         if (error)
2501                 goto err;
2502 
2503         resp->status = NFS3_OK;
2504         vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2505         goto out;
2506 
2507 err:
2508         if (curthread->t_flag & T_WOULDBLOCK) {
2509                 curthread->t_flag &= ~T_WOULDBLOCK;
2510                 resp->status = NFS3ERR_JUKEBOX;
2511         } else
2512                 resp->status = puterrno3(error);
2513 err1:
2514         vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2515 out:
2516         DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
2517             cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
2518 
2519         if (name != NULL && name != args->object.name)
2520                 kmem_free(name, MAXPATHLEN + 1);
2521 
2522         if (vp != NULL)
2523                 VN_RELE(vp);
2524 }
2525 
2526 void *
2527 rfs3_remove_getfh(REMOVE3args *args)
2528 {
2529 
2530         return (&args->object.dir);
2531 }
2532 
2533 void
2534 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2535     struct svc_req *req, cred_t *cr, bool_t ro)
2536 {
2537         int error;
2538         vnode_t *vp;
2539         struct vattr *bvap;
2540         struct vattr bva;
2541         struct vattr *avap;
2542         struct vattr ava;
2543         struct sockaddr *ca;
2544         char *name = NULL;
2545 
2546         bvap = NULL;
2547         avap = NULL;
2548 
2549         vp = nfs3_fhtovp(&args->object.dir, exi);
2550 
2551         DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
2552             cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
2553 
2554         if (vp == NULL) {
2555                 error = ESTALE;
2556                 goto err;
2557         }
2558 
2559         bva.va_mask = AT_ALL;
2560         bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2561         avap = bvap;
2562 
2563         if (vp->v_type != VDIR) {
2564                 resp->status = NFS3ERR_NOTDIR;
2565                 goto err1;
2566         }
2567 
2568         if (args->object.name == nfs3nametoolong) {
2569                 resp->status = NFS3ERR_NAMETOOLONG;
2570                 goto err1;
2571         }
2572 
 
2588                     "got client label from request(1)", struct svc_req *, req);
2589 
2590                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2591                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2592                             exi)) {
2593                                 resp->status = NFS3ERR_ACCES;
2594                                 goto err1;
2595                         }
2596                 }
2597         }
2598 
2599         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2600         name = nfscmd_convname(ca, exi, args->object.name,
2601             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2602 
2603         if (name == NULL) {
2604                 resp->status = NFS3ERR_INVAL;
2605                 goto err1;
2606         }
2607 
2608         error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
2609 
2610         if (name != args->object.name)
2611                 kmem_free(name, MAXPATHLEN + 1);
2612 
2613         ava.va_mask = AT_ALL;
2614         avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2615 
2616         /*
2617          * Force modified data and metadata out to stable storage.
2618          */
2619         (void) VOP_FSYNC(vp, 0, cr, NULL);
2620 
2621         if (error) {
2622                 /*
2623                  * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2624                  * if the directory is not empty.  A System V NFS server
2625                  * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2626                  * over the wire.
2627                  */
2628                 if (error == EEXIST)
2629                         error = ENOTEMPTY;
2630                 goto err;
2631         }
2632 
2633         resp->status = NFS3_OK;
2634         vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2635         goto out;
2636 
2637 err:
2638         if (curthread->t_flag & T_WOULDBLOCK) {
2639                 curthread->t_flag &= ~T_WOULDBLOCK;
2640                 resp->status = NFS3ERR_JUKEBOX;
2641         } else
2642                 resp->status = puterrno3(error);
2643 err1:
2644         vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2645 out:
2646         DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
2647             cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
2648         if (vp != NULL)
2649                 VN_RELE(vp);
2650 
2651 }
2652 
2653 void *
2654 rfs3_rmdir_getfh(RMDIR3args *args)
2655 {
2656 
2657         return (&args->object.dir);
2658 }
2659 
2660 void
2661 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2662     struct svc_req *req, cred_t *cr, bool_t ro)
2663 {
2664         int error = 0;
2665         vnode_t *fvp;
2666         vnode_t *tvp;
2667         vnode_t *targvp;
2668         struct vattr *fbvap;
2669         struct vattr fbva;
2670         struct vattr *favap;
2671         struct vattr fava;
2672         struct vattr *tbvap;
2673         struct vattr tbva;
2674         struct vattr *tavap;
2675         struct vattr tava;
2676         nfs_fh3 *fh3;
2677         struct exportinfo *to_exi;
2678         vnode_t *srcvp = NULL;
2679         bslabel_t *clabel;
2680         struct sockaddr *ca;
2681         char *name = NULL;
2682         char *toname = NULL;
2683 
2684         fbvap = NULL;
2685         favap = NULL;
2686         tbvap = NULL;
2687         tavap = NULL;
2688         tvp = NULL;
2689 
2690         fvp = nfs3_fhtovp(&args->from.dir, exi);
2691 
2692         DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
2693             cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
2694 
2695         if (fvp == NULL) {
2696                 error = ESTALE;
2697                 goto err;
2698         }
2699 
2700         if (is_system_labeled()) {
2701                 clabel = req->rq_label;
2702                 ASSERT(clabel != NULL);
2703                 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2704                     "got client label from request(1)", struct svc_req *, req);
2705 
2706                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2707                         if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2708                             exi)) {
2709                                 resp->status = NFS3ERR_ACCES;
2710                                 goto err1;
2711                         }
2712                 }
2713         }
2714 
2715         fbva.va_mask = AT_ALL;
2716         fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2717         favap = fbvap;
2718 
2719         fh3 = &args->to.dir;
2720         to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2721         if (to_exi == NULL) {
2722                 resp->status = NFS3ERR_ACCES;
2723                 goto err1;
2724         }
2725         exi_rele(to_exi);
2726 
2727         if (to_exi != exi) {
2728                 resp->status = NFS3ERR_XDEV;
2729                 goto err1;
2730         }
2731 
2732         tvp = nfs3_fhtovp(&args->to.dir, exi);
2733         if (tvp == NULL) {
2734                 error = ESTALE;
2735                 goto err;
2736         }
2737 
2738         tbva.va_mask = AT_ALL;
2739         tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2740         tavap = tbvap;
2741 
2742         if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
2743                 resp->status = NFS3ERR_NOTDIR;
2744                 goto err1;
2745         }
2746 
2747         if (args->from.name == nfs3nametoolong ||
2748             args->to.name == nfs3nametoolong) {
2749                 resp->status = NFS3ERR_NAMETOOLONG;
2750                 goto err1;
2751         }
2752         if (args->from.name == NULL || *(args->from.name) == '\0' ||
2753             args->to.name == NULL || *(args->to.name) == '\0') {
2754                 resp->status = NFS3ERR_ACCES;
2755                 goto err1;
2756         }
2757 
2758         if (rdonly(ro, tvp)) {
2759                 resp->status = NFS3ERR_ROFS;
2760                 goto err1;
2761         }
2762 
2763         if (is_system_labeled()) {
2764                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2765                         if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
2766                             exi)) {
2767                                 resp->status = NFS3ERR_ACCES;
2768                                 goto err1;
2769                         }
2770                 }
2771         }
2772 
2773         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2774         name = nfscmd_convname(ca, exi, args->from.name,
2775             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2776 
2777         if (name == NULL) {
2778                 resp->status = NFS3ERR_INVAL;
2779                 goto err1;
2780         }
2781 
2782         toname = nfscmd_convname(ca, exi, args->to.name,
 
2790         /*
2791          * Check for a conflict with a non-blocking mandatory share
2792          * reservation or V4 delegations.
2793          */
2794         error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2795             NULL, cr, NULL, NULL, NULL);
2796         if (error != 0)
2797                 goto err;
2798 
2799         /*
2800          * If we rename a delegated file we should recall the
2801          * delegation, since future opens should fail or would
2802          * refer to a new file.
2803          */
2804         if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2805                 resp->status = NFS3ERR_JUKEBOX;
2806                 goto err1;
2807         }
2808 
2809         /*
2810          * Check for renaming over a delegated file.  Check rfs4_deleg_policy
2811          * first to avoid VOP_LOOKUP if possible.
2812          */
2813         if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
2814             VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2815             NULL, NULL, NULL) == 0) {
2816 
2817                 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2818                         VN_RELE(targvp);
2819                         resp->status = NFS3ERR_JUKEBOX;
2820                         goto err1;
2821                 }
2822                 VN_RELE(targvp);
2823         }
2824 
2825         if (!nbl_need_check(srcvp)) {
2826                 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2827         } else {
2828                 nbl_start_crit(srcvp, RW_READER);
2829                 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2830                         error = EACCES;
2831                 else
2832                         error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2833                 nbl_end_crit(srcvp);
 
2857         vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2858         goto out;
2859 
2860 err:
2861         if (curthread->t_flag & T_WOULDBLOCK) {
2862                 curthread->t_flag &= ~T_WOULDBLOCK;
2863                 resp->status = NFS3ERR_JUKEBOX;
2864         } else {
2865                 resp->status = puterrno3(error);
2866         }
2867 err1:
2868         vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2869         vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2870 
2871 out:
2872         if (name != NULL && name != args->from.name)
2873                 kmem_free(name, MAXPATHLEN + 1);
2874         if (toname != NULL && toname != args->to.name)
2875                 kmem_free(toname, MAXPATHLEN + 1);
2876 
2877         DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
2878             cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
2879         if (fvp != NULL)
2880                 VN_RELE(fvp);
2881         if (tvp != NULL)
2882                 VN_RELE(tvp);
2883 }
2884 
2885 void *
2886 rfs3_rename_getfh(RENAME3args *args)
2887 {
2888 
2889         return (&args->from.dir);
2890 }
2891 
2892 void
2893 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2894     struct svc_req *req, cred_t *cr, bool_t ro)
2895 {
2896         int error;
2897         vnode_t *vp;
2898         vnode_t *dvp;
2899         struct vattr *vap;
2900         struct vattr va;
2901         struct vattr *bvap;
2902         struct vattr bva;
2903         struct vattr *avap;
2904         struct vattr ava;
2905         nfs_fh3 *fh3;
2906         struct exportinfo *to_exi;
2907         bslabel_t *clabel;
2908         struct sockaddr *ca;
2909         char *name = NULL;
2910 
2911         vap = NULL;
2912         bvap = NULL;
2913         avap = NULL;
2914         dvp = NULL;
2915 
2916         vp = nfs3_fhtovp(&args->file, exi);
2917 
2918         DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
2919             cred_t *, cr, vnode_t *, vp, LINK3args *, args);
2920 
2921         if (vp == NULL) {
2922                 error = ESTALE;
2923                 goto out;
2924         }
2925 
2926         va.va_mask = AT_ALL;
2927         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2928 
2929         fh3 = &args->link.dir;
2930         to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2931         if (to_exi == NULL) {
2932                 resp->status = NFS3ERR_ACCES;
2933                 goto out1;
2934         }
2935         exi_rele(to_exi);
2936 
2937         if (to_exi != exi) {
2938                 resp->status = NFS3ERR_XDEV;
2939                 goto out1;
2940         }
2941 
2942         if (is_system_labeled()) {
2943                 clabel = req->rq_label;
2944 
2945                 ASSERT(clabel != NULL);
2946                 DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
2947                     "got client label from request(1)", struct svc_req *, req);
2948 
2949                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2950                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
2951                             exi)) {
2952                                 resp->status = NFS3ERR_ACCES;
2953                                 goto out1;
2954                         }
2955                 }
 
2967         if (dvp->v_type != VDIR) {
2968                 resp->status = NFS3ERR_NOTDIR;
2969                 goto out1;
2970         }
2971 
2972         if (args->link.name == nfs3nametoolong) {
2973                 resp->status = NFS3ERR_NAMETOOLONG;
2974                 goto out1;
2975         }
2976 
2977         if (args->link.name == NULL || *(args->link.name) == '\0') {
2978                 resp->status = NFS3ERR_ACCES;
2979                 goto out1;
2980         }
2981 
2982         if (rdonly(ro, dvp)) {
2983                 resp->status = NFS3ERR_ROFS;
2984                 goto out1;
2985         }
2986 
2987         if (is_system_labeled()) {
2988                 DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
2989                     "got client label from request(1)", struct svc_req *, req);
2990 
2991                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2992                         if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2993                             exi)) {
2994                                 resp->status = NFS3ERR_ACCES;
2995                                 goto out1;
2996                         }
2997                 }
2998         }
2999 
3000         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3001         name = nfscmd_convname(ca, exi, args->link.name,
3002             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3003 
3004         if (name == NULL) {
3005                 resp->status = NFS3ERR_SERVERFAULT;
3006                 goto out1;
 
3011         va.va_mask = AT_ALL;
3012         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3013         ava.va_mask = AT_ALL;
3014         avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3015 
3016         /*
3017          * Force modified data and metadata out to stable storage.
3018          */
3019         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3020         (void) VOP_FSYNC(dvp, 0, cr, NULL);
3021 
3022         if (error)
3023                 goto out;
3024 
3025         VN_RELE(dvp);
3026 
3027         resp->status = NFS3_OK;
3028         vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3029         vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3030 
3031         DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3032             cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3033 
3034         VN_RELE(vp);
3035 
3036         return;
3037 
3038 out:
3039         if (curthread->t_flag & T_WOULDBLOCK) {
3040                 curthread->t_flag &= ~T_WOULDBLOCK;
3041                 resp->status = NFS3ERR_JUKEBOX;
3042         } else
3043                 resp->status = puterrno3(error);
3044 out1:
3045         if (name != NULL && name != args->link.name)
3046                 kmem_free(name, MAXPATHLEN + 1);
3047 
3048         DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3049             cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3050 
3051         if (vp != NULL)
3052                 VN_RELE(vp);
3053         if (dvp != NULL)
3054                 VN_RELE(dvp);
3055         vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3056         vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3057 }
3058 
3059 void *
3060 rfs3_link_getfh(LINK3args *args)
3061 {
3062 
3063         return (&args->file);
3064 }
3065 
3066 /*
3067  * This macro defines the size of a response which contains attribute
3068  * information and one directory entry (whose length is specified by
3069  * the macro parameter).  If the incoming request is larger than this,
3070  * then we are guaranteed to be able to return at one directory entry
3071  * if one exists.  Therefore, we do not need to check for
3072  * NFS3ERR_TOOSMALL if the requested size is larger then this.  If it
3073  * is not, then we need to check to make sure that this error does not
3074  * need to be returned.
3075  *
3076  * NFS3_READDIR_MIN_COUNT is comprised of following :
3077  *
3078  * status - 1 * BYTES_PER_XDR_UNIT
3079  * attr. flag - 1 * BYTES_PER_XDR_UNIT
3080  * cookie verifier - 2 * BYTES_PER_XDR_UNIT
3081  * attributes  - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3082  * boolean - 1 * BYTES_PER_XDR_UNIT
3083  * file id - 2 * BYTES_PER_XDR_UNIT
3084  * directory name length - 1 * BYTES_PER_XDR_UNIT
3085  * cookie - 2 * BYTES_PER_XDR_UNIT
3086  * end of list - 1 * BYTES_PER_XDR_UNIT
3087  * end of file - 1 * BYTES_PER_XDR_UNIT
3088  * Name length of directory to the nearest byte
3089  */
3090 
3091 #define NFS3_READDIR_MIN_COUNT(length)  \
3092         ((1 + 1 + 2 + NFS3_SIZEOF_FATTR3 + 1 + 2 + 1 + 2 + 1 + 1) * \
3093                 BYTES_PER_XDR_UNIT + roundup((length), BYTES_PER_XDR_UNIT))
3094 
3095 /* ARGSUSED */
3096 void
3097 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3098     struct svc_req *req, cred_t *cr, bool_t ro)
3099 {
3100         int error;
3101         vnode_t *vp;
3102         struct vattr *vap;
3103         struct vattr va;
3104         struct iovec iov;
3105         struct uio uio;
3106         char *data;
3107         int iseof;
3108         int bufsize;
3109         int namlen;
3110         uint_t count;
3111         struct sockaddr *ca;
3112 
3113         vap = NULL;
3114 
3115         vp = nfs3_fhtovp(&args->dir, exi);
3116 
3117         DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
3118             cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
3119 
3120         if (vp == NULL) {
3121                 error = ESTALE;
3122                 goto out;
3123         }
3124 
3125         if (is_system_labeled()) {
3126                 bslabel_t *clabel = req->rq_label;
3127 
3128                 ASSERT(clabel != NULL);
3129                 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3130                     "got client label from request(1)", struct svc_req *, req);
3131 
3132                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3133                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3134                             exi)) {
3135                                 resp->status = NFS3ERR_ACCES;
3136                                 goto out1;
3137                         }
3138                 }
3139         }
3140 
3141         (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3142 
3143         va.va_mask = AT_ALL;
3144         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3145 
3146         if (vp->v_type != VDIR) {
3147                 resp->status = NFS3ERR_NOTDIR;
3148                 goto out1;
3149         }
3150 
3151         error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3152         if (error)
3153                 goto out;
3154 
3155         /*
3156          * Now don't allow arbitrary count to alloc;
3157          * allow the maximum not to exceed rfs3_tsize()
3158          */
3159         if (args->count > rfs3_tsize(req))
3160                 args->count = rfs3_tsize(req);
3161 
3162         /*
3163          * Make sure that there is room to read at least one entry
3164          * if any are available.
3165          */
3166         if (args->count < DIRENT64_RECLEN(MAXNAMELEN))
3167                 count = DIRENT64_RECLEN(MAXNAMELEN);
3168         else
3169                 count = args->count;
3170 
3171         data = kmem_alloc(count, KM_SLEEP);
3172 
3173         iov.iov_base = data;
3174         iov.iov_len = count;
3175         uio.uio_iov = &iov;
3176         uio.uio_iovcnt = 1;
3177         uio.uio_segflg = UIO_SYSSPACE;
3178         uio.uio_extflg = UIO_COPY_CACHED;
3179         uio.uio_loffset = (offset_t)args->cookie;
3180         uio.uio_resid = count;
3181 
3182         error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3183 
3184         va.va_mask = AT_ALL;
3185         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3186 
3187         if (error) {
3188                 kmem_free(data, count);
3189                 goto out;
3190         }
3191 
3192         /*
3193          * If the count was not large enough to be able to guarantee
3194          * to be able to return at least one entry, then need to
3195          * check to see if NFS3ERR_TOOSMALL should be returned.
3196          */
3197         if (args->count < NFS3_READDIR_MIN_COUNT(MAXNAMELEN)) {
3198                 /*
3199                  * bufsize is used to keep track of the size of the response.
3200                  * It is primed with:
3201                  *      1 for the status +
3202                  *      1 for the dir_attributes.attributes boolean +
3203                  *      2 for the cookie verifier
3204                  * all times BYTES_PER_XDR_UNIT to convert from XDR units
3205                  * to bytes.  If there are directory attributes to be
3206                  * returned, then:
3207                  *      NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3208                  * time BYTES_PER_XDR_UNIT is added to account for them.
3209                  */
3210                 bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3211                 if (vap != NULL)
3212                         bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3213                 /*
3214                  * An entry is composed of:
3215                  *      1 for the true/false list indicator +
3216                  *      2 for the fileid +
3217                  *      1 for the length of the name +
3218                  *      2 for the cookie +
3219                  * all times BYTES_PER_XDR_UNIT to convert from
3220                  * XDR units to bytes, plus the length of the name
3221                  * rounded up to the nearest BYTES_PER_XDR_UNIT.
3222                  */
3223                 if (count != uio.uio_resid) {
3224                         namlen = strlen(((struct dirent64 *)data)->d_name);
3225                         bufsize += (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3226                             roundup(namlen, BYTES_PER_XDR_UNIT);
3227                 }
3228                 /*
3229                  * We need to check to see if the number of bytes left
3230                  * to go into the buffer will actually fit into the
3231                  * buffer.  This is calculated as the size of this
3232                  * entry plus:
3233                  *      1 for the true/false list indicator +
3234                  *      1 for the eof indicator
3235                  * times BYTES_PER_XDR_UNIT to convert from from
3236                  * XDR units to bytes.
3237                  */
3238                 bufsize += (1 + 1) * BYTES_PER_XDR_UNIT;
3239                 if (bufsize > args->count) {
3240                         kmem_free(data, count);
3241                         resp->status = NFS3ERR_TOOSMALL;
3242                         goto out1;
3243                 }
3244         }
3245 
3246         /*
3247          * Have a valid readir buffer for the native character
3248          * set. Need to check if a conversion is necessary and
3249          * potentially rewrite the whole buffer. Note that if the
3250          * conversion expands names enough, the structure may not
3251          * fit. In this case, we need to drop entries until if fits
3252          * and patch the counts in order that the next readdir will
3253          * get the correct entries.
3254          */
3255         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3256         data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
3257 
3258 
3259         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3260 
3261 #if 0 /* notyet */
3262         /*
3263          * Don't do this.  It causes local disk writes when just
3264          * reading the file and the overhead is deemed larger
3265          * than the benefit.
3266          */
3267         /*
3268          * Force modified metadata out to stable storage.
3269          */
3270         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3271 #endif
3272 
3273         resp->status = NFS3_OK;
3274         vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3275         resp->resok.cookieverf = 0;
3276         resp->resok.reply.entries = (entry3 *)data;
3277         resp->resok.reply.eof = iseof;
3278         resp->resok.size = count - uio.uio_resid;
3279         resp->resok.count = args->count;
3280         resp->resok.freecount = count;
3281 
3282         DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3283             cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3284 
3285         VN_RELE(vp);
3286 
3287         return;
3288 
3289 out:
3290         if (curthread->t_flag & T_WOULDBLOCK) {
3291                 curthread->t_flag &= ~T_WOULDBLOCK;
3292                 resp->status = NFS3ERR_JUKEBOX;
3293         } else
3294                 resp->status = puterrno3(error);
3295 out1:
3296         DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3297             cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3298 
3299         if (vp != NULL) {
3300                 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3301                 VN_RELE(vp);
3302         }
3303         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3304 }
3305 
3306 void *
3307 rfs3_readdir_getfh(READDIR3args *args)
3308 {
3309 
3310         return (&args->dir);
3311 }
3312 
3313 void
3314 rfs3_readdir_free(READDIR3res *resp)
3315 {
3316 
3317         if (resp->status == NFS3_OK)
3318                 kmem_free(resp->resok.reply.entries, resp->resok.freecount);
3319 }
3320 
3321 #ifdef nextdp
3322 #undef nextdp
3323 #endif
3324 #define nextdp(dp)      ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3325 
3326 /*
3327  * This macro computes the size of a response which contains
3328  * one directory entry including the attributes as well as file handle.
3329  * If the incoming request is larger than this, then we are guaranteed to be
3330  * able to return at least one more directory entry if one exists.
3331  *
3332  * NFS3_READDIRPLUS_ENTRY is made up of the following:
3333  *
3334  * boolean - 1 * BYTES_PER_XDR_UNIT
3335  * file id - 2 * BYTES_PER_XDR_UNIT
3336  * directory name length - 1 * BYTES_PER_XDR_UNIT
3337  * cookie - 2 * BYTES_PER_XDR_UNIT
3338  * attribute flag - 1 * BYTES_PER_XDR_UNIT
3339  * attributes - NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT
3340  * status byte for file handle - 1 *  BYTES_PER_XDR_UNIT
3341  * length of a file handle - 1 * BYTES_PER_XDR_UNIT
3342  * Maximum length of a file handle (NFS3_MAXFHSIZE)
3343  * name length of the entry to the nearest bytes
3344  */
3345 #define NFS3_READDIRPLUS_ENTRY(namelen) \
3346         ((1 + 2 + 1 + 2 + 1 + NFS3_SIZEOF_FATTR3 + 1 + 1) * \
3347                 BYTES_PER_XDR_UNIT + \
3348         NFS3_MAXFHSIZE + roundup(namelen, BYTES_PER_XDR_UNIT))
3349 
3350 static int rfs3_readdir_unit = MAXBSIZE;
3351 
3352 /* ARGSUSED */
3353 void
3354 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
3355     struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
3356 {
3357         int error;
3358         vnode_t *vp;
3359         struct vattr *vap;
3360         struct vattr va;
3361         struct iovec iov;
3362         struct uio uio;
3363         char *data;
3364         int iseof;
3365         struct dirent64 *dp;
3366         vnode_t *nvp;
3367         struct vattr *nvap;
3368         struct vattr nva;
3369         entryplus3_info *infop = NULL;
3370         int size = 0;
3371         int nents = 0;
3372         int bufsize = 0;
3373         int entrysize = 0;
3374         int tofit = 0;
3375         int rd_unit = rfs3_readdir_unit;
3376         int prev_len;
3377         int space_left;
3378         int i;
3379         uint_t *namlen = NULL;
3380         char *ndata = NULL;
3381         struct sockaddr *ca;
3382         size_t ret;
3383 
3384         vap = NULL;
3385 
3386         vp = nfs3_fhtovp(&args->dir, exi);
3387 
3388         DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
3389             cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
3390 
3391         if (vp == NULL) {
3392                 error = ESTALE;
3393                 goto out;
3394         }
3395 
3396         if (is_system_labeled()) {
3397                 bslabel_t *clabel = req->rq_label;
3398 
3399                 ASSERT(clabel != NULL);
3400                 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3401                     char *, "got client label from request(1)",
3402                     struct svc_req *, req);
3403 
3404                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3405                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3406                             exi)) {
3407                                 resp->status = NFS3ERR_ACCES;
3408                                 goto out1;
3409                         }
3410                 }
3411         }
3412 
3413         (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3414 
3415         va.va_mask = AT_ALL;
3416         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3417 
3418         if (vp->v_type != VDIR) {
3419                 error = ENOTDIR;
3420                 goto out;
3421         }
3422 
3423         error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3424         if (error)
3425                 goto out;
3426 
3427         /*
3428          * Don't allow arbitrary counts for allocation
3429          */
3430         if (args->maxcount > rfs3_tsize(req))
3431                 args->maxcount = rfs3_tsize(req);
3432 
3433         /*
3434          * Make sure that there is room to read at least one entry
3435          * if any are available
3436          */
3437         args->dircount = MIN(args->dircount, args->maxcount);
3438 
3439         if (args->dircount < DIRENT64_RECLEN(MAXNAMELEN))
3440                 args->dircount = DIRENT64_RECLEN(MAXNAMELEN);
3441 
3442         /*
3443          * This allocation relies on a minimum directory entry
3444          * being roughly 24 bytes.  Therefore, the namlen array
3445          * will have enough space based on the maximum number of
3446          * entries to read.
3447          */
3448         namlen = kmem_alloc(args->dircount, KM_SLEEP);
3449 
3450         space_left = args->dircount;
3451         data = kmem_alloc(args->dircount, KM_SLEEP);
3452         dp = (struct dirent64 *)data;
3453         uio.uio_iov = &iov;
3454         uio.uio_iovcnt = 1;
3455         uio.uio_segflg = UIO_SYSSPACE;
3456         uio.uio_extflg = UIO_COPY_CACHED;
3457         uio.uio_loffset = (offset_t)args->cookie;
3458 
3459         /*
3460          * bufsize is used to keep track of the size of the response as we
3461          * get post op attributes and filehandles for each entry.  This is
3462          * an optimization as the server may have read more entries than will
3463          * fit in the buffer specified by maxcount.  We stop calculating
3464          * post op attributes and filehandles once we have exceeded maxcount.
3465          * This will minimize the effect of truncation.
3466          *
3467          * It is primed with:
3468          *      1 for the status +
3469          *      1 for the dir_attributes.attributes boolean +
3470          *      2 for the cookie verifier
3471          * all times BYTES_PER_XDR_UNIT to convert from XDR units
3472          * to bytes.  If there are directory attributes to be
3473          * returned, then:
3474          *      NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
3475          * time BYTES_PER_XDR_UNIT is added to account for them.
3476          */
3477         bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
3478         if (vap != NULL)
3479                 bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3480 
3481 getmoredents:
3482         /*
3483          * Here we make a check so that our read unit is not larger than
3484          * the space left in the buffer.
3485          */
3486         rd_unit = MIN(rd_unit, space_left);
3487         iov.iov_base = (char *)dp;
3488         iov.iov_len = rd_unit;
3489         uio.uio_resid = rd_unit;
3490         prev_len = rd_unit;
3491 
3492         error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3493 
3494         if (error) {
3495                 kmem_free(data, args->dircount);
3496                 goto out;
3497         }
3498 
3499         if (uio.uio_resid == prev_len && !iseof) {
3500                 if (nents == 0) {
3501                         kmem_free(data, args->dircount);
3502                         resp->status = NFS3ERR_TOOSMALL;
3503                         goto out1;
3504                 }
3505 
3506                 /*
3507                  * We could not get any more entries, so get the attributes
3508                  * and filehandle for the entries already obtained.
3509                  */
3510                 goto good;
3511         }
3512 
3513         /*
3514          * We estimate the size of the response by assuming the
3515          * entry exists and attributes and filehandle are also valid
3516          */
3517         for (size = prev_len - uio.uio_resid;
3518             size > 0;
3519             size -= dp->d_reclen, dp = nextdp(dp)) {
3520 
3521                 if (dp->d_ino == 0) {
3522                         nents++;
3523                         continue;
3524                 }
3525 
3526                 namlen[nents] = strlen(dp->d_name);
3527                 entrysize = NFS3_READDIRPLUS_ENTRY(namlen[nents]);
3528 
3529                 /*
3530                  * We need to check to see if the number of bytes left
3531                  * to go into the buffer will actually fit into the
3532                  * buffer.  This is calculated as the size of this
3533                  * entry plus:
3534                  *      1 for the true/false list indicator +
3535                  *      1 for the eof indicator
3536                  * times BYTES_PER_XDR_UNIT to convert from XDR units
3537                  * to bytes.
3538                  *
3539                  * Also check the dircount limit against the first entry read
3540                  *
3541                  */
3542                 tofit = entrysize + (1 + 1) * BYTES_PER_XDR_UNIT;
3543                 if (bufsize + tofit > args->maxcount) {
3544                         /*
3545                          * We make a check here to see if this was the
3546                          * first entry being measured.  If so, then maxcount
3547                          * was too small to begin with and so we need to
3548                          * return with NFS3ERR_TOOSMALL.
3549                          */
3550                         if (nents == 0) {
3551                                 kmem_free(data, args->dircount);
3552                                 resp->status = NFS3ERR_TOOSMALL;
3553                                 goto out1;
3554                         }
3555                         iseof = FALSE;
3556                         goto good;
3557                 }
3558                 bufsize += entrysize;
3559                 nents++;
3560         }
3561 
3562         /*
3563          * If there is enough room to fit at least 1 more entry including
3564          * post op attributes and filehandle in the buffer AND that we haven't
3565          * exceeded dircount then go back and get some more.
3566          */
3567         if (!iseof &&
3568             (args->maxcount - bufsize) >= NFS3_READDIRPLUS_ENTRY(MAXNAMELEN)) {
3569                 space_left -= (prev_len - uio.uio_resid);
3570                 if (space_left >= DIRENT64_RECLEN(MAXNAMELEN))
3571                         goto getmoredents;
3572 
3573                 /* else, fall through */
3574         }
3575 good:
3576         va.va_mask = AT_ALL;
3577         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3578 
3579         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3580 
3581         infop = kmem_alloc(nents * sizeof (struct entryplus3_info), KM_SLEEP);
3582         resp->resok.infop = infop;
3583 
3584         dp = (struct dirent64 *)data;
3585         for (i = 0; i < nents; i++) {
3586 
3587                 if (dp->d_ino == 0) {
3588                         infop[i].attr.attributes = FALSE;
3589                         infop[i].fh.handle_follows = FALSE;
3590                         dp = nextdp(dp);
3591                         continue;
3592                 }
3593 
3594                 infop[i].namelen = namlen[i];
3595 
3596                 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3597                     NULL, NULL, NULL);
3598                 if (error) {
3599                         infop[i].attr.attributes = FALSE;
3600                         infop[i].fh.handle_follows = FALSE;
3601                         dp = nextdp(dp);
3602                         continue;
3603                 }
3604 
3605                 nva.va_mask = AT_ALL;
3606                 nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL : &nva;
3607 
3608                 /* Lie about the object type for a referral */
3609                 if (vn_is_nfs_reparse(nvp, cr))
3610                         nvap->va_type = VLNK;
3611 
3612                 vattr_to_post_op_attr(nvap, &infop[i].attr);
3613 
3614                 error = makefh3(&infop[i].fh.handle, nvp, exi);
3615                 if (!error)
3616                         infop[i].fh.handle_follows = TRUE;
3617                 else
3618                         infop[i].fh.handle_follows = FALSE;
3619 
3620                 VN_RELE(nvp);
3621                 dp = nextdp(dp);
3622         }
3623 
3624         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3625         ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
3626         if (ndata == NULL)
3627                 ndata = data;
3628 
3629         if (ret > 0) {
3630                 /*
3631                  * We had to drop one or more entries in order to fit
3632                  * during the character conversion.  We need to patch
3633                  * up the size and eof info.
3634                  */
3635                 if (iseof)
3636                         iseof = FALSE;
3637 
3638                 ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
3639                     nents, ret);
3640         }
3641 
3642 
3643 #if 0 /* notyet */
3644         /*
3645          * Don't do this.  It causes local disk writes when just
3646          * reading the file and the overhead is deemed larger
3647          * than the benefit.
3648          */
3649         /*
3650          * Force modified metadata out to stable storage.
3651          */
3652         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3653 #endif
3654 
3655         kmem_free(namlen, args->dircount);
3656 
3657         resp->status = NFS3_OK;
3658         vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3659         resp->resok.cookieverf = 0;
3660         resp->resok.reply.entries = (entryplus3 *)ndata;
3661         resp->resok.reply.eof = iseof;
3662         resp->resok.size = nents;
3663         resp->resok.count = args->dircount - ret;
3664         resp->resok.maxcount = args->maxcount;
3665 
3666         DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3667             cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3668         if (ndata != data)
3669                 kmem_free(data, args->dircount);
3670 
3671 
3672         VN_RELE(vp);
3673 
3674         return;
3675 
3676 out:
3677         if (curthread->t_flag & T_WOULDBLOCK) {
3678                 curthread->t_flag &= ~T_WOULDBLOCK;
3679                 resp->status = NFS3ERR_JUKEBOX;
3680         } else {
3681                 resp->status = puterrno3(error);
3682         }
3683 out1:
3684         DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3685             cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3686 
3687         if (vp != NULL) {
3688                 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3689                 VN_RELE(vp);
3690         }
3691 
3692         if (namlen != NULL)
3693                 kmem_free(namlen, args->dircount);
3694 
3695         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3696 }
3697 
3698 void *
3699 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3700 {
3701 
3702         return (&args->dir);
3703 }
3704 
3705 void
3706 rfs3_readdirplus_free(READDIRPLUS3res *resp)
3707 {
3708 
3709         if (resp->status == NFS3_OK) {
3710                 kmem_free(resp->resok.reply.entries, resp->resok.count);
3711                 kmem_free(resp->resok.infop,
3712                     resp->resok.size * sizeof (struct entryplus3_info));
3713         }
3714 }
3715 
3716 /* ARGSUSED */
3717 void
3718 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3719     struct svc_req *req, cred_t *cr, bool_t ro)
3720 {
3721         int error;
3722         vnode_t *vp;
3723         struct vattr *vap;
3724         struct vattr va;
3725         struct statvfs64 sb;
3726 
3727         vap = NULL;
3728 
3729         vp = nfs3_fhtovp(&args->fsroot, exi);
3730 
3731         DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
3732             cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
3733 
3734         if (vp == NULL) {
3735                 error = ESTALE;
3736                 goto out;
3737         }
3738 
3739         if (is_system_labeled()) {
3740                 bslabel_t *clabel = req->rq_label;
3741 
3742                 ASSERT(clabel != NULL);
3743                 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3744                     "got client label from request(1)", struct svc_req *, req);
3745 
3746                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3747                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3748                             exi)) {
3749                                 resp->status = NFS3ERR_ACCES;
3750                                 goto out1;
3751                         }
3752                 }
 
3762 
3763         resp->status = NFS3_OK;
3764         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3765         if (sb.f_blocks != (fsblkcnt64_t)-1)
3766                 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3767         else
3768                 resp->resok.tbytes = (size3)sb.f_blocks;
3769         if (sb.f_bfree != (fsblkcnt64_t)-1)
3770                 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3771         else
3772                 resp->resok.fbytes = (size3)sb.f_bfree;
3773         if (sb.f_bavail != (fsblkcnt64_t)-1)
3774                 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3775         else
3776                 resp->resok.abytes = (size3)sb.f_bavail;
3777         resp->resok.tfiles = (size3)sb.f_files;
3778         resp->resok.ffiles = (size3)sb.f_ffree;
3779         resp->resok.afiles = (size3)sb.f_favail;
3780         resp->resok.invarsec = 0;
3781 
3782         DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3783             cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3784         VN_RELE(vp);
3785 
3786         return;
3787 
3788 out:
3789         if (curthread->t_flag & T_WOULDBLOCK) {
3790                 curthread->t_flag &= ~T_WOULDBLOCK;
3791                 resp->status = NFS3ERR_JUKEBOX;
3792         } else
3793                 resp->status = puterrno3(error);
3794 out1:
3795         DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3796             cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3797 
3798         if (vp != NULL)
3799                 VN_RELE(vp);
3800         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3801 }
3802 
3803 void *
3804 rfs3_fsstat_getfh(FSSTAT3args *args)
3805 {
3806 
3807         return (&args->fsroot);
3808 }
3809 
3810 /* ARGSUSED */
3811 void
3812 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3813     struct svc_req *req, cred_t *cr, bool_t ro)
3814 {
3815         vnode_t *vp;
3816         struct vattr *vap;
3817         struct vattr va;
3818         uint32_t xfer_size;
3819         ulong_t l = 0;
3820         int error;
3821 
3822         vp = nfs3_fhtovp(&args->fsroot, exi);
3823 
3824         DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
3825             cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
3826 
3827         if (vp == NULL) {
3828                 if (curthread->t_flag & T_WOULDBLOCK) {
3829                         curthread->t_flag &= ~T_WOULDBLOCK;
3830                         resp->status = NFS3ERR_JUKEBOX;
3831                 } else
3832                         resp->status = NFS3ERR_STALE;
3833                 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3834                 goto out;
3835         }
3836 
3837         if (is_system_labeled()) {
3838                 bslabel_t *clabel = req->rq_label;
3839 
3840                 ASSERT(clabel != NULL);
3841                 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3842                     "got client label from request(1)", struct svc_req *, req);
3843 
3844                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3845                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
 
3879         /*
3880          * If the underlying file system does not support _PC_FILESIZEBITS,
3881          * return a reasonable default. Note that error code on VOP_PATHCONF
3882          * will be 0, even if the underlying file system does not support
3883          * _PC_FILESIZEBITS.
3884          */
3885         if (l == (ulong_t)-1) {
3886                 resp->resok.maxfilesize = MAXOFF32_T;
3887         } else {
3888                 if (l >= (sizeof (uint64_t) * 8))
3889                         resp->resok.maxfilesize = INT64_MAX;
3890                 else
3891                         resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3892         }
3893 
3894         resp->resok.time_delta.seconds = 0;
3895         resp->resok.time_delta.nseconds = 1000;
3896         resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3897             FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3898 
3899         DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3900             cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
3901 
3902         VN_RELE(vp);
3903 
3904         return;
3905 
3906 out:
3907         DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3908             cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
3909         if (vp != NULL)
3910                 VN_RELE(vp);
3911 }
3912 
3913 void *
3914 rfs3_fsinfo_getfh(FSINFO3args *args)
3915 {
3916         return (&args->fsroot);
3917 }
3918 
3919 /* ARGSUSED */
3920 void
3921 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
3922     struct svc_req *req, cred_t *cr, bool_t ro)
3923 {
3924         int error;
3925         vnode_t *vp;
3926         struct vattr *vap;
3927         struct vattr va;
3928         ulong_t val;
3929 
3930         vap = NULL;
3931 
3932         vp = nfs3_fhtovp(&args->object, exi);
3933 
3934         DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
3935             cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
3936 
3937         if (vp == NULL) {
3938                 error = ESTALE;
3939                 goto out;
3940         }
3941 
3942         if (is_system_labeled()) {
3943                 bslabel_t *clabel = req->rq_label;
3944 
3945                 ASSERT(clabel != NULL);
3946                 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
3947                     "got client label from request(1)", struct svc_req *, req);
3948 
3949                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3950                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3951                             exi)) {
3952                                 resp->status = NFS3ERR_ACCES;
3953                                 goto out1;
3954                         }
3955                 }
 
3971         error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
3972         if (error)
3973                 goto out;
3974         if (val == 1)
3975                 resp->resok.info.no_trunc = TRUE;
3976         else
3977                 resp->resok.info.no_trunc = FALSE;
3978 
3979         error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
3980         if (error)
3981                 goto out;
3982         if (val == 1)
3983                 resp->resok.info.chown_restricted = TRUE;
3984         else
3985                 resp->resok.info.chown_restricted = FALSE;
3986 
3987         resp->status = NFS3_OK;
3988         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3989         resp->resok.info.case_insensitive = FALSE;
3990         resp->resok.info.case_preserving = TRUE;
3991         DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
3992             cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
3993         VN_RELE(vp);
3994         return;
3995 
3996 out:
3997         if (curthread->t_flag & T_WOULDBLOCK) {
3998                 curthread->t_flag &= ~T_WOULDBLOCK;
3999                 resp->status = NFS3ERR_JUKEBOX;
4000         } else
4001                 resp->status = puterrno3(error);
4002 out1:
4003         DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4004             cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
4005         if (vp != NULL)
4006                 VN_RELE(vp);
4007         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4008 }
4009 
4010 void *
4011 rfs3_pathconf_getfh(PATHCONF3args *args)
4012 {
4013 
4014         return (&args->object);
4015 }
4016 
4017 void
4018 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4019     struct svc_req *req, cred_t *cr, bool_t ro)
4020 {
4021         int error;
4022         vnode_t *vp;
4023         struct vattr *bvap;
4024         struct vattr bva;
4025         struct vattr *avap;
4026         struct vattr ava;
4027 
4028         bvap = NULL;
4029         avap = NULL;
4030 
4031         vp = nfs3_fhtovp(&args->file, exi);
4032 
4033         DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
4034             cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
4035 
4036         if (vp == NULL) {
4037                 error = ESTALE;
4038                 goto out;
4039         }
4040 
4041         bva.va_mask = AT_ALL;
4042         error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4043 
4044         /*
4045          * If we can't get the attributes, then we can't do the
4046          * right access checking.  So, we'll fail the request.
4047          */
4048         if (error)
4049                 goto out;
4050 
4051         bvap = &bva;
4052 
4053         if (rdonly(ro, vp)) {
4054                 resp->status = NFS3ERR_ROFS;
4055                 goto out1;
4056         }
4057 
4058         if (vp->v_type != VREG) {
4059                 resp->status = NFS3ERR_INVAL;
4060                 goto out1;
 
4073                                 resp->status = NFS3ERR_ACCES;
4074                                 goto out1;
4075                         }
4076                 }
4077         }
4078 
4079         if (crgetuid(cr) != bva.va_uid &&
4080             (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4081                 goto out;
4082 
4083         error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4084 
4085         ava.va_mask = AT_ALL;
4086         avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4087 
4088         if (error)
4089                 goto out;
4090 
4091         resp->status = NFS3_OK;
4092         vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4093         resp->resok.verf = write3verf;
4094 
4095         DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4096             cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4097 
4098         VN_RELE(vp);
4099 
4100         return;
4101 
4102 out:
4103         if (curthread->t_flag & T_WOULDBLOCK) {
4104                 curthread->t_flag &= ~T_WOULDBLOCK;
4105                 resp->status = NFS3ERR_JUKEBOX;
4106         } else
4107                 resp->status = puterrno3(error);
4108 out1:
4109         DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4110             cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4111 
4112         if (vp != NULL)
4113                 VN_RELE(vp);
4114         vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4115 }
4116 
4117 void *
4118 rfs3_commit_getfh(COMMIT3args *args)
4119 {
4120 
4121         return (&args->file);
4122 }
4123 
4124 static int
4125 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4126 {
4127 
4128         vap->va_mask = 0;
4129 
4130         if (sap->mode.set_it) {
4131                 vap->va_mode = (mode_t)sap->mode.mode;
4132                 vap->va_mask |= AT_MODE;
4133         }
4134         if (sap->uid.set_it) {
4135                 vap->va_uid = (uid_t)sap->uid.uid;
4136                 vap->va_mask |= AT_UID;
4137         }
4138         if (sap->gid.set_it) {
4139                 vap->va_gid = (gid_t)sap->gid.gid;
4140                 vap->va_mask |= AT_GID;
 
4168                 /* check time validity */
4169                 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4170                         return (EOVERFLOW);
4171 #endif
4172                 /*
4173                  * nfs protocol defines times as unsigned so don't extend sign,
4174                  * unless sysadmin set nfs_allow_preepoch_time.
4175                  */
4176                 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4177                     sap->mtime.mtime.seconds);
4178                 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4179                 vap->va_mask |= AT_MTIME;
4180         } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4181                 gethrestime(&vap->va_mtime);
4182                 vap->va_mask |= AT_MTIME;
4183         }
4184 
4185         return (0);
4186 }
4187 
4188 static ftype3 vt_to_nf3[] = {
4189         0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4190 };
4191 
4192 static int
4193 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4194 {
4195 
4196         ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4197         /* Return error if time or size overflow */
4198         if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4199                 return (EOVERFLOW);
4200         }
4201         fap->type = vt_to_nf3[vap->va_type];
4202         fap->mode = (mode3)(vap->va_mode & MODEMASK);
4203         fap->nlink = (uint32)vap->va_nlink;
4204         if (vap->va_uid == UID_NOBODY)
4205                 fap->uid = (uid3)NFS_UID_NOBODY;
4206         else
4207                 fap->uid = (uid3)vap->va_uid;
4208         if (vap->va_gid == GID_NOBODY)
 
4250         if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4251                 poap->attributes = TRUE;
4252         } else
4253                 poap->attributes = FALSE;
4254 }
4255 
4256 void
4257 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4258 {
4259 
4260         /* don't return attrs if time overflow */
4261         if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4262                 poap->attributes = TRUE;
4263         } else
4264                 poap->attributes = FALSE;
4265 }
4266 
4267 static void
4268 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4269 {
4270 
4271         vattr_to_pre_op_attr(bvap, &wccp->before);
4272         vattr_to_post_op_attr(avap, &wccp->after);
4273 }
4274 
4275 void
4276 rfs3_srvrinit(void)
4277 {
4278         struct rfs3_verf_overlay {
4279                 uint_t id; /* a "unique" identifier */
4280                 int ts; /* a unique timestamp */
4281         } *verfp;
4282         timestruc_t now;
4283 
4284         /*
4285          * The following algorithm attempts to find a unique verifier
4286          * to be used as the write verifier returned from the server
4287          * to the client.  It is important that this verifier change
4288          * whenever the server reboots.  Of secondary importance, it
4289          * is important for the verifier to be unique between two
4290          * different servers.
4291          *
4292          * Thus, an attempt is made to use the system hostid and the
4293          * current time in seconds when the nfssrv kernel module is
4294          * loaded.  It is assumed that an NFS server will not be able
4295          * to boot and then to reboot in less than a second.  If the
4296          * hostid has not been set, then the current high resolution
4297          * time is used.  This will ensure different verifiers each
4298          * time the server reboots and minimize the chances that two
4299          * different servers will have the same verifier.
4300          */
4301 
4302 #ifndef lint
4303         /*
4304          * We ASSERT that this constant logic expression is
4305          * always true because in the past, it wasn't.
4306          */
4307         ASSERT(sizeof (*verfp) <= sizeof (write3verf));
4308 #endif
4309 
4310         gethrestime(&now);
4311         verfp = (struct rfs3_verf_overlay *)&write3verf;
4312         verfp->ts = (int)now.tv_sec;
4313         verfp->id = zone_get_hostid(NULL);
4314 
4315         if (verfp->id == 0)
4316                 verfp->id = (uint_t)now.tv_nsec;
4317 
4318         nfs3_srv_caller_id = fs_new_caller_id();
4319 
4320 }
4321 
4322 static int
4323 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4324 {
4325         struct clist    *wcl;
4326         int             wlist_len;
4327         count3          count = rok->count;
4328 
4329         wcl = args->wlist;
4330         if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
4331                 return (FALSE);
4332         }
4333 
4334         wcl = args->wlist;
4335         rok->wlist_len = wlist_len;
4336         rok->wlist = wcl;
4337         return (TRUE);
4338 }
4339 
4340 void
4341 rfs3_srvrfini(void)
4342 {
4343         /* Nothing to do */
4344 }
 | 
 
 
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   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 2018 Nexenta Systems, Inc.
  24  * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
  25  * Copyright (c) 2013 by Delphix. All rights reserved.
  26  */
  27 
  28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  29 /* All Rights Reserved */
  30 
  31 
  32 #include <sys/param.h>
  33 #include <sys/types.h>
  34 #include <sys/systm.h>
  35 #include <sys/cred.h>
  36 #include <sys/buf.h>
  37 #include <sys/vfs.h>
  38 #include <sys/vnode.h>
  39 #include <sys/uio.h>
  40 #include <sys/errno.h>
  41 #include <sys/sysmacros.h>
  42 #include <sys/statvfs.h>
  43 #include <sys/kmem.h>
  44 #include <sys/dirent.h>
  45 #include <sys/cmn_err.h>
  46 #include <sys/debug.h>
  47 #include <sys/systeminfo.h>
  48 #include <sys/flock.h>
  49 #include <sys/nbmlock.h>
  50 #include <sys/policy.h>
  51 #include <sys/sdt.h>
  52 
  53 #include <rpc/types.h>
  54 #include <rpc/auth.h>
  55 #include <rpc/svc.h>
  56 #include <rpc/rpc_rdma.h>
  57 
  58 #include <nfs/nfs.h>
  59 #include <nfs/export.h>
  60 #include <nfs/nfs_cmd.h>
  61 
  62 #include <sys/strsubr.h>
  63 #include <sys/tsol/label.h>
  64 #include <sys/tsol/tndb.h>
  65 
  66 #include <sys/zone.h>
  67 
  68 #include <inet/ip.h>
  69 #include <inet/ip6.h>
  70 
  71 /*
  72  * Zone global variables of NFSv3 server
  73  */
  74 typedef struct nfs3_srv {
  75         writeverf3      write3verf;
  76 } nfs3_srv_t;
  77 
  78 /*
  79  * These are the interface routines for the server side of the
  80  * Network File System.  See the NFS version 3 protocol specification
  81  * for a description of this interface.
  82  */
  83 
  84 static int      sattr3_to_vattr(sattr3 *, struct vattr *);
  85 static int      vattr_to_fattr3(struct vattr *, fattr3 *);
  86 static int      vattr_to_wcc_attr(struct vattr *, wcc_attr *);
  87 static void     vattr_to_pre_op_attr(struct vattr *, pre_op_attr *);
  88 static void     vattr_to_wcc_data(struct vattr *, struct vattr *, wcc_data *);
  89 static int      rdma_setup_read_data3(READ3args *, READ3resok *);
  90 
  91 extern int nfs_loaned_buffers;
  92 
  93 u_longlong_t nfs3_srv_caller_id;
  94 static zone_key_t rfs3_zone_key;
  95 
  96 /* ARGSUSED */
  97 void
  98 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
  99     struct svc_req *req, cred_t *cr, bool_t ro)
 100 {
 101         int error;
 102         vnode_t *vp;
 103         struct vattr va;
 104 
 105         vp = nfs3_fhtovp(&args->object, exi);
 106 
 107         DTRACE_NFSV3_5(op__getattr__start, struct svc_req *, req,
 108             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 109             GETATTR3args *, args);
 110 
 111         if (vp == NULL) {
 112                 error = ESTALE;
 113                 goto out;
 114         }
 115 
 116         va.va_mask = AT_ALL;
 117         error = rfs4_delegated_getattr(vp, &va, 0, cr);
 118 
 119         if (!error) {
 120                 /* Lie about the object type for a referral */
 121                 if (vn_is_nfs_reparse(vp, cr))
 122                         va.va_type = VLNK;
 123 
 124                 /* overflow error if time or size is out of range */
 125                 error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
 126                 if (error)
 127                         goto out;
 128                 resp->status = NFS3_OK;
 129 
 130                 DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
 131                     cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 132                     GETATTR3res *, resp);
 133 
 134                 VN_RELE(vp);
 135 
 136                 return;
 137         }
 138 
 139 out:
 140         if (curthread->t_flag & T_WOULDBLOCK) {
 141                 curthread->t_flag &= ~T_WOULDBLOCK;
 142                 resp->status = NFS3ERR_JUKEBOX;
 143         } else
 144                 resp->status = puterrno3(error);
 145 
 146         DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
 147             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 148             GETATTR3res *, resp);
 149 
 150         if (vp != NULL)
 151                 VN_RELE(vp);
 152 }
 153 
 154 void *
 155 rfs3_getattr_getfh(GETATTR3args *args)
 156 {
 157         return (&args->object);
 158 }
 159 
 160 void
 161 rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
 162     struct svc_req *req, cred_t *cr, bool_t ro)
 163 {
 164         int error;
 165         vnode_t *vp;
 166         struct vattr *bvap;
 167         struct vattr bva;
 168         struct vattr *avap;
 169         struct vattr ava;
 170         int flag;
 171         int in_crit = 0;
 172         struct flock64 bf;
 173         caller_context_t ct;
 174 
 175         bvap = NULL;
 176         avap = NULL;
 177 
 178         vp = nfs3_fhtovp(&args->object, exi);
 179 
 180         DTRACE_NFSV3_5(op__setattr__start, struct svc_req *, req,
 181             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 182             SETATTR3args *, args);
 183 
 184         if (vp == NULL) {
 185                 error = ESTALE;
 186                 goto out;
 187         }
 188 
 189         error = sattr3_to_vattr(&args->new_attributes, &ava);
 190         if (error)
 191                 goto out;
 192 
 193         if (is_system_labeled()) {
 194                 bslabel_t *clabel = req->rq_label;
 195 
 196                 ASSERT(clabel != NULL);
 197                 DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
 198                     "got client label from request(1)", struct svc_req *, req);
 199 
 200                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
 201                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
 202                             exi)) {
 
 323                 goto out1;
 324         }
 325 
 326         ava.va_mask = AT_ALL;
 327         avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
 328 
 329         /*
 330          * Force modified metadata out to stable storage.
 331          */
 332         (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
 333 
 334         if (error)
 335                 goto out;
 336 
 337         if (in_crit)
 338                 nbl_end_crit(vp);
 339 
 340         resp->status = NFS3_OK;
 341         vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
 342 
 343         DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
 344             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 345             SETATTR3res *, resp);
 346 
 347         VN_RELE(vp);
 348 
 349         return;
 350 
 351 out:
 352         if (curthread->t_flag & T_WOULDBLOCK) {
 353                 curthread->t_flag &= ~T_WOULDBLOCK;
 354                 resp->status = NFS3ERR_JUKEBOX;
 355         } else
 356                 resp->status = puterrno3(error);
 357 out1:
 358         DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
 359             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 360             SETATTR3res *, resp);
 361 
 362         if (vp != NULL) {
 363                 if (in_crit)
 364                         nbl_end_crit(vp);
 365                 VN_RELE(vp);
 366         }
 367         vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
 368 }
 369 
 370 void *
 371 rfs3_setattr_getfh(SETATTR3args *args)
 372 {
 373         return (&args->object);
 374 }
 375 
 376 /* ARGSUSED */
 377 void
 378 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 379     struct svc_req *req, cred_t *cr, bool_t ro)
 380 {
 381         int error;
 382         vnode_t *vp;
 383         vnode_t *dvp;
 384         struct vattr *vap;
 385         struct vattr va;
 386         struct vattr *dvap;
 387         struct vattr dva;
 388         nfs_fh3 *fhp;
 389         struct sec_ol sec = {0, 0};
 390         bool_t publicfh_flag = FALSE, auth_weak = FALSE;
 391         struct sockaddr *ca;
 392         char *name = NULL;
 393 
 394         dvap = NULL;
 395 
 396         if (exi != NULL)
 397                 exi_hold(exi);
 398 
 399         /*
 400          * Allow lookups from the root - the default
 401          * location of the public filehandle.
 402          */
 403         if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
 404                 dvp = ZONE_ROOTVP();
 405                 VN_HOLD(dvp);
 406 
 407                 DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
 408                     cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 409                     LOOKUP3args *, args);
 410         } else {
 411                 dvp = nfs3_fhtovp(&args->what.dir, exi);
 412 
 413                 DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
 414                     cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 415                     LOOKUP3args *, args);
 416 
 417                 if (dvp == NULL) {
 418                         error = ESTALE;
 419                         goto out;
 420                 }
 421         }
 422 
 423         dva.va_mask = AT_ALL;
 424         dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 425 
 426         if (args->what.name == nfs3nametoolong) {
 427                 resp->status = NFS3ERR_NAMETOOLONG;
 428                 goto out1;
 429         }
 430 
 431         if (args->what.name == NULL || *(args->what.name) == '\0') {
 432                 resp->status = NFS3ERR_ACCES;
 433                 goto out1;
 434         }
 435 
 436         fhp = &args->what.dir;
 437         if (strcmp(args->what.name, "..") == 0 &&
 438             EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
 439                 if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
 440                     (dvp->v_flag & VROOT)) {
 441                         /*
 442                          * special case for ".." and 'nohide'exported root
 443                          */
 444                         if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
 445                                 resp->status = NFS3ERR_ACCES;
 446                                 goto out1;
 447                         }
 448                 } else {
 449                         resp->status = NFS3ERR_NOENT;
 450                         goto out1;
 451                 }
 452         }
 453 
 454         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 455         name = nfscmd_convname(ca, exi, args->what.name,
 456             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
 457 
 458         if (name == NULL) {
 459                 resp->status = NFS3ERR_ACCES;
 460                 goto out1;
 461         }
 462 
 463         /*
 464          * If the public filehandle is used then allow
 465          * a multi-component lookup
 466          */
 467         if (PUBLIC_FH3(&args->what.dir)) {
 468                 publicfh_flag = TRUE;
 469 
 470                 exi_rele(&exi);
 471 
 472                 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
 473                     &exi, &sec);
 474 
 475                 /*
 476                  * Since WebNFS may bypass MOUNT, we need to ensure this
 477                  * request didn't come from an unlabeled admin_low client.
 478                  */
 479                 if (is_system_labeled() && error == 0) {
 480                         int             addr_type;
 481                         void            *ipaddr;
 482                         tsol_tpc_t      *tp;
 483 
 484                         if (ca->sa_family == AF_INET) {
 485                                 addr_type = IPV4_VERSION;
 486                                 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
 487                         } else if (ca->sa_family == AF_INET6) {
 488                                 addr_type = IPV6_VERSION;
 489                                 ipaddr = &((struct sockaddr_in6 *)
 490                                     ca)->sin6_addr;
 491                         }
 492                         tp = find_tpc(ipaddr, addr_type, B_FALSE);
 493                         if (tp == NULL || tp->tpc_tp.tp_doi !=
 494                             l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
 495                             SUN_CIPSO) {
 496                                 VN_RELE(vp);
 497                                 error = EACCES;
 498                         }
 499                         if (tp != NULL)
 500                                 TPC_RELE(tp);
 501                 }
 502         } else {
 503                 error = VOP_LOOKUP(dvp, name, &vp,
 504                     NULL, 0, NULL, cr, NULL, NULL, NULL);
 505         }
 506 
 507         if (name != args->what.name)
 508                 kmem_free(name, MAXPATHLEN + 1);
 509 
 510         if (error == 0 && vn_ismntpt(vp)) {
 511                 error = rfs_cross_mnt(&vp, &exi);
 512                 if (error)
 513                         VN_RELE(vp);
 514         }
 515 
 516         if (is_system_labeled() && error == 0) {
 517                 bslabel_t *clabel = req->rq_label;
 518 
 519                 ASSERT(clabel != NULL);
 520                 DTRACE_PROBE2(tx__rfs3__log__info__oplookup__clabel, char *,
 521                     "got client label from request(1)", struct svc_req *, req);
 522 
 523                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
 524                         if (!do_rfs_label_check(clabel, dvp,
 525                             DOMINANCE_CHECK, exi)) {
 526                                 VN_RELE(vp);
 527                                 error = EACCES;
 528                         }
 529                 }
 530         }
 531 
 532         dva.va_mask = AT_ALL;
 533         dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 534 
 535         if (error)
 536                 goto out;
 537 
 538         if (sec.sec_flags & SEC_QUERY) {
 539                 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
 540         } else {
 541                 error = makefh3(&resp->resok.object, vp, exi);
 542                 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
 543                         auth_weak = TRUE;
 544         }
 545 
 546         if (error) {
 547                 VN_RELE(vp);
 548                 goto out;
 549         }
 550 
 551         va.va_mask = AT_ALL;
 552         vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 553 
 554         exi_rele(&exi);
 555         VN_RELE(vp);
 556 
 557         resp->status = NFS3_OK;
 558         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 559         vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
 560 
 561         /*
 562          * If it's public fh, no 0x81, and client's flavor is
 563          * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
 564          * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
 565          */
 566         if (auth_weak)
 567                 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
 568 
 569         DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
 570             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 571             LOOKUP3res *, resp);
 572         VN_RELE(dvp);
 573 
 574         return;
 575 
 576 out:
 577         if (curthread->t_flag & T_WOULDBLOCK) {
 578                 curthread->t_flag &= ~T_WOULDBLOCK;
 579                 resp->status = NFS3ERR_JUKEBOX;
 580         } else
 581                 resp->status = puterrno3(error);
 582 out1:
 583         if (exi != NULL)
 584                 exi_rele(&exi);
 585 
 586         DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
 587             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 588             LOOKUP3res *, resp);
 589 
 590         if (dvp != NULL)
 591                 VN_RELE(dvp);
 592         vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
 593 
 594 }
 595 
 596 void *
 597 rfs3_lookup_getfh(LOOKUP3args *args)
 598 {
 599         return (&args->what.dir);
 600 }
 601 
 602 void
 603 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
 604     struct svc_req *req, cred_t *cr, bool_t ro)
 605 {
 606         int error;
 607         vnode_t *vp;
 608         struct vattr *vap;
 609         struct vattr va;
 610         int checkwriteperm;
 611         boolean_t dominant_label = B_FALSE;
 612         boolean_t equal_label = B_FALSE;
 613         boolean_t admin_low_client;
 614 
 615         vap = NULL;
 616 
 617         vp = nfs3_fhtovp(&args->object, exi);
 618 
 619         DTRACE_NFSV3_5(op__access__start, struct svc_req *, req,
 620             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 621             ACCESS3args *, args);
 622 
 623         if (vp == NULL) {
 624                 error = ESTALE;
 625                 goto out;
 626         }
 627 
 628         /*
 629          * If the file system is exported read only, it is not appropriate
 630          * to check write permissions for regular files and directories.
 631          * Special files are interpreted by the client, so the underlying
 632          * permissions are sent back to the client for interpretation.
 633          */
 634         if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
 635                 checkwriteperm = 0;
 636         else
 637                 checkwriteperm = 1;
 638 
 639         /*
 640          * We need the mode so that we can correctly determine access
 641          * permissions relative to a mandatory lock file.  Access to
 
 711                     equal_label)
 712                         resp->resok.access |= ACCESS3_DELETE;
 713         }
 714         if (args->access & ACCESS3_EXECUTE) {
 715                 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
 716                 if (error) {
 717                         if (curthread->t_flag & T_WOULDBLOCK)
 718                                 goto out;
 719                 } else if (!MANDLOCK(vp, va.va_mode) &&
 720                     (!is_system_labeled() || admin_low_client ||
 721                     dominant_label))
 722                         resp->resok.access |= ACCESS3_EXECUTE;
 723         }
 724 
 725         va.va_mask = AT_ALL;
 726         vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 727 
 728         resp->status = NFS3_OK;
 729         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 730 
 731         DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
 732             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 733             ACCESS3res *, resp);
 734 
 735         VN_RELE(vp);
 736 
 737         return;
 738 
 739 out:
 740         if (curthread->t_flag & T_WOULDBLOCK) {
 741                 curthread->t_flag &= ~T_WOULDBLOCK;
 742                 resp->status = NFS3ERR_JUKEBOX;
 743         } else
 744                 resp->status = puterrno3(error);
 745         DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
 746             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 747             ACCESS3res *, resp);
 748         if (vp != NULL)
 749                 VN_RELE(vp);
 750         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
 751 }
 752 
 753 void *
 754 rfs3_access_getfh(ACCESS3args *args)
 755 {
 756         return (&args->object);
 757 }
 758 
 759 /* ARGSUSED */
 760 void
 761 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
 762     struct svc_req *req, cred_t *cr, bool_t ro)
 763 {
 764         int error;
 765         vnode_t *vp;
 766         struct vattr *vap;
 767         struct vattr va;
 768         struct iovec iov;
 769         struct uio uio;
 770         char *data;
 771         struct sockaddr *ca;
 772         char *name = NULL;
 773         int is_referral = 0;
 774 
 775         vap = NULL;
 776 
 777         vp = nfs3_fhtovp(&args->symlink, exi);
 778 
 779         DTRACE_NFSV3_5(op__readlink__start, struct svc_req *, req,
 780             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 781             READLINK3args *, args);
 782 
 783         if (vp == NULL) {
 784                 error = ESTALE;
 785                 goto out;
 786         }
 787 
 788         va.va_mask = AT_ALL;
 789         error = VOP_GETATTR(vp, &va, 0, cr, NULL);
 790         if (error)
 791                 goto out;
 792 
 793         vap = &va;
 794 
 795         /* We lied about the object type for a referral */
 796         if (vn_is_nfs_reparse(vp, cr))
 797                 is_referral = 1;
 798 
 799         if (vp->v_type != VLNK && !is_referral) {
 800                 resp->status = NFS3ERR_INVAL;
 801                 goto out1;
 
 881                 kmem_free(data, MAXPATHLEN + 1);
 882                 goto out;
 883         }
 884 
 885         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 886         name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
 887             MAXPATHLEN + 1);
 888 
 889         if (name == NULL) {
 890                 /*
 891                  * Even though the conversion failed, we return
 892                  * something. We just don't translate it.
 893                  */
 894                 name = data;
 895         }
 896 
 897         resp->status = NFS3_OK;
 898         vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
 899         resp->resok.data = name;
 900 
 901         DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
 902             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 903             READLINK3res *, resp);
 904         VN_RELE(vp);
 905 
 906         if (name != data)
 907                 kmem_free(data, MAXPATHLEN + 1);
 908 
 909         return;
 910 
 911 out:
 912         if (curthread->t_flag & T_WOULDBLOCK) {
 913                 curthread->t_flag &= ~T_WOULDBLOCK;
 914                 resp->status = NFS3ERR_JUKEBOX;
 915         } else
 916                 resp->status = puterrno3(error);
 917 out1:
 918         DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
 919             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 920             READLINK3res *, resp);
 921         if (vp != NULL)
 922                 VN_RELE(vp);
 923         vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
 924 }
 925 
 926 void *
 927 rfs3_readlink_getfh(READLINK3args *args)
 928 {
 929         return (&args->symlink);
 930 }
 931 
 932 void
 933 rfs3_readlink_free(READLINK3res *resp)
 934 {
 935         if (resp->status == NFS3_OK)
 936                 kmem_free(resp->resok.data, MAXPATHLEN + 1);
 937 }
 938 
 939 /*
 940  * Server routine to handle read
 941  * May handle RDMA data as well as mblks
 942  */
 943 /* ARGSUSED */
 944 void
 945 rfs3_read(READ3args *args, READ3res *resp, struct exportinfo *exi,
 946     struct svc_req *req, cred_t *cr, bool_t ro)
 947 {
 948         int error;
 949         vnode_t *vp;
 950         struct vattr *vap;
 951         struct vattr va;
 952         struct iovec iov, *iovp = NULL;
 953         int iovcnt;
 954         struct uio uio;
 955         u_offset_t offset;
 956         mblk_t *mp = NULL;
 957         int in_crit = 0;
 958         int need_rwunlock = 0;
 959         caller_context_t ct;
 960         int rdma_used = 0;
 961         int loaned_buffers;
 962         struct uio *uiop;
 963 
 964         vap = NULL;
 965 
 966         vp = nfs3_fhtovp(&args->file, exi);
 967 
 968         DTRACE_NFSV3_5(op__read__start, struct svc_req *, req,
 969             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 970             READ3args *, args);
 971 
 972 
 973         if (vp == NULL) {
 974                 error = ESTALE;
 975                 goto out;
 976         }
 977 
 978         if (args->wlist) {
 979                 if (args->count > clist_len(args->wlist)) {
 980                         error = EINVAL;
 981                         goto out;
 982                 }
 983                 rdma_used = 1;
 984         }
 985 
 986         /* use loaned buffers for TCP */
 987         loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
 988 
 989         if (is_system_labeled()) {
 990                 bslabel_t *clabel = req->rq_label;
 991 
 992                 ASSERT(clabel != NULL);
 
1206                 resp->resok.eof = FALSE;
1207         resp->resok.data.data_len = resp->resok.count;
1208 
1209         if (mp)
1210                 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1211 
1212         resp->resok.data.mp = mp;
1213         resp->resok.size = (uint_t)args->count;
1214 
1215         if (rdma_used) {
1216                 resp->resok.data.data_val = (caddr_t)iov.iov_base;
1217                 if (!rdma_setup_read_data3(args, &(resp->resok))) {
1218                         resp->status = NFS3ERR_INVAL;
1219                 }
1220         } else {
1221                 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1222                 (resp->resok).wlist = NULL;
1223         }
1224 
1225 done:
1226         DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1227             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1228             READ3res *, resp);
1229 
1230         VN_RELE(vp);
1231 
1232         if (iovp != NULL)
1233                 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1234 
1235         return;
1236 
1237 out:
1238         if (curthread->t_flag & T_WOULDBLOCK) {
1239                 curthread->t_flag &= ~T_WOULDBLOCK;
1240                 resp->status = NFS3ERR_JUKEBOX;
1241         } else
1242                 resp->status = puterrno3(error);
1243 out1:
1244         DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1245             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1246             READ3res *, resp);
1247 
1248         if (vp != NULL) {
1249                 if (need_rwunlock)
1250                         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1251                 if (in_crit)
1252                         nbl_end_crit(vp);
1253                 VN_RELE(vp);
1254         }
1255         vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1256 
1257         if (iovp != NULL)
1258                 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1259 }
1260 
1261 void
1262 rfs3_read_free(READ3res *resp)
1263 {
1264         mblk_t *mp;
1265 
1266         if (resp->status == NFS3_OK) {
1267                 mp = resp->resok.data.mp;
1268                 if (mp != NULL)
1269                         freemsg(mp);
1270         }
1271 }
1272 
1273 void *
1274 rfs3_read_getfh(READ3args *args)
1275 {
1276         return (&args->file);
1277 }
1278 
1279 #define MAX_IOVECS      12
1280 
1281 #ifdef DEBUG
1282 static int rfs3_write_hits = 0;
1283 static int rfs3_write_misses = 0;
1284 #endif
1285 
1286 void
1287 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1288     struct svc_req *req, cred_t *cr, bool_t ro)
1289 {
1290         nfs3_srv_t *ns;
1291         int error;
1292         vnode_t *vp;
1293         struct vattr *bvap = NULL;
1294         struct vattr bva;
1295         struct vattr *avap = NULL;
1296         struct vattr ava;
1297         u_offset_t rlimit;
1298         struct uio uio;
1299         struct iovec iov[MAX_IOVECS];
1300         mblk_t *m;
1301         struct iovec *iovp;
1302         int iovcnt;
1303         int ioflag;
1304         cred_t *savecred;
1305         int in_crit = 0;
1306         int rwlock_ret = -1;
1307         caller_context_t ct;
1308 
1309         vp = nfs3_fhtovp(&args->file, exi);
1310 
1311         DTRACE_NFSV3_5(op__write__start, struct svc_req *, req,
1312             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1313             WRITE3args *, args);
1314 
1315         if (vp == NULL) {
1316                 error = ESTALE;
1317                 goto err;
1318         }
1319 
1320         ns = zone_getspecific(rfs3_zone_key, curzone);
1321         if (is_system_labeled()) {
1322                 bslabel_t *clabel = req->rq_label;
1323 
1324                 ASSERT(clabel != NULL);
1325                 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1326                     "got client label from request(1)", struct svc_req *, req);
1327 
1328                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1329                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1330                             exi)) {
1331                                 resp->status = NFS3ERR_ACCES;
1332                                 goto err1;
1333                         }
1334                 }
1335         }
1336 
1337         ct.cc_sysid = 0;
1338         ct.cc_pid = 0;
1339         ct.cc_caller_id = nfs3_srv_caller_id;
1340         ct.cc_flags = CC_DONTBLOCK;
 
1388 
1389         if (vp->v_type != VREG) {
1390                 resp->status = NFS3ERR_INVAL;
1391                 goto err1;
1392         }
1393 
1394         if (crgetuid(cr) != bva.va_uid &&
1395             (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1396                 goto err;
1397 
1398         if (MANDLOCK(vp, bva.va_mode)) {
1399                 resp->status = NFS3ERR_ACCES;
1400                 goto err1;
1401         }
1402 
1403         if (args->count == 0) {
1404                 resp->status = NFS3_OK;
1405                 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1406                 resp->resok.count = 0;
1407                 resp->resok.committed = args->stable;
1408                 resp->resok.verf = ns->write3verf;
1409                 goto out;
1410         }
1411 
1412         if (args->mblk != NULL) {
1413                 iovcnt = 0;
1414                 for (m = args->mblk; m != NULL; m = m->b_cont)
1415                         iovcnt++;
1416                 if (iovcnt <= MAX_IOVECS) {
1417 #ifdef DEBUG
1418                         rfs3_write_hits++;
1419 #endif
1420                         iovp = iov;
1421                 } else {
1422 #ifdef DEBUG
1423                         rfs3_write_misses++;
1424 #endif
1425                         iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1426                 }
1427                 mblk_to_iov(args->mblk, iovcnt, iovp);
1428 
 
1490 
1491         /*
1492          * If we were unable to get the V_WRITELOCK_TRUE, then we
1493          * may not have accurate after attrs, so check if
1494          * we have both attributes, they have a non-zero va_seq, and
1495          * va_seq has changed by exactly one,
1496          * if not, turn off the before attr.
1497          */
1498         if (rwlock_ret != V_WRITELOCK_TRUE) {
1499                 if (bvap == NULL || avap == NULL ||
1500                     bvap->va_seq == 0 || avap->va_seq == 0 ||
1501                     avap->va_seq != (bvap->va_seq + 1)) {
1502                         bvap = NULL;
1503                 }
1504         }
1505 
1506         resp->status = NFS3_OK;
1507         vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1508         resp->resok.count = args->count - uio.uio_resid;
1509         resp->resok.committed = args->stable;
1510         resp->resok.verf = ns->write3verf;
1511         goto out;
1512 
1513 err:
1514         if (curthread->t_flag & T_WOULDBLOCK) {
1515                 curthread->t_flag &= ~T_WOULDBLOCK;
1516                 resp->status = NFS3ERR_JUKEBOX;
1517         } else
1518                 resp->status = puterrno3(error);
1519 err1:
1520         vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1521 out:
1522         DTRACE_NFSV3_5(op__write__done, struct svc_req *, req,
1523             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1524             WRITE3res *, resp);
1525 
1526         if (vp != NULL) {
1527                 if (rwlock_ret != -1)
1528                         VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1529                 if (in_crit)
1530                         nbl_end_crit(vp);
1531                 VN_RELE(vp);
1532         }
1533 }
1534 
1535 void *
1536 rfs3_write_getfh(WRITE3args *args)
1537 {
1538         return (&args->file);
1539 }
1540 
1541 void
1542 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1543     struct svc_req *req, cred_t *cr, bool_t ro)
1544 {
1545         int error;
1546         int in_crit = 0;
1547         vnode_t *vp;
1548         vnode_t *tvp = NULL;
1549         vnode_t *dvp;
1550         struct vattr *vap;
1551         struct vattr va;
1552         struct vattr *dbvap;
1553         struct vattr dbva;
1554         struct vattr *davap;
1555         struct vattr dava;
1556         enum vcexcl excl;
1557         nfstime3 *mtime;
1558         len_t reqsize;
1559         bool_t trunc;
1560         struct sockaddr *ca;
1561         char *name = NULL;
1562 
1563         dbvap = NULL;
1564         davap = NULL;
1565 
1566         dvp = nfs3_fhtovp(&args->where.dir, exi);
1567 
1568         DTRACE_NFSV3_5(op__create__start, struct svc_req *, req,
1569             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1570             CREATE3args *, args);
1571 
1572         if (dvp == NULL) {
1573                 error = ESTALE;
1574                 goto out;
1575         }
1576 
1577         dbva.va_mask = AT_ALL;
1578         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1579         davap = dbvap;
1580 
1581         if (args->where.name == nfs3nametoolong) {
1582                 resp->status = NFS3ERR_NAMETOOLONG;
1583                 goto out1;
1584         }
1585 
1586         if (args->where.name == NULL || *(args->where.name) == '\0') {
1587                 resp->status = NFS3ERR_ACCES;
1588                 goto out1;
1589         }
1590 
1591         if (rdonly(ro, dvp)) {
1592                 resp->status = NFS3ERR_ROFS;
1593                 goto out1;
1594         }
1595 
1596         if (protect_zfs_mntpt(dvp) != 0) {
1597                 resp->status = NFS3ERR_ACCES;
1598                 goto out1;
1599         }
1600 
1601         if (is_system_labeled()) {
1602                 bslabel_t *clabel = req->rq_label;
1603 
1604                 ASSERT(clabel != NULL);
1605                 DTRACE_PROBE2(tx__rfs3__log__info__opcreate__clabel, char *,
1606                     "got client label from request(1)", struct svc_req *, req);
1607 
1608                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1609                         if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1610                             exi)) {
1611                                 resp->status = NFS3ERR_ACCES;
1612                                 goto out1;
1613                         }
1614                 }
1615         }
1616 
1617         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
1618         name = nfscmd_convname(ca, exi, args->where.name,
1619             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
1620 
 
1854         else
1855                 resp->resok.obj.handle_follows = TRUE;
1856 
1857         /*
1858          * Force modified data and metadata out to stable storage.
1859          */
1860         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1861         (void) VOP_FSYNC(dvp, 0, cr, NULL);
1862 
1863         VN_RELE(vp);
1864         if (tvp != NULL) {
1865                 if (in_crit)
1866                         nbl_end_crit(tvp);
1867                 VN_RELE(tvp);
1868         }
1869 
1870         resp->status = NFS3_OK;
1871         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1872         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1873 
1874         DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1875             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1876             CREATE3res *, resp);
1877 
1878         VN_RELE(dvp);
1879         return;
1880 
1881 out:
1882         if (curthread->t_flag & T_WOULDBLOCK) {
1883                 curthread->t_flag &= ~T_WOULDBLOCK;
1884                 resp->status = NFS3ERR_JUKEBOX;
1885         } else
1886                 resp->status = puterrno3(error);
1887 out1:
1888         DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1889             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1890             CREATE3res *, resp);
1891 
1892         if (name != NULL && name != args->where.name)
1893                 kmem_free(name, MAXPATHLEN + 1);
1894 
1895         if (tvp != NULL) {
1896                 if (in_crit)
1897                         nbl_end_crit(tvp);
1898                 VN_RELE(tvp);
1899         }
1900         if (dvp != NULL)
1901                 VN_RELE(dvp);
1902         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1903 }
1904 
1905 void *
1906 rfs3_create_getfh(CREATE3args *args)
1907 {
1908         return (&args->where.dir);
1909 }
1910 
1911 void
1912 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1913     struct svc_req *req, cred_t *cr, bool_t ro)
1914 {
1915         int error;
1916         vnode_t *vp = NULL;
1917         vnode_t *dvp;
1918         struct vattr *vap;
1919         struct vattr va;
1920         struct vattr *dbvap;
1921         struct vattr dbva;
1922         struct vattr *davap;
1923         struct vattr dava;
1924         struct sockaddr *ca;
1925         char *name = NULL;
1926 
1927         dbvap = NULL;
1928         davap = NULL;
1929 
1930         dvp = nfs3_fhtovp(&args->where.dir, exi);
1931 
1932         DTRACE_NFSV3_5(op__mkdir__start, struct svc_req *, req,
1933             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1934             MKDIR3args *, args);
1935 
1936         if (dvp == NULL) {
1937                 error = ESTALE;
1938                 goto out;
1939         }
1940 
1941         dbva.va_mask = AT_ALL;
1942         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1943         davap = dbvap;
1944 
1945         if (args->where.name == nfs3nametoolong) {
1946                 resp->status = NFS3ERR_NAMETOOLONG;
1947                 goto out1;
1948         }
1949 
1950         if (args->where.name == NULL || *(args->where.name) == '\0') {
1951                 resp->status = NFS3ERR_ACCES;
1952                 goto out1;
1953         }
1954 
1955         if (rdonly(ro, dvp)) {
1956                 resp->status = NFS3ERR_ROFS;
1957                 goto out1;
1958         }
1959 
1960         if (protect_zfs_mntpt(dvp) != 0) {
1961                 resp->status = NFS3ERR_ACCES;
1962                 goto out1;
1963         }
1964 
1965         if (is_system_labeled()) {
1966                 bslabel_t *clabel = req->rq_label;
1967 
1968                 ASSERT(clabel != NULL);
1969                 DTRACE_PROBE2(tx__rfs3__log__info__opmkdir__clabel, char *,
1970                     "got client label from request(1)", struct svc_req *, req);
1971 
1972                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1973                         if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
1974                             exi)) {
1975                                 resp->status = NFS3ERR_ACCES;
1976                                 goto out1;
1977                         }
1978                 }
1979         }
1980 
1981         error = sattr3_to_vattr(&args->attributes, &va);
1982         if (error)
1983                 goto out;
1984 
 
2018         error = makefh3(&resp->resok.obj.handle, vp, exi);
2019         if (error)
2020                 resp->resok.obj.handle_follows = FALSE;
2021         else
2022                 resp->resok.obj.handle_follows = TRUE;
2023 
2024         va.va_mask = AT_ALL;
2025         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2026 
2027         /*
2028          * Force modified data and metadata out to stable storage.
2029          */
2030         (void) VOP_FSYNC(vp, 0, cr, NULL);
2031 
2032         VN_RELE(vp);
2033 
2034         resp->status = NFS3_OK;
2035         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2036         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2037 
2038         DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
2039             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2040             MKDIR3res *, resp);
2041         VN_RELE(dvp);
2042 
2043         return;
2044 
2045 out:
2046         if (curthread->t_flag & T_WOULDBLOCK) {
2047                 curthread->t_flag &= ~T_WOULDBLOCK;
2048                 resp->status = NFS3ERR_JUKEBOX;
2049         } else
2050                 resp->status = puterrno3(error);
2051 out1:
2052         DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
2053             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2054             MKDIR3res *, resp);
2055         if (dvp != NULL)
2056                 VN_RELE(dvp);
2057         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2058 }
2059 
2060 void *
2061 rfs3_mkdir_getfh(MKDIR3args *args)
2062 {
2063         return (&args->where.dir);
2064 }
2065 
2066 void
2067 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2068     struct svc_req *req, cred_t *cr, bool_t ro)
2069 {
2070         int error;
2071         vnode_t *vp;
2072         vnode_t *dvp;
2073         struct vattr *vap;
2074         struct vattr va;
2075         struct vattr *dbvap;
2076         struct vattr dbva;
2077         struct vattr *davap;
2078         struct vattr dava;
2079         struct sockaddr *ca;
2080         char *name = NULL;
2081         char *symdata = NULL;
2082 
2083         dbvap = NULL;
2084         davap = NULL;
2085 
2086         dvp = nfs3_fhtovp(&args->where.dir, exi);
2087 
2088         DTRACE_NFSV3_5(op__symlink__start, struct svc_req *, req,
2089             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2090             SYMLINK3args *, args);
2091 
2092         if (dvp == NULL) {
2093                 error = ESTALE;
2094                 goto err;
2095         }
2096 
2097         dbva.va_mask = AT_ALL;
2098         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2099         davap = dbvap;
2100 
2101         if (args->where.name == nfs3nametoolong) {
2102                 resp->status = NFS3ERR_NAMETOOLONG;
2103                 goto err1;
2104         }
2105 
2106         if (args->where.name == NULL || *(args->where.name) == '\0') {
2107                 resp->status = NFS3ERR_ACCES;
2108                 goto err1;
2109         }
2110 
2111         if (rdonly(ro, dvp)) {
2112                 resp->status = NFS3ERR_ROFS;
2113                 goto err1;
2114         }
2115 
2116         if (protect_zfs_mntpt(dvp) != 0) {
2117                 resp->status = NFS3ERR_ACCES;
2118                 goto err1;
2119         }
2120 
2121         if (is_system_labeled()) {
2122                 bslabel_t *clabel = req->rq_label;
2123 
2124                 ASSERT(clabel != NULL);
2125                 DTRACE_PROBE2(tx__rfs3__log__info__opsymlink__clabel, char *,
2126                     "got client label from request(1)", struct svc_req *, req);
2127 
2128                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2129                         if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2130                             exi)) {
2131                                 resp->status = NFS3ERR_ACCES;
2132                                 goto err1;
2133                         }
2134                 }
2135         }
2136 
2137         error = sattr3_to_vattr(&args->symlink.symlink_attributes, &va);
2138         if (error)
2139                 goto err;
2140 
 
2212         VN_RELE(vp);
2213 
2214         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2215         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2216         goto out;
2217 
2218 err:
2219         if (curthread->t_flag & T_WOULDBLOCK) {
2220                 curthread->t_flag &= ~T_WOULDBLOCK;
2221                 resp->status = NFS3ERR_JUKEBOX;
2222         } else
2223                 resp->status = puterrno3(error);
2224 err1:
2225         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2226 out:
2227         if (name != NULL && name != args->where.name)
2228                 kmem_free(name, MAXPATHLEN + 1);
2229         if (symdata != NULL && symdata != args->symlink.symlink_data)
2230                 kmem_free(symdata, MAXPATHLEN + 1);
2231 
2232         DTRACE_NFSV3_5(op__symlink__done, struct svc_req *, req,
2233             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2234             SYMLINK3res *, resp);
2235 
2236         if (dvp != NULL)
2237                 VN_RELE(dvp);
2238 }
2239 
2240 void *
2241 rfs3_symlink_getfh(SYMLINK3args *args)
2242 {
2243         return (&args->where.dir);
2244 }
2245 
2246 void
2247 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2248     struct svc_req *req, cred_t *cr, bool_t ro)
2249 {
2250         int error;
2251         vnode_t *vp;
2252         vnode_t *realvp;
2253         vnode_t *dvp;
2254         struct vattr *vap;
2255         struct vattr va;
2256         struct vattr *dbvap;
2257         struct vattr dbva;
2258         struct vattr *davap;
2259         struct vattr dava;
2260         int mode;
2261         enum vcexcl excl;
2262         struct sockaddr *ca;
2263         char *name = NULL;
2264 
2265         dbvap = NULL;
2266         davap = NULL;
2267 
2268         dvp = nfs3_fhtovp(&args->where.dir, exi);
2269 
2270         DTRACE_NFSV3_5(op__mknod__start, struct svc_req *, req,
2271             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2272             MKNOD3args *, args);
2273 
2274         if (dvp == NULL) {
2275                 error = ESTALE;
2276                 goto out;
2277         }
2278 
2279         dbva.va_mask = AT_ALL;
2280         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2281         davap = dbvap;
2282 
2283         if (args->where.name == nfs3nametoolong) {
2284                 resp->status = NFS3ERR_NAMETOOLONG;
2285                 goto out1;
2286         }
2287 
2288         if (args->where.name == NULL || *(args->where.name) == '\0') {
2289                 resp->status = NFS3ERR_ACCES;
2290                 goto out1;
2291         }
2292 
2293         if (rdonly(ro, dvp)) {
2294                 resp->status = NFS3ERR_ROFS;
2295                 goto out1;
2296         }
2297 
2298         if (protect_zfs_mntpt(dvp) != 0) {
2299                 resp->status = NFS3ERR_ACCES;
2300                 goto out1;
2301         }
2302 
2303         if (is_system_labeled()) {
2304                 bslabel_t *clabel = req->rq_label;
2305 
2306                 ASSERT(clabel != NULL);
2307                 DTRACE_PROBE2(tx__rfs3__log__info__opmknod__clabel, char *,
2308                     "got client label from request(1)", struct svc_req *, req);
2309 
2310                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2311                         if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
2312                             exi)) {
2313                                 resp->status = NFS3ERR_ACCES;
2314                                 goto out1;
2315                         }
2316                 }
2317         }
2318 
2319         switch (args->what.type) {
2320         case NF3CHR:
2321         case NF3BLK:
2322                 error = sattr3_to_vattr(
 
2403         else
2404                 resp->resok.obj.handle_follows = TRUE;
2405 
2406         va.va_mask = AT_ALL;
2407         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2408 
2409         /*
2410          * Force modified metadata out to stable storage.
2411          *
2412          * if a underlying vp exists, pass it to VOP_FSYNC
2413          */
2414         if (VOP_REALVP(vp, &realvp, NULL) == 0)
2415                 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2416         else
2417                 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2418 
2419         VN_RELE(vp);
2420 
2421         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2422         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2423         DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2424             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2425             MKNOD3res *, resp);
2426         VN_RELE(dvp);
2427         return;
2428 
2429 out:
2430         if (curthread->t_flag & T_WOULDBLOCK) {
2431                 curthread->t_flag &= ~T_WOULDBLOCK;
2432                 resp->status = NFS3ERR_JUKEBOX;
2433         } else
2434                 resp->status = puterrno3(error);
2435 out1:
2436         DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2437             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2438             MKNOD3res *, resp);
2439         if (dvp != NULL)
2440                 VN_RELE(dvp);
2441         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2442 }
2443 
2444 void *
2445 rfs3_mknod_getfh(MKNOD3args *args)
2446 {
2447         return (&args->where.dir);
2448 }
2449 
2450 void
2451 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2452     struct svc_req *req, cred_t *cr, bool_t ro)
2453 {
2454         int error = 0;
2455         vnode_t *vp;
2456         struct vattr *bvap;
2457         struct vattr bva;
2458         struct vattr *avap;
2459         struct vattr ava;
2460         vnode_t *targvp = NULL;
2461         struct sockaddr *ca;
2462         char *name = NULL;
2463 
2464         bvap = NULL;
2465         avap = NULL;
2466 
2467         vp = nfs3_fhtovp(&args->object.dir, exi);
2468 
2469         DTRACE_NFSV3_5(op__remove__start, struct svc_req *, req,
2470             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2471             REMOVE3args *, args);
2472 
2473         if (vp == NULL) {
2474                 error = ESTALE;
2475                 goto err;
2476         }
2477 
2478         bva.va_mask = AT_ALL;
2479         bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2480         avap = bvap;
2481 
2482         if (vp->v_type != VDIR) {
2483                 resp->status = NFS3ERR_NOTDIR;
2484                 goto err1;
2485         }
2486 
2487         if (args->object.name == nfs3nametoolong) {
2488                 resp->status = NFS3ERR_NAMETOOLONG;
2489                 goto err1;
2490         }
2491 
 
2559          * Force modified data and metadata out to stable storage.
2560          */
2561         (void) VOP_FSYNC(vp, 0, cr, NULL);
2562 
2563         if (error)
2564                 goto err;
2565 
2566         resp->status = NFS3_OK;
2567         vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2568         goto out;
2569 
2570 err:
2571         if (curthread->t_flag & T_WOULDBLOCK) {
2572                 curthread->t_flag &= ~T_WOULDBLOCK;
2573                 resp->status = NFS3ERR_JUKEBOX;
2574         } else
2575                 resp->status = puterrno3(error);
2576 err1:
2577         vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2578 out:
2579         DTRACE_NFSV3_5(op__remove__done, struct svc_req *, req,
2580             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2581             REMOVE3res *, resp);
2582 
2583         if (name != NULL && name != args->object.name)
2584                 kmem_free(name, MAXPATHLEN + 1);
2585 
2586         if (vp != NULL)
2587                 VN_RELE(vp);
2588 }
2589 
2590 void *
2591 rfs3_remove_getfh(REMOVE3args *args)
2592 {
2593         return (&args->object.dir);
2594 }
2595 
2596 void
2597 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2598     struct svc_req *req, cred_t *cr, bool_t ro)
2599 {
2600         int error;
2601         vnode_t *vp;
2602         struct vattr *bvap;
2603         struct vattr bva;
2604         struct vattr *avap;
2605         struct vattr ava;
2606         struct sockaddr *ca;
2607         char *name = NULL;
2608 
2609         bvap = NULL;
2610         avap = NULL;
2611 
2612         vp = nfs3_fhtovp(&args->object.dir, exi);
2613 
2614         DTRACE_NFSV3_5(op__rmdir__start, struct svc_req *, req,
2615             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2616             RMDIR3args *, args);
2617 
2618         if (vp == NULL) {
2619                 error = ESTALE;
2620                 goto err;
2621         }
2622 
2623         bva.va_mask = AT_ALL;
2624         bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2625         avap = bvap;
2626 
2627         if (vp->v_type != VDIR) {
2628                 resp->status = NFS3ERR_NOTDIR;
2629                 goto err1;
2630         }
2631 
2632         if (args->object.name == nfs3nametoolong) {
2633                 resp->status = NFS3ERR_NAMETOOLONG;
2634                 goto err1;
2635         }
2636 
 
2652                     "got client label from request(1)", struct svc_req *, req);
2653 
2654                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2655                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2656                             exi)) {
2657                                 resp->status = NFS3ERR_ACCES;
2658                                 goto err1;
2659                         }
2660                 }
2661         }
2662 
2663         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2664         name = nfscmd_convname(ca, exi, args->object.name,
2665             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2666 
2667         if (name == NULL) {
2668                 resp->status = NFS3ERR_INVAL;
2669                 goto err1;
2670         }
2671 
2672         error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0);
2673 
2674         if (name != args->object.name)
2675                 kmem_free(name, MAXPATHLEN + 1);
2676 
2677         ava.va_mask = AT_ALL;
2678         avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2679 
2680         /*
2681          * Force modified data and metadata out to stable storage.
2682          */
2683         (void) VOP_FSYNC(vp, 0, cr, NULL);
2684 
2685         if (error) {
2686                 /*
2687                  * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2688                  * if the directory is not empty.  A System V NFS server
2689                  * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2690                  * over the wire.
2691                  */
2692                 if (error == EEXIST)
2693                         error = ENOTEMPTY;
2694                 goto err;
2695         }
2696 
2697         resp->status = NFS3_OK;
2698         vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2699         goto out;
2700 
2701 err:
2702         if (curthread->t_flag & T_WOULDBLOCK) {
2703                 curthread->t_flag &= ~T_WOULDBLOCK;
2704                 resp->status = NFS3ERR_JUKEBOX;
2705         } else
2706                 resp->status = puterrno3(error);
2707 err1:
2708         vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2709 out:
2710         DTRACE_NFSV3_5(op__rmdir__done, struct svc_req *, req,
2711             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2712             RMDIR3res *, resp);
2713         if (vp != NULL)
2714                 VN_RELE(vp);
2715 
2716 }
2717 
2718 void *
2719 rfs3_rmdir_getfh(RMDIR3args *args)
2720 {
2721         return (&args->object.dir);
2722 }
2723 
2724 void
2725 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2726     struct svc_req *req, cred_t *cr, bool_t ro)
2727 {
2728         int error = 0;
2729         vnode_t *fvp;
2730         vnode_t *tvp;
2731         vnode_t *targvp;
2732         struct vattr *fbvap;
2733         struct vattr fbva;
2734         struct vattr *favap;
2735         struct vattr fava;
2736         struct vattr *tbvap;
2737         struct vattr tbva;
2738         struct vattr *tavap;
2739         struct vattr tava;
2740         nfs_fh3 *fh3;
2741         struct exportinfo *to_exi;
2742         vnode_t *srcvp = NULL;
2743         bslabel_t *clabel;
2744         struct sockaddr *ca;
2745         char *name = NULL;
2746         char *toname = NULL;
2747 
2748         fbvap = NULL;
2749         favap = NULL;
2750         tbvap = NULL;
2751         tavap = NULL;
2752         tvp = NULL;
2753 
2754         fvp = nfs3_fhtovp(&args->from.dir, exi);
2755 
2756         DTRACE_NFSV3_5(op__rename__start, struct svc_req *, req,
2757             cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2758             RENAME3args *, args);
2759 
2760         if (fvp == NULL) {
2761                 error = ESTALE;
2762                 goto err;
2763         }
2764 
2765         if (is_system_labeled()) {
2766                 clabel = req->rq_label;
2767                 ASSERT(clabel != NULL);
2768                 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2769                     "got client label from request(1)", struct svc_req *, req);
2770 
2771                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2772                         if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2773                             exi)) {
2774                                 resp->status = NFS3ERR_ACCES;
2775                                 goto err1;
2776                         }
2777                 }
2778         }
2779 
2780         fbva.va_mask = AT_ALL;
2781         fbvap = VOP_GETATTR(fvp, &fbva, 0, cr, NULL) ? NULL : &fbva;
2782         favap = fbvap;
2783 
2784         fh3 = &args->to.dir;
2785         to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2786         if (to_exi == NULL) {
2787                 resp->status = NFS3ERR_ACCES;
2788                 goto err1;
2789         }
2790         exi_rele(&to_exi);
2791 
2792         if (to_exi != exi) {
2793                 resp->status = NFS3ERR_XDEV;
2794                 goto err1;
2795         }
2796 
2797         tvp = nfs3_fhtovp(&args->to.dir, exi);
2798         if (tvp == NULL) {
2799                 error = ESTALE;
2800                 goto err;
2801         }
2802 
2803         tbva.va_mask = AT_ALL;
2804         tbvap = VOP_GETATTR(tvp, &tbva, 0, cr, NULL) ? NULL : &tbva;
2805         tavap = tbvap;
2806 
2807         if (fvp->v_type != VDIR || tvp->v_type != VDIR) {
2808                 resp->status = NFS3ERR_NOTDIR;
2809                 goto err1;
2810         }
2811 
2812         if (args->from.name == nfs3nametoolong ||
2813             args->to.name == nfs3nametoolong) {
2814                 resp->status = NFS3ERR_NAMETOOLONG;
2815                 goto err1;
2816         }
2817         if (args->from.name == NULL || *(args->from.name) == '\0' ||
2818             args->to.name == NULL || *(args->to.name) == '\0') {
2819                 resp->status = NFS3ERR_ACCES;
2820                 goto err1;
2821         }
2822 
2823         if (rdonly(ro, tvp)) {
2824                 resp->status = NFS3ERR_ROFS;
2825                 goto err1;
2826         }
2827 
2828         if (protect_zfs_mntpt(tvp) != 0) {
2829                 resp->status = NFS3ERR_ACCES;
2830                 goto err1;
2831         }
2832 
2833         if (is_system_labeled()) {
2834                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2835                         if (!do_rfs_label_check(clabel, tvp, EQUALITY_CHECK,
2836                             exi)) {
2837                                 resp->status = NFS3ERR_ACCES;
2838                                 goto err1;
2839                         }
2840                 }
2841         }
2842 
2843         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2844         name = nfscmd_convname(ca, exi, args->from.name,
2845             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2846 
2847         if (name == NULL) {
2848                 resp->status = NFS3ERR_INVAL;
2849                 goto err1;
2850         }
2851 
2852         toname = nfscmd_convname(ca, exi, args->to.name,
 
2860         /*
2861          * Check for a conflict with a non-blocking mandatory share
2862          * reservation or V4 delegations.
2863          */
2864         error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2865             NULL, cr, NULL, NULL, NULL);
2866         if (error != 0)
2867                 goto err;
2868 
2869         /*
2870          * If we rename a delegated file we should recall the
2871          * delegation, since future opens should fail or would
2872          * refer to a new file.
2873          */
2874         if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2875                 resp->status = NFS3ERR_JUKEBOX;
2876                 goto err1;
2877         }
2878 
2879         /*
2880          * Check for renaming over a delegated file.  Check nfs4_deleg_policy
2881          * first to avoid VOP_LOOKUP if possible.
2882          */
2883         if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE &&
2884             VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2885             NULL, NULL, NULL) == 0) {
2886 
2887                 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2888                         VN_RELE(targvp);
2889                         resp->status = NFS3ERR_JUKEBOX;
2890                         goto err1;
2891                 }
2892                 VN_RELE(targvp);
2893         }
2894 
2895         if (!nbl_need_check(srcvp)) {
2896                 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2897         } else {
2898                 nbl_start_crit(srcvp, RW_READER);
2899                 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2900                         error = EACCES;
2901                 else
2902                         error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2903                 nbl_end_crit(srcvp);
 
2927         vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2928         goto out;
2929 
2930 err:
2931         if (curthread->t_flag & T_WOULDBLOCK) {
2932                 curthread->t_flag &= ~T_WOULDBLOCK;
2933                 resp->status = NFS3ERR_JUKEBOX;
2934         } else {
2935                 resp->status = puterrno3(error);
2936         }
2937 err1:
2938         vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2939         vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2940 
2941 out:
2942         if (name != NULL && name != args->from.name)
2943                 kmem_free(name, MAXPATHLEN + 1);
2944         if (toname != NULL && toname != args->to.name)
2945                 kmem_free(toname, MAXPATHLEN + 1);
2946 
2947         DTRACE_NFSV3_5(op__rename__done, struct svc_req *, req,
2948             cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2949             RENAME3res *, resp);
2950         if (fvp != NULL)
2951                 VN_RELE(fvp);
2952         if (tvp != NULL)
2953                 VN_RELE(tvp);
2954 }
2955 
2956 void *
2957 rfs3_rename_getfh(RENAME3args *args)
2958 {
2959         return (&args->from.dir);
2960 }
2961 
2962 void
2963 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2964     struct svc_req *req, cred_t *cr, bool_t ro)
2965 {
2966         int error;
2967         vnode_t *vp;
2968         vnode_t *dvp;
2969         struct vattr *vap;
2970         struct vattr va;
2971         struct vattr *bvap;
2972         struct vattr bva;
2973         struct vattr *avap;
2974         struct vattr ava;
2975         nfs_fh3 *fh3;
2976         struct exportinfo *to_exi;
2977         bslabel_t *clabel;
2978         struct sockaddr *ca;
2979         char *name = NULL;
2980 
2981         vap = NULL;
2982         bvap = NULL;
2983         avap = NULL;
2984         dvp = NULL;
2985 
2986         vp = nfs3_fhtovp(&args->file, exi);
2987 
2988         DTRACE_NFSV3_5(op__link__start, struct svc_req *, req,
2989             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2990             LINK3args *, args);
2991 
2992         if (vp == NULL) {
2993                 error = ESTALE;
2994                 goto out;
2995         }
2996 
2997         va.va_mask = AT_ALL;
2998         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2999 
3000         fh3 = &args->link.dir;
3001         to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
3002         if (to_exi == NULL) {
3003                 resp->status = NFS3ERR_ACCES;
3004                 goto out1;
3005         }
3006         exi_rele(&to_exi);
3007 
3008         if (to_exi != exi) {
3009                 resp->status = NFS3ERR_XDEV;
3010                 goto out1;
3011         }
3012 
3013         if (is_system_labeled()) {
3014                 clabel = req->rq_label;
3015 
3016                 ASSERT(clabel != NULL);
3017                 DTRACE_PROBE2(tx__rfs3__log__info__oplink__clabel, char *,
3018                     "got client label from request(1)", struct svc_req *, req);
3019 
3020                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3021                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3022                             exi)) {
3023                                 resp->status = NFS3ERR_ACCES;
3024                                 goto out1;
3025                         }
3026                 }
 
3038         if (dvp->v_type != VDIR) {
3039                 resp->status = NFS3ERR_NOTDIR;
3040                 goto out1;
3041         }
3042 
3043         if (args->link.name == nfs3nametoolong) {
3044                 resp->status = NFS3ERR_NAMETOOLONG;
3045                 goto out1;
3046         }
3047 
3048         if (args->link.name == NULL || *(args->link.name) == '\0') {
3049                 resp->status = NFS3ERR_ACCES;
3050                 goto out1;
3051         }
3052 
3053         if (rdonly(ro, dvp)) {
3054                 resp->status = NFS3ERR_ROFS;
3055                 goto out1;
3056         }
3057 
3058         if (protect_zfs_mntpt(dvp) != 0) {
3059                 resp->status = NFS3ERR_ACCES;
3060                 goto out1;
3061         }
3062 
3063         if (is_system_labeled()) {
3064                 DTRACE_PROBE2(tx__rfs3__log__info__oplinkdir__clabel, char *,
3065                     "got client label from request(1)", struct svc_req *, req);
3066 
3067                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3068                         if (!do_rfs_label_check(clabel, dvp, EQUALITY_CHECK,
3069                             exi)) {
3070                                 resp->status = NFS3ERR_ACCES;
3071                                 goto out1;
3072                         }
3073                 }
3074         }
3075 
3076         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3077         name = nfscmd_convname(ca, exi, args->link.name,
3078             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
3079 
3080         if (name == NULL) {
3081                 resp->status = NFS3ERR_SERVERFAULT;
3082                 goto out1;
 
3087         va.va_mask = AT_ALL;
3088         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3089         ava.va_mask = AT_ALL;
3090         avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3091 
3092         /*
3093          * Force modified data and metadata out to stable storage.
3094          */
3095         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3096         (void) VOP_FSYNC(dvp, 0, cr, NULL);
3097 
3098         if (error)
3099                 goto out;
3100 
3101         VN_RELE(dvp);
3102 
3103         resp->status = NFS3_OK;
3104         vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3105         vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3106 
3107         DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3108             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3109             LINK3res *, resp);
3110 
3111         VN_RELE(vp);
3112 
3113         return;
3114 
3115 out:
3116         if (curthread->t_flag & T_WOULDBLOCK) {
3117                 curthread->t_flag &= ~T_WOULDBLOCK;
3118                 resp->status = NFS3ERR_JUKEBOX;
3119         } else
3120                 resp->status = puterrno3(error);
3121 out1:
3122         if (name != NULL && name != args->link.name)
3123                 kmem_free(name, MAXPATHLEN + 1);
3124 
3125         DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3126             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3127             LINK3res *, resp);
3128 
3129         if (vp != NULL)
3130                 VN_RELE(vp);
3131         if (dvp != NULL)
3132                 VN_RELE(dvp);
3133         vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3134         vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3135 }
3136 
3137 void *
3138 rfs3_link_getfh(LINK3args *args)
3139 {
3140         return (&args->file);
3141 }
3142 
3143 #ifdef nextdp
3144 #undef nextdp
3145 #endif
3146 #define nextdp(dp)      ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3147 
3148 /* ARGSUSED */
3149 void
3150 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3151     struct svc_req *req, cred_t *cr, bool_t ro)
3152 {
3153         int error;
3154         vnode_t *vp;
3155         struct vattr *vap;
3156         struct vattr va;
3157         struct iovec iov;
3158         struct uio uio;
3159         int iseof;
3160 
3161         count3 count = args->count;
3162         count3 size;            /* size of the READDIR3resok structure */
3163 
3164         size_t datasz;
3165         char *data = NULL;
3166         dirent64_t *dp;
3167 
3168         struct sockaddr *ca;
3169         entry3 **eptr;
3170         entry3 *entry;
3171 
3172         vp = nfs3_fhtovp(&args->dir, exi);
3173 
3174         DTRACE_NFSV3_5(op__readdir__start, struct svc_req *, req,
3175             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3176             READDIR3args *, args);
3177 
3178         if (vp == NULL) {
3179                 resp->status = NFS3ERR_STALE;
3180                 vap = NULL;
3181                 goto out1;
3182         }
3183 
3184         if (vp->v_type != VDIR) {
3185                 resp->status = NFS3ERR_NOTDIR;
3186                 vap = NULL;
3187                 goto out1;
3188         }
3189 
3190         if (is_system_labeled()) {
3191                 bslabel_t *clabel = req->rq_label;
3192 
3193                 ASSERT(clabel != NULL);
3194                 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3195                     "got client label from request(1)", struct svc_req *, req);
3196 
3197                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3198                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3199                             exi)) {
3200                                 resp->status = NFS3ERR_ACCES;
3201                                 vap = NULL;
3202                                 goto out1;
3203                         }
3204                 }
3205         }
3206 
3207         (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3208 
3209         va.va_mask = AT_ALL;
3210         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3211 
3212         error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3213         if (error)
3214                 goto out;
3215 
3216         /*
3217          * Don't allow arbitrary counts for allocation
3218          */
3219         if (count > rfs3_tsize(req))
3220                 count = rfs3_tsize(req);
3221 
3222         /*
3223          * struct READDIR3resok:
3224          *   dir_attributes:    1 + NFS3_SIZEOF_FATTR3
3225          *   cookieverf:        2
3226          *   entries (bool):    1
3227          *   eof:               1
3228          */
3229         size = (1 + NFS3_SIZEOF_FATTR3 + 2 + 1 + 1) * BYTES_PER_XDR_UNIT;
3230 
3231         if (size > count) {
3232                 resp->status = NFS3ERR_TOOSMALL;
3233                 goto out1;
3234         }
3235 
3236         /*
3237          * This is simplification.  The dirent64_t size is not the same as the
3238          * size of XDR representation of entry3, but the sizes are similar so
3239          * we'll assume they are same.  This assumption should not cause any
3240          * harm.  In worst case we will need to issue VOP_READDIR() once more.
3241          */
3242         datasz = count;
3243 
3244         /*
3245          * Make sure that there is room to read at least one entry
3246          * if any are available.
3247          */
3248         if (datasz < DIRENT64_RECLEN(MAXNAMELEN))
3249                 datasz = DIRENT64_RECLEN(MAXNAMELEN);
3250 
3251         data = kmem_alloc(datasz, KM_NOSLEEP);
3252         if (data == NULL) {
3253                 /* The allocation failed; downsize and wait for it this time */
3254                 if (datasz > MAXBSIZE)
3255                         datasz = MAXBSIZE;
3256                 data = kmem_alloc(datasz, KM_SLEEP);
3257         }
3258 
3259         uio.uio_iov = &iov;
3260         uio.uio_iovcnt = 1;
3261         uio.uio_segflg = UIO_SYSSPACE;
3262         uio.uio_extflg = UIO_COPY_CACHED;
3263         uio.uio_loffset = (offset_t)args->cookie;
3264         uio.uio_resid = datasz;
3265 
3266         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3267         eptr = &resp->resok.reply.entries;
3268         entry = NULL;
3269 
3270 getmoredents:
3271         iov.iov_base = data;
3272         iov.iov_len = datasz;
3273 
3274         error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3275         if (error) {
3276                 iseof = 0;
3277                 goto done;
3278         }
3279 
3280         if (iov.iov_len == datasz)
3281                 goto done;
3282 
3283         for (dp = (dirent64_t *)data; (char *)dp - data < datasz - iov.iov_len;
3284             dp = nextdp(dp)) {
3285                 char *name;
3286                 count3 esize;
3287 
3288                 if (dp->d_ino == 0) {
3289                         if (entry != NULL)
3290                                 entry->cookie = (cookie3)dp->d_off;
3291                         continue;
3292                 }
3293 
3294                 name = nfscmd_convname(ca, exi, dp->d_name,
3295                     NFSCMD_CONV_OUTBOUND, MAXPATHLEN + 1);
3296                 if (name == NULL) {
3297                         if (entry != NULL)
3298                                 entry->cookie = (cookie3)dp->d_off;
3299                         continue;
3300                 }
3301 
3302                 /*
3303                  * struct entry3:
3304                  *   fileid:            2
3305                  *   name (length):     1
3306                  *   name (data):       length (rounded up)
3307                  *   cookie:            2
3308                  *   nextentry (bool):  1
3309                  */
3310                 esize = (2 + 1 + 2 + 1) * BYTES_PER_XDR_UNIT +
3311                     RNDUP(strlen(name));
3312 
3313                 /* If the new entry does not fit, discard it */
3314                 if (esize > count - size) {
3315                         if (name != dp->d_name)
3316                                 kmem_free(name, MAXPATHLEN + 1);
3317                         iseof = 0;
3318                         goto done;
3319                 }
3320 
3321                 entry = kmem_alloc(sizeof (entry3), KM_SLEEP);
3322 
3323                 entry->fileid = (fileid3)dp->d_ino;
3324                 entry->name = strdup(name);
3325                 if (name != dp->d_name)
3326                         kmem_free(name, MAXPATHLEN + 1);
3327                 entry->cookie = (cookie3)dp->d_off;
3328 
3329                 size += esize;
3330 
3331                 /* Add the entry to the linked list */
3332                 *eptr = entry;
3333                 eptr = &entry->nextentry;
3334         }
3335 
3336         if (!iseof && size < count) {
3337                 uio.uio_resid = MIN(datasz, MAXBSIZE);
3338                 goto getmoredents;
3339         }
3340 
3341 done:
3342         *eptr = NULL;
3343 
3344         va.va_mask = AT_ALL;
3345         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3346 
3347         if (!iseof && resp->resok.reply.entries == NULL) {
3348                 if (error)
3349                         goto out;
3350                 resp->status = NFS3ERR_TOOSMALL;
3351                 goto out1;
3352         }
3353 
3354         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3355 
3356 #if 0 /* notyet */
3357         /*
3358          * Don't do this.  It causes local disk writes when just
3359          * reading the file and the overhead is deemed larger
3360          * than the benefit.
3361          */
3362         /*
3363          * Force modified metadata out to stable storage.
3364          */
3365         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3366 #endif
3367 
3368         resp->status = NFS3_OK;
3369         resp->resok.cookieverf = 0;
3370         resp->resok.reply.eof = iseof ? TRUE : FALSE;
3371 
3372         vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3373 
3374         DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3375             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3376             READDIR3res *, resp);
3377 
3378         VN_RELE(vp);
3379 
3380         if (data != NULL)
3381                 kmem_free(data, datasz);
3382 
3383         return;
3384 
3385 out:
3386         if (curthread->t_flag & T_WOULDBLOCK) {
3387                 curthread->t_flag &= ~T_WOULDBLOCK;
3388                 resp->status = NFS3ERR_JUKEBOX;
3389         } else
3390                 resp->status = puterrno3(error);
3391 out1:
3392         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3393 
3394         DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3395             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3396             READDIR3res *, resp);
3397 
3398         if (vp != NULL) {
3399                 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3400                 VN_RELE(vp);
3401         }
3402 
3403         if (data != NULL)
3404                 kmem_free(data, datasz);
3405 }
3406 
3407 void *
3408 rfs3_readdir_getfh(READDIR3args *args)
3409 {
3410         return (&args->dir);
3411 }
3412 
3413 void
3414 rfs3_readdir_free(READDIR3res *resp)
3415 {
3416         if (resp->status == NFS3_OK) {
3417                 entry3 *entry, *nentry;
3418 
3419                 for (entry = resp->resok.reply.entries; entry != NULL;
3420                     entry = nentry) {
3421                         nentry = entry->nextentry;
3422                         strfree(entry->name);
3423                         kmem_free(entry, sizeof (entry3));
3424                 }
3425         }
3426 }
3427 
3428 #ifdef nextdp
3429 #undef nextdp
3430 #endif
3431 #define nextdp(dp)      ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
3432 
3433 /* ARGSUSED */
3434 void
3435 rfs3_readdirplus(READDIRPLUS3args *args, READDIRPLUS3res *resp,
3436     struct exportinfo *exi, struct svc_req *req, cred_t *cr, bool_t ro)
3437 {
3438         int error;
3439         vnode_t *vp;
3440         struct vattr *vap;
3441         struct vattr va;
3442         struct iovec iov;
3443         struct uio uio;
3444         int iseof;
3445 
3446         count3 dircount = args->dircount;
3447         count3 maxcount = args->maxcount;
3448         count3 dirsize = 0;
3449         count3 size;            /* size of the READDIRPLUS3resok structure */
3450 
3451         size_t datasz;
3452         char *data = NULL;
3453         dirent64_t *dp;
3454 
3455         struct sockaddr *ca;
3456         entryplus3 **eptr;
3457         entryplus3 *entry;
3458 
3459         vp = nfs3_fhtovp(&args->dir, exi);
3460 
3461         DTRACE_NFSV3_5(op__readdirplus__start, struct svc_req *, req,
3462             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3463             READDIRPLUS3args *, args);
3464 
3465         if (vp == NULL) {
3466                 resp->status = NFS3ERR_STALE;
3467                 vap = NULL;
3468                 goto out1;
3469         }
3470 
3471         if (vp->v_type != VDIR) {
3472                 resp->status = NFS3ERR_NOTDIR;
3473                 vap = NULL;
3474                 goto out1;
3475         }
3476 
3477         if (is_system_labeled()) {
3478                 bslabel_t *clabel = req->rq_label;
3479 
3480                 ASSERT(clabel != NULL);
3481                 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3482                     char *, "got client label from request(1)",
3483                     struct svc_req *, req);
3484 
3485                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3486                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3487                             exi)) {
3488                                 resp->status = NFS3ERR_ACCES;
3489                                 vap = NULL;
3490                                 goto out1;
3491                         }
3492                 }
3493         }
3494 
3495         (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
3496 
3497         va.va_mask = AT_ALL;
3498         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3499 
3500         error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3501         if (error)
3502                 goto out;
3503 
3504         /*
3505          * Don't allow arbitrary counts for allocation
3506          */
3507         if (maxcount > rfs3_tsize(req))
3508                 maxcount = rfs3_tsize(req);
3509 
3510         /*
3511          * struct READDIRPLUS3resok:
3512          *   dir_attributes:    1 + NFS3_SIZEOF_FATTR3
3513          *   cookieverf:        2
3514          *   entries (bool):    1
3515          *   eof:               1
3516          */
3517         size = (1 + NFS3_SIZEOF_FATTR3 + 2 + 1 + 1) * BYTES_PER_XDR_UNIT;
3518 
3519         if (size > maxcount) {
3520                 resp->status = NFS3ERR_TOOSMALL;
3521                 goto out1;
3522         }
3523 
3524         /*
3525          * This is simplification.  The dirent64_t size is not the same as the
3526          * size of XDR representation of entryplus3 (excluding attributes and
3527          * handle), but the sizes are similar so we'll assume they are same.
3528          * This assumption should not cause any harm.  In worst case we will
3529          * need to issue VOP_READDIR() once more.
3530          */
3531 
3532         datasz = MIN(dircount, maxcount);
3533 
3534         /*
3535          * Make sure that there is room to read at least one entry
3536          * if any are available.
3537          */
3538         if (datasz < DIRENT64_RECLEN(MAXNAMELEN))
3539                 datasz = DIRENT64_RECLEN(MAXNAMELEN);
3540 
3541         data = kmem_alloc(datasz, KM_NOSLEEP);
3542         if (data == NULL) {
3543                 /* The allocation failed; downsize and wait for it this time */
3544                 if (datasz > MAXBSIZE)
3545                         datasz = MAXBSIZE;
3546                 data = kmem_alloc(datasz, KM_SLEEP);
3547         }
3548 
3549         uio.uio_iov = &iov;
3550         uio.uio_iovcnt = 1;
3551         uio.uio_segflg = UIO_SYSSPACE;
3552         uio.uio_extflg = UIO_COPY_CACHED;
3553         uio.uio_loffset = (offset_t)args->cookie;
3554         uio.uio_resid = datasz;
3555 
3556         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
3557         eptr = &resp->resok.reply.entries;
3558         entry = NULL;
3559 
3560 getmoredents:
3561         iov.iov_base = data;
3562         iov.iov_len = datasz;
3563 
3564         error = VOP_READDIR(vp, &uio, cr, &iseof, NULL, 0);
3565         if (error) {
3566                 iseof = 0;
3567                 goto done;
3568         }
3569 
3570         if (iov.iov_len == datasz)
3571                 goto done;
3572 
3573         for (dp = (dirent64_t *)data; (char *)dp - data < datasz - iov.iov_len;
3574             dp = nextdp(dp)) {
3575                 char *name;
3576                 vnode_t *nvp;
3577                 count3 edirsize;
3578                 count3 esize;
3579 
3580                 if (dp->d_ino == 0) {
3581                         if (entry != NULL)
3582                                 entry->cookie = (cookie3)dp->d_off;
3583                         continue;
3584                 }
3585 
3586                 name = nfscmd_convname(ca, exi, dp->d_name,
3587                     NFSCMD_CONV_OUTBOUND, MAXPATHLEN + 1);
3588                 if (name == NULL) {
3589                         if (entry != NULL)
3590                                 entry->cookie = (cookie3)dp->d_off;
3591                         continue;
3592                 }
3593 
3594                 /*
3595                  * struct entryplus3:
3596                  *   fileid:            2
3597                  *   name (length):     1
3598                  *   name (data):       length (rounded up)
3599                  *   cookie:            2
3600                  */
3601                 edirsize = (2 + 1 + 2) * BYTES_PER_XDR_UNIT +
3602                     RNDUP(strlen(name));
3603 
3604                 /*
3605                  * struct entryplus3:
3606                  *   attributes_follow: 1
3607                  *   handle_follows:    1
3608                  *   nextentry (bool):  1
3609                  */
3610                 esize = edirsize + (1 + 1 + 1) * BYTES_PER_XDR_UNIT;
3611 
3612                 /* If the new entry does not fit, we are done */
3613                 if (edirsize > dircount - dirsize || esize > maxcount - size) {
3614                         if (name != dp->d_name)
3615                                 kmem_free(name, MAXPATHLEN + 1);
3616                         iseof = 0;
3617                         error = 0;
3618                         goto done;
3619                 }
3620 
3621                 entry = kmem_alloc(sizeof (entryplus3), KM_SLEEP);
3622 
3623                 entry->fileid = (fileid3)dp->d_ino;
3624                 entry->name = strdup(name);
3625                 if (name != dp->d_name)
3626                         kmem_free(name, MAXPATHLEN + 1);
3627                 entry->cookie = (cookie3)dp->d_off;
3628 
3629                 error = VOP_LOOKUP(vp, dp->d_name, &nvp, NULL, 0, NULL, cr,
3630                     NULL, NULL, NULL);
3631                 if (error) {
3632                         entry->name_attributes.attributes = FALSE;
3633                         entry->name_handle.handle_follows = FALSE;
3634                 } else {
3635                         struct vattr nva;
3636                         struct vattr *nvap;
3637 
3638                         nva.va_mask = AT_ALL;
3639                         nvap = rfs4_delegated_getattr(nvp, &nva, 0, cr) ? NULL :
3640                             &nva;
3641 
3642                         /* Lie about the object type for a referral */
3643                         if (nvap != NULL && vn_is_nfs_reparse(nvp, cr))
3644                                 nvap->va_type = VLNK;
3645 
3646                         if (vn_ismntpt(nvp)) {
3647                                 entry->name_attributes.attributes = FALSE;
3648                                 entry->name_handle.handle_follows = FALSE;
3649                         } else {
3650                                 vattr_to_post_op_attr(nvap,
3651                                     &entry->name_attributes);
3652 
3653                                 error = makefh3(&entry->name_handle.handle, nvp,
3654                                     exi);
3655                                 if (!error)
3656                                         entry->name_handle.handle_follows =
3657                                             TRUE;
3658                                 else
3659                                         entry->name_handle.handle_follows =
3660                                             FALSE;
3661                         }
3662 
3663                         VN_RELE(nvp);
3664                 }
3665 
3666                 /*
3667                  * struct entryplus3 (optionally):
3668                  *   attributes:        NFS3_SIZEOF_FATTR3
3669                  *   handle length:     1
3670                  *   handle data:       length (rounded up)
3671                  */
3672                 if (entry->name_attributes.attributes == TRUE)
3673                         esize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
3674                 if (entry->name_handle.handle_follows == TRUE)
3675                         esize += 1 * BYTES_PER_XDR_UNIT +
3676                             RNDUP(entry->name_handle.handle.fh3_length);
3677 
3678                 /* If the new entry does not fit, discard it */
3679                 if (esize > maxcount - size) {
3680                         strfree(entry->name);
3681                         kmem_free(entry, sizeof (entryplus3));
3682                         iseof = 0;
3683                         error = 0;
3684                         goto done;
3685                 }
3686 
3687                 dirsize += edirsize;
3688                 size += esize;
3689 
3690                 /* Add the entry to the linked list */
3691                 *eptr = entry;
3692                 eptr = &entry->nextentry;
3693         }
3694 
3695         if (!iseof && dirsize < dircount && size < maxcount) {
3696                 uio.uio_resid = MIN(datasz, MAXBSIZE);
3697                 goto getmoredents;
3698         }
3699 
3700 done:
3701         *eptr = NULL;
3702 
3703         va.va_mask = AT_ALL;
3704         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3705 
3706         if (!iseof && resp->resok.reply.entries == NULL) {
3707                 if (error)
3708                         goto out;
3709                 resp->status = NFS3ERR_TOOSMALL;
3710                 goto out1;
3711         }
3712 
3713         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3714 
3715 #if 0 /* notyet */
3716         /*
3717          * Don't do this.  It causes local disk writes when just
3718          * reading the file and the overhead is deemed larger
3719          * than the benefit.
3720          */
3721         /*
3722          * Force modified metadata out to stable storage.
3723          */
3724         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3725 #endif
3726 
3727         resp->status = NFS3_OK;
3728         resp->resok.cookieverf = 0;
3729         resp->resok.reply.eof = iseof ? TRUE : FALSE;
3730 
3731         vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3732 
3733         DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3734             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3735             READDIRPLUS3res *, resp);
3736 
3737         VN_RELE(vp);
3738 
3739         if (data != NULL)
3740                 kmem_free(data, datasz);
3741 
3742         return;
3743 
3744 out:
3745         if (curthread->t_flag & T_WOULDBLOCK) {
3746                 curthread->t_flag &= ~T_WOULDBLOCK;
3747                 resp->status = NFS3ERR_JUKEBOX;
3748         } else {
3749                 resp->status = puterrno3(error);
3750         }
3751 out1:
3752         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3753 
3754         DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3755             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3756             READDIRPLUS3res *, resp);
3757 
3758         if (vp != NULL) {
3759                 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3760                 VN_RELE(vp);
3761         }
3762 
3763         if (data != NULL)
3764                 kmem_free(data, datasz);
3765 }
3766 
3767 void *
3768 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3769 {
3770         return (&args->dir);
3771 }
3772 
3773 void
3774 rfs3_readdirplus_free(READDIRPLUS3res *resp)
3775 {
3776         if (resp->status == NFS3_OK) {
3777                 entryplus3 *entry, *nentry;
3778 
3779                 for (entry = resp->resok.reply.entries; entry != NULL;
3780                     entry = nentry) {
3781                         nentry = entry->nextentry;
3782                         strfree(entry->name);
3783                         kmem_free(entry, sizeof (entryplus3));
3784                 }
3785         }
3786 }
3787 
3788 /* ARGSUSED */
3789 void
3790 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3791     struct svc_req *req, cred_t *cr, bool_t ro)
3792 {
3793         int error;
3794         vnode_t *vp;
3795         struct vattr *vap;
3796         struct vattr va;
3797         struct statvfs64 sb;
3798 
3799         vap = NULL;
3800 
3801         vp = nfs3_fhtovp(&args->fsroot, exi);
3802 
3803         DTRACE_NFSV3_5(op__fsstat__start, struct svc_req *, req,
3804             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3805             FSSTAT3args *, args);
3806 
3807         if (vp == NULL) {
3808                 error = ESTALE;
3809                 goto out;
3810         }
3811 
3812         if (is_system_labeled()) {
3813                 bslabel_t *clabel = req->rq_label;
3814 
3815                 ASSERT(clabel != NULL);
3816                 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3817                     "got client label from request(1)", struct svc_req *, req);
3818 
3819                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3820                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3821                             exi)) {
3822                                 resp->status = NFS3ERR_ACCES;
3823                                 goto out1;
3824                         }
3825                 }
 
3835 
3836         resp->status = NFS3_OK;
3837         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3838         if (sb.f_blocks != (fsblkcnt64_t)-1)
3839                 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3840         else
3841                 resp->resok.tbytes = (size3)sb.f_blocks;
3842         if (sb.f_bfree != (fsblkcnt64_t)-1)
3843                 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3844         else
3845                 resp->resok.fbytes = (size3)sb.f_bfree;
3846         if (sb.f_bavail != (fsblkcnt64_t)-1)
3847                 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3848         else
3849                 resp->resok.abytes = (size3)sb.f_bavail;
3850         resp->resok.tfiles = (size3)sb.f_files;
3851         resp->resok.ffiles = (size3)sb.f_ffree;
3852         resp->resok.afiles = (size3)sb.f_favail;
3853         resp->resok.invarsec = 0;
3854 
3855         DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3856             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3857             FSSTAT3res *, resp);
3858         VN_RELE(vp);
3859 
3860         return;
3861 
3862 out:
3863         if (curthread->t_flag & T_WOULDBLOCK) {
3864                 curthread->t_flag &= ~T_WOULDBLOCK;
3865                 resp->status = NFS3ERR_JUKEBOX;
3866         } else
3867                 resp->status = puterrno3(error);
3868 out1:
3869         DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3870             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3871             FSSTAT3res *, resp);
3872 
3873         if (vp != NULL)
3874                 VN_RELE(vp);
3875         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3876 }
3877 
3878 void *
3879 rfs3_fsstat_getfh(FSSTAT3args *args)
3880 {
3881         return (&args->fsroot);
3882 }
3883 
3884 /* ARGSUSED */
3885 void
3886 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3887     struct svc_req *req, cred_t *cr, bool_t ro)
3888 {
3889         vnode_t *vp;
3890         struct vattr *vap;
3891         struct vattr va;
3892         uint32_t xfer_size;
3893         ulong_t l = 0;
3894         int error;
3895 
3896         vp = nfs3_fhtovp(&args->fsroot, exi);
3897 
3898         DTRACE_NFSV3_5(op__fsinfo__start, struct svc_req *, req,
3899             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3900             FSINFO3args *, args);
3901 
3902         if (vp == NULL) {
3903                 if (curthread->t_flag & T_WOULDBLOCK) {
3904                         curthread->t_flag &= ~T_WOULDBLOCK;
3905                         resp->status = NFS3ERR_JUKEBOX;
3906                 } else
3907                         resp->status = NFS3ERR_STALE;
3908                 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3909                 goto out;
3910         }
3911 
3912         if (is_system_labeled()) {
3913                 bslabel_t *clabel = req->rq_label;
3914 
3915                 ASSERT(clabel != NULL);
3916                 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3917                     "got client label from request(1)", struct svc_req *, req);
3918 
3919                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3920                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
 
3954         /*
3955          * If the underlying file system does not support _PC_FILESIZEBITS,
3956          * return a reasonable default. Note that error code on VOP_PATHCONF
3957          * will be 0, even if the underlying file system does not support
3958          * _PC_FILESIZEBITS.
3959          */
3960         if (l == (ulong_t)-1) {
3961                 resp->resok.maxfilesize = MAXOFF32_T;
3962         } else {
3963                 if (l >= (sizeof (uint64_t) * 8))
3964                         resp->resok.maxfilesize = INT64_MAX;
3965                 else
3966                         resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3967         }
3968 
3969         resp->resok.time_delta.seconds = 0;
3970         resp->resok.time_delta.nseconds = 1000;
3971         resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3972             FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3973 
3974         DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
3975             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3976             FSINFO3res *, resp);
3977 
3978         VN_RELE(vp);
3979 
3980         return;
3981 
3982 out:
3983         DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
3984             cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi,
3985             FSINFO3res *, resp);
3986         if (vp != NULL)
3987                 VN_RELE(vp);
3988 }
3989 
3990 void *
3991 rfs3_fsinfo_getfh(FSINFO3args *args)
3992 {
3993         return (&args->fsroot);
3994 }
3995 
3996 /* ARGSUSED */
3997 void
3998 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
3999     struct svc_req *req, cred_t *cr, bool_t ro)
4000 {
4001         int error;
4002         vnode_t *vp;
4003         struct vattr *vap;
4004         struct vattr va;
4005         ulong_t val;
4006 
4007         vap = NULL;
4008 
4009         vp = nfs3_fhtovp(&args->object, exi);
4010 
4011         DTRACE_NFSV3_5(op__pathconf__start, struct svc_req *, req,
4012             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4013             PATHCONF3args *, args);
4014 
4015         if (vp == NULL) {
4016                 error = ESTALE;
4017                 goto out;
4018         }
4019 
4020         if (is_system_labeled()) {
4021                 bslabel_t *clabel = req->rq_label;
4022 
4023                 ASSERT(clabel != NULL);
4024                 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
4025                     "got client label from request(1)", struct svc_req *, req);
4026 
4027                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4028                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
4029                             exi)) {
4030                                 resp->status = NFS3ERR_ACCES;
4031                                 goto out1;
4032                         }
4033                 }
 
4049         error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
4050         if (error)
4051                 goto out;
4052         if (val == 1)
4053                 resp->resok.info.no_trunc = TRUE;
4054         else
4055                 resp->resok.info.no_trunc = FALSE;
4056 
4057         error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
4058         if (error)
4059                 goto out;
4060         if (val == 1)
4061                 resp->resok.info.chown_restricted = TRUE;
4062         else
4063                 resp->resok.info.chown_restricted = FALSE;
4064 
4065         resp->status = NFS3_OK;
4066         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4067         resp->resok.info.case_insensitive = FALSE;
4068         resp->resok.info.case_preserving = TRUE;
4069         DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4070             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4071             PATHCONF3res *, resp);
4072         VN_RELE(vp);
4073         return;
4074 
4075 out:
4076         if (curthread->t_flag & T_WOULDBLOCK) {
4077                 curthread->t_flag &= ~T_WOULDBLOCK;
4078                 resp->status = NFS3ERR_JUKEBOX;
4079         } else
4080                 resp->status = puterrno3(error);
4081 out1:
4082         DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4083             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4084             PATHCONF3res *, resp);
4085         if (vp != NULL)
4086                 VN_RELE(vp);
4087         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4088 }
4089 
4090 void *
4091 rfs3_pathconf_getfh(PATHCONF3args *args)
4092 {
4093         return (&args->object);
4094 }
4095 
4096 void
4097 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4098     struct svc_req *req, cred_t *cr, bool_t ro)
4099 {
4100         nfs3_srv_t *ns;
4101         int error;
4102         vnode_t *vp;
4103         struct vattr *bvap;
4104         struct vattr bva;
4105         struct vattr *avap;
4106         struct vattr ava;
4107 
4108         bvap = NULL;
4109         avap = NULL;
4110 
4111         vp = nfs3_fhtovp(&args->file, exi);
4112 
4113         DTRACE_NFSV3_5(op__commit__start, struct svc_req *, req,
4114             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4115             COMMIT3args *, args);
4116 
4117         if (vp == NULL) {
4118                 error = ESTALE;
4119                 goto out;
4120         }
4121 
4122         ns = zone_getspecific(rfs3_zone_key, curzone);
4123         bva.va_mask = AT_ALL;
4124         error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4125 
4126         /*
4127          * If we can't get the attributes, then we can't do the
4128          * right access checking.  So, we'll fail the request.
4129          */
4130         if (error)
4131                 goto out;
4132 
4133         bvap = &bva;
4134 
4135         if (rdonly(ro, vp)) {
4136                 resp->status = NFS3ERR_ROFS;
4137                 goto out1;
4138         }
4139 
4140         if (vp->v_type != VREG) {
4141                 resp->status = NFS3ERR_INVAL;
4142                 goto out1;
 
4155                                 resp->status = NFS3ERR_ACCES;
4156                                 goto out1;
4157                         }
4158                 }
4159         }
4160 
4161         if (crgetuid(cr) != bva.va_uid &&
4162             (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4163                 goto out;
4164 
4165         error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4166 
4167         ava.va_mask = AT_ALL;
4168         avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4169 
4170         if (error)
4171                 goto out;
4172 
4173         resp->status = NFS3_OK;
4174         vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4175         resp->resok.verf = ns->write3verf;
4176 
4177         DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4178             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4179             COMMIT3res *, resp);
4180 
4181         VN_RELE(vp);
4182 
4183         return;
4184 
4185 out:
4186         if (curthread->t_flag & T_WOULDBLOCK) {
4187                 curthread->t_flag &= ~T_WOULDBLOCK;
4188                 resp->status = NFS3ERR_JUKEBOX;
4189         } else
4190                 resp->status = puterrno3(error);
4191 out1:
4192         DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4193             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4194             COMMIT3res *, resp);
4195 
4196         if (vp != NULL)
4197                 VN_RELE(vp);
4198         vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4199 }
4200 
4201 void *
4202 rfs3_commit_getfh(COMMIT3args *args)
4203 {
4204         return (&args->file);
4205 }
4206 
4207 static int
4208 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4209 {
4210 
4211         vap->va_mask = 0;
4212 
4213         if (sap->mode.set_it) {
4214                 vap->va_mode = (mode_t)sap->mode.mode;
4215                 vap->va_mask |= AT_MODE;
4216         }
4217         if (sap->uid.set_it) {
4218                 vap->va_uid = (uid_t)sap->uid.uid;
4219                 vap->va_mask |= AT_UID;
4220         }
4221         if (sap->gid.set_it) {
4222                 vap->va_gid = (gid_t)sap->gid.gid;
4223                 vap->va_mask |= AT_GID;
 
4251                 /* check time validity */
4252                 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4253                         return (EOVERFLOW);
4254 #endif
4255                 /*
4256                  * nfs protocol defines times as unsigned so don't extend sign,
4257                  * unless sysadmin set nfs_allow_preepoch_time.
4258                  */
4259                 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4260                     sap->mtime.mtime.seconds);
4261                 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4262                 vap->va_mask |= AT_MTIME;
4263         } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4264                 gethrestime(&vap->va_mtime);
4265                 vap->va_mask |= AT_MTIME;
4266         }
4267 
4268         return (0);
4269 }
4270 
4271 static const ftype3 vt_to_nf3[] = {
4272         0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4273 };
4274 
4275 static int
4276 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4277 {
4278 
4279         ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4280         /* Return error if time or size overflow */
4281         if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4282                 return (EOVERFLOW);
4283         }
4284         fap->type = vt_to_nf3[vap->va_type];
4285         fap->mode = (mode3)(vap->va_mode & MODEMASK);
4286         fap->nlink = (uint32)vap->va_nlink;
4287         if (vap->va_uid == UID_NOBODY)
4288                 fap->uid = (uid3)NFS_UID_NOBODY;
4289         else
4290                 fap->uid = (uid3)vap->va_uid;
4291         if (vap->va_gid == GID_NOBODY)
 
4333         if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4334                 poap->attributes = TRUE;
4335         } else
4336                 poap->attributes = FALSE;
4337 }
4338 
4339 void
4340 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4341 {
4342 
4343         /* don't return attrs if time overflow */
4344         if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4345                 poap->attributes = TRUE;
4346         } else
4347                 poap->attributes = FALSE;
4348 }
4349 
4350 static void
4351 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4352 {
4353         vattr_to_pre_op_attr(bvap, &wccp->before);
4354         vattr_to_post_op_attr(avap, &wccp->after);
4355 }
4356 
4357 static int
4358 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4359 {
4360         struct clist    *wcl;
4361         int             wlist_len;
4362         count3          count = rok->count;
4363 
4364         wcl = args->wlist;
4365         if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE)
4366                 return (FALSE);
4367 
4368         wcl = args->wlist;
4369         rok->wlist_len = wlist_len;
4370         rok->wlist = wcl;
4371         return (TRUE);
4372 }
4373 
4374 /* ARGSUSED */
4375 static void *
4376 rfs3_zone_init(zoneid_t zoneid)
4377 {
4378         nfs3_srv_t *ns;
4379         struct rfs3_verf_overlay {
4380                 uint_t id; /* a "unique" identifier */
4381                 int ts; /* a unique timestamp */
4382         } *verfp;
4383         timestruc_t now;
4384 
4385         ns = kmem_zalloc(sizeof (*ns), KM_SLEEP);
4386 
4387         /*
4388          * The following algorithm attempts to find a unique verifier
4389          * to be used as the write verifier returned from the server
4390          * to the client.  It is important that this verifier change
4391          * whenever the server reboots.  Of secondary importance, it
4392          * is important for the verifier to be unique between two
4393          * different servers.
4394          *
4395          * Thus, an attempt is made to use the system hostid and the
4396          * current time in seconds when the nfssrv kernel module is
4397          * loaded.  It is assumed that an NFS server will not be able
4398          * to boot and then to reboot in less than a second.  If the
4399          * hostid has not been set, then the current high resolution
4400          * time is used.  This will ensure different verifiers each
4401          * time the server reboots and minimize the chances that two
4402          * different servers will have the same verifier.
4403          */
4404 
4405 #ifndef lint
4406         /*
4407          * We ASSERT that this constant logic expression is
4408          * always true because in the past, it wasn't.
4409          */
4410         ASSERT(sizeof (*verfp) <= sizeof (ns->write3verf));
4411 #endif
4412 
4413         gethrestime(&now);
4414         verfp = (struct rfs3_verf_overlay *)&ns->write3verf;
4415         verfp->ts = (int)now.tv_sec;
4416         verfp->id = zone_get_hostid(NULL);
4417 
4418         if (verfp->id == 0)
4419                 verfp->id = (uint_t)now.tv_nsec;
4420 
4421         return (ns);
4422 }
4423 
4424 /* ARGSUSED */
4425 static void
4426 rfs3_zone_fini(zoneid_t zoneid, void *data)
4427 {
4428         nfs3_srv_t *ns = data;
4429 
4430         kmem_free(ns, sizeof (*ns));
4431 }
4432 
4433 void
4434 rfs3_srvrinit(void)
4435 {
4436         nfs3_srv_caller_id = fs_new_caller_id();
4437         zone_key_create(&rfs3_zone_key, rfs3_zone_init, NULL, rfs3_zone_fini);
4438 }
4439 
4440 void
4441 rfs3_srvrfini(void)
4442 {
4443         /* Nothing to do */
4444 }
 |