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)
 
 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         if (exi != NULL)
 386                 exi_hold(exi);
 387 
 388         /*
 389          * Allow lookups from the root - the default
 390          * location of the public filehandle.
 391          */
 392         if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
 393                 dvp = rootdir;
 394                 VN_HOLD(dvp);
 395 
 396                 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
 397                     cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
 398         } else {
 399                 dvp = nfs3_fhtovp(&args->what.dir, exi);
 400 
 401                 DTRACE_NFSV3_4(op__lookup__start, struct svc_req *, req,
 402                     cred_t *, cr, vnode_t *, dvp, LOOKUP3args *, args);
 403 
 404                 if (dvp == NULL) {
 405                         error = ESTALE;
 406                         goto out;
 407                 }
 408         }
 409 
 410         dva.va_mask = AT_ALL;
 411         dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 412 
 413         if (args->what.name == nfs3nametoolong) {
 414                 resp->status = NFS3ERR_NAMETOOLONG;
 415                 goto out1;
 416         }
 417 
 418         if (args->what.name == NULL || *(args->what.name) == '\0') {
 419                 resp->status = NFS3ERR_ACCES;
 420                 goto out1;
 421         }
 422 
 423         fhp = &args->what.dir;
 424         if (strcmp(args->what.name, "..") == 0 &&
 425             EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
 426                 if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
 427                     (dvp->v_flag & VROOT)) {
 428                         /*
 429                          * special case for ".." and 'nohide'exported root
 430                          */
 431                         if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
 432                                 resp->status = NFS3ERR_ACCES;
 433                                 goto out1;
 434                         }
 435                 } else {
 436                         resp->status = NFS3ERR_NOENT;
 437                         goto out1;
 438                 }
 439         }
 440 
 441         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 442         name = nfscmd_convname(ca, exi, args->what.name,
 443             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
 444 
 445         if (name == NULL) {
 446                 resp->status = NFS3ERR_ACCES;
 447                 goto out1;
 448         }
 449 
 450         /*
 451          * If the public filehandle is used then allow
 452          * a multi-component lookup
 453          */
 454         if (PUBLIC_FH3(&args->what.dir)) {
 455                 publicfh_flag = TRUE;
 456 
 457                 exi_rele(exi);
 458 
 459                 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
 460                     &exi, &sec);
 461 
 462                 /*
 463                  * Since WebNFS may bypass MOUNT, we need to ensure this
 464                  * request didn't come from an unlabeled admin_low client.
 465                  */
 466                 if (is_system_labeled() && error == 0) {
 467                         int             addr_type;
 468                         void            *ipaddr;
 469                         tsol_tpc_t      *tp;
 470 
 471                         if (ca->sa_family == AF_INET) {
 472                                 addr_type = IPV4_VERSION;
 473                                 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
 474                         } else if (ca->sa_family == AF_INET6) {
 475                                 addr_type = IPV6_VERSION;
 476                                 ipaddr = &((struct sockaddr_in6 *)
 477                                     ca)->sin6_addr;
 
 521 
 522         if (error)
 523                 goto out;
 524 
 525         if (sec.sec_flags & SEC_QUERY) {
 526                 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
 527         } else {
 528                 error = makefh3(&resp->resok.object, vp, exi);
 529                 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
 530                         auth_weak = TRUE;
 531         }
 532 
 533         if (error) {
 534                 VN_RELE(vp);
 535                 goto out;
 536         }
 537 
 538         va.va_mask = AT_ALL;
 539         vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 540 
 541         exi_rele(exi);
 542         VN_RELE(vp);
 543 
 544         resp->status = NFS3_OK;
 545         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 546         vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
 547 
 548         /*
 549          * If it's public fh, no 0x81, and client's flavor is
 550          * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
 551          * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
 552          */
 553         if (auth_weak)
 554                 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
 555 
 556         DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
 557             cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
 558         VN_RELE(dvp);
 559 
 560         return;
 561 
 562 out:
 563         if (curthread->t_flag & T_WOULDBLOCK) {
 564                 curthread->t_flag &= ~T_WOULDBLOCK;
 565                 resp->status = NFS3ERR_JUKEBOX;
 566         } else
 567                 resp->status = puterrno3(error);
 568 out1:
 569         if (exi != NULL)
 570                 exi_rele(exi);
 571 
 572         DTRACE_NFSV3_4(op__lookup__done, struct svc_req *, req,
 573             cred_t *, cr, vnode_t *, dvp, LOOKUP3res *, resp);
 574 
 575         if (dvp != NULL)
 576                 VN_RELE(dvp);
 577         vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
 578 
 579 }
 580 
 581 void *
 582 rfs3_lookup_getfh(LOOKUP3args *args)
 583 {
 584 
 585         return (&args->what.dir);
 586 }
 587 
 588 /* ARGSUSED */
 589 void
 590 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
 591     struct svc_req *req, cred_t *cr, bool_t ro)
 592 {
 593         int error;
 594         vnode_t *vp;
 595         struct vattr *vap;
 596         struct vattr va;
 597         int checkwriteperm;
 598         boolean_t dominant_label = B_FALSE;
 599         boolean_t equal_label = B_FALSE;
 600         boolean_t admin_low_client;
 601 
 602         vap = NULL;
 603 
 604         vp = nfs3_fhtovp(&args->object, exi);
 605 
 606         DTRACE_NFSV3_4(op__access__start, struct svc_req *, req,
 607             cred_t *, cr, vnode_t *, vp, ACCESS3args *, args);
 608 
 609         if (vp == NULL) {
 610                 error = ESTALE;
 611                 goto out;
 612         }
 613 
 614         /*
 615          * If the file system is exported read only, it is not appropriate
 616          * to check write permissions for regular files and directories.
 617          * Special files are interpreted by the client, so the underlying
 618          * permissions are sent back to the client for interpretation.
 619          */
 620         if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
 621                 checkwriteperm = 0;
 622         else
 623                 checkwriteperm = 1;
 624 
 625         /*
 626          * We need the mode so that we can correctly determine access
 627          * permissions relative to a mandatory lock file.  Access to
 
 697                     equal_label)
 698                         resp->resok.access |= ACCESS3_DELETE;
 699         }
 700         if (args->access & ACCESS3_EXECUTE) {
 701                 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
 702                 if (error) {
 703                         if (curthread->t_flag & T_WOULDBLOCK)
 704                                 goto out;
 705                 } else if (!MANDLOCK(vp, va.va_mode) &&
 706                     (!is_system_labeled() || admin_low_client ||
 707                     dominant_label))
 708                         resp->resok.access |= ACCESS3_EXECUTE;
 709         }
 710 
 711         va.va_mask = AT_ALL;
 712         vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 713 
 714         resp->status = NFS3_OK;
 715         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 716 
 717         DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
 718             cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
 719 
 720         VN_RELE(vp);
 721 
 722         return;
 723 
 724 out:
 725         if (curthread->t_flag & T_WOULDBLOCK) {
 726                 curthread->t_flag &= ~T_WOULDBLOCK;
 727                 resp->status = NFS3ERR_JUKEBOX;
 728         } else
 729                 resp->status = puterrno3(error);
 730         DTRACE_NFSV3_4(op__access__done, struct svc_req *, req,
 731             cred_t *, cr, vnode_t *, vp, ACCESS3res *, resp);
 732         if (vp != NULL)
 733                 VN_RELE(vp);
 734         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
 735 }
 736 
 737 void *
 738 rfs3_access_getfh(ACCESS3args *args)
 739 {
 740 
 741         return (&args->object);
 742 }
 743 
 744 /* ARGSUSED */
 745 void
 746 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
 747     struct svc_req *req, cred_t *cr, bool_t ro)
 748 {
 749         int error;
 750         vnode_t *vp;
 751         struct vattr *vap;
 752         struct vattr va;
 753         struct iovec iov;
 754         struct uio uio;
 755         char *data;
 756         struct sockaddr *ca;
 757         char *name = NULL;
 758         int is_referral = 0;
 759 
 760         vap = NULL;
 761 
 762         vp = nfs3_fhtovp(&args->symlink, exi);
 763 
 764         DTRACE_NFSV3_4(op__readlink__start, struct svc_req *, req,
 765             cred_t *, cr, vnode_t *, vp, READLINK3args *, args);
 766 
 767         if (vp == NULL) {
 768                 error = ESTALE;
 769                 goto out;
 770         }
 771 
 772         va.va_mask = AT_ALL;
 773         error = VOP_GETATTR(vp, &va, 0, cr, NULL);
 774         if (error)
 775                 goto out;
 776 
 777         vap = &va;
 778 
 779         /* We lied about the object type for a referral */
 780         if (vn_is_nfs_reparse(vp, cr))
 781                 is_referral = 1;
 782 
 783         if (vp->v_type != VLNK && !is_referral) {
 784                 resp->status = NFS3ERR_INVAL;
 785                 goto out1;
 
 794                 bslabel_t *clabel = req->rq_label;
 795 
 796                 ASSERT(clabel != NULL);
 797                 DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
 798                     "got client label from request(1)", struct svc_req *, req);
 799 
 800                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
 801                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
 802                             exi)) {
 803                                 resp->status = NFS3ERR_ACCES;
 804                                 goto out1;
 805                         }
 806                 }
 807         }
 808 
 809         data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
 810 
 811         if (is_referral) {
 812                 char *s;
 813                 size_t strsz;
 814 
 815                 /* Get an artificial symlink based on a referral */
 816                 s = build_symlink(vp, cr, &strsz);
 817                 global_svstat_ptr[3][NFS_REFERLINKS].value.ui64++;
 818                 DTRACE_PROBE2(nfs3serv__func__referral__reflink,
 819                     vnode_t *, vp, char *, s);
 820                 if (s == NULL)
 821                         error = EINVAL;
 822                 else {
 823                         error = 0;
 824                         (void) strlcpy(data, s, MAXPATHLEN + 1);
 825                         kmem_free(s, strsz);
 826                 }
 827 
 828         } else {
 829 
 830                 iov.iov_base = data;
 831                 iov.iov_len = MAXPATHLEN;
 832                 uio.uio_iov = &iov;
 833                 uio.uio_iovcnt = 1;
 834                 uio.uio_segflg = UIO_SYSSPACE;
 835                 uio.uio_extflg = UIO_COPY_CACHED;
 836                 uio.uio_loffset = 0;
 837                 uio.uio_resid = MAXPATHLEN;
 
 865                 kmem_free(data, MAXPATHLEN + 1);
 866                 goto out;
 867         }
 868 
 869         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 870         name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
 871             MAXPATHLEN + 1);
 872 
 873         if (name == NULL) {
 874                 /*
 875                  * Even though the conversion failed, we return
 876                  * something. We just don't translate it.
 877                  */
 878                 name = data;
 879         }
 880 
 881         resp->status = NFS3_OK;
 882         vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
 883         resp->resok.data = name;
 884 
 885         DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
 886             cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
 887         VN_RELE(vp);
 888 
 889         if (name != data)
 890                 kmem_free(data, MAXPATHLEN + 1);
 891 
 892         return;
 893 
 894 out:
 895         if (curthread->t_flag & T_WOULDBLOCK) {
 896                 curthread->t_flag &= ~T_WOULDBLOCK;
 897                 resp->status = NFS3ERR_JUKEBOX;
 898         } else
 899                 resp->status = puterrno3(error);
 900 out1:
 901         DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
 902             cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
 903         if (vp != NULL)
 904                 VN_RELE(vp);
 905         vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
 906 }
 907 
 908 void *
 909 rfs3_readlink_getfh(READLINK3args *args)
 910 {
 911 
 912         return (&args->symlink);
 913 }
 914 
 915 void
 916 rfs3_readlink_free(READLINK3res *resp)
 917 {
 918 
 919         if (resp->status == NFS3_OK)
 920                 kmem_free(resp->resok.data, MAXPATHLEN + 1);
 921 }
 922 
 
 932         int error;
 933         vnode_t *vp;
 934         struct vattr *vap;
 935         struct vattr va;
 936         struct iovec iov, *iovp = NULL;
 937         int iovcnt;
 938         struct uio uio;
 939         u_offset_t offset;
 940         mblk_t *mp = NULL;
 941         int in_crit = 0;
 942         int need_rwunlock = 0;
 943         caller_context_t ct;
 944         int rdma_used = 0;
 945         int loaned_buffers;
 946         struct uio *uiop;
 947 
 948         vap = NULL;
 949 
 950         vp = nfs3_fhtovp(&args->file, exi);
 951 
 952         DTRACE_NFSV3_4(op__read__start, struct svc_req *, req,
 953             cred_t *, cr, vnode_t *, vp, READ3args *, args);
 954 
 955         if (vp == NULL) {
 956                 error = ESTALE;
 957                 goto out;
 958         }
 959 
 960         if (args->wlist) {
 961                 if (args->count > clist_len(args->wlist)) {
 962                         error = EINVAL;
 963                         goto out;
 964                 }
 965                 rdma_used = 1;
 966         }
 967 
 968         /* use loaned buffers for TCP */
 969         loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
 970 
 971         if (is_system_labeled()) {
 972                 bslabel_t *clabel = req->rq_label;
 973 
 974                 ASSERT(clabel != NULL);
 
1188                 resp->resok.eof = FALSE;
1189         resp->resok.data.data_len = resp->resok.count;
1190 
1191         if (mp)
1192                 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1193 
1194         resp->resok.data.mp = mp;
1195         resp->resok.size = (uint_t)args->count;
1196 
1197         if (rdma_used) {
1198                 resp->resok.data.data_val = (caddr_t)iov.iov_base;
1199                 if (!rdma_setup_read_data3(args, &(resp->resok))) {
1200                         resp->status = NFS3ERR_INVAL;
1201                 }
1202         } else {
1203                 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1204                 (resp->resok).wlist = NULL;
1205         }
1206 
1207 done:
1208         DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1209             cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1210 
1211         VN_RELE(vp);
1212 
1213         if (iovp != NULL)
1214                 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1215 
1216         return;
1217 
1218 out:
1219         if (curthread->t_flag & T_WOULDBLOCK) {
1220                 curthread->t_flag &= ~T_WOULDBLOCK;
1221                 resp->status = NFS3ERR_JUKEBOX;
1222         } else
1223                 resp->status = puterrno3(error);
1224 out1:
1225         DTRACE_NFSV3_4(op__read__done, struct svc_req *, req,
1226             cred_t *, cr, vnode_t *, vp, READ3res *, resp);
1227 
1228         if (vp != NULL) {
1229                 if (need_rwunlock)
1230                         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1231                 if (in_crit)
1232                         nbl_end_crit(vp);
1233                 VN_RELE(vp);
1234         }
1235         vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1236 
1237         if (iovp != NULL)
1238                 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1239 }
1240 
1241 void
1242 rfs3_read_free(READ3res *resp)
1243 {
1244         mblk_t *mp;
1245 
1246         if (resp->status == NFS3_OK) {
 
1251 }
1252 
1253 void *
1254 rfs3_read_getfh(READ3args *args)
1255 {
1256 
1257         return (&args->file);
1258 }
1259 
1260 #define MAX_IOVECS      12
1261 
1262 #ifdef DEBUG
1263 static int rfs3_write_hits = 0;
1264 static int rfs3_write_misses = 0;
1265 #endif
1266 
1267 void
1268 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1269     struct svc_req *req, cred_t *cr, bool_t ro)
1270 {
1271         int error;
1272         vnode_t *vp;
1273         struct vattr *bvap = NULL;
1274         struct vattr bva;
1275         struct vattr *avap = NULL;
1276         struct vattr ava;
1277         u_offset_t rlimit;
1278         struct uio uio;
1279         struct iovec iov[MAX_IOVECS];
1280         mblk_t *m;
1281         struct iovec *iovp;
1282         int iovcnt;
1283         int ioflag;
1284         cred_t *savecred;
1285         int in_crit = 0;
1286         int rwlock_ret = -1;
1287         caller_context_t ct;
1288 
1289         vp = nfs3_fhtovp(&args->file, exi);
1290 
1291         DTRACE_NFSV3_4(op__write__start, struct svc_req *, req,
1292             cred_t *, cr, vnode_t *, vp, WRITE3args *, args);
1293 
1294         if (vp == NULL) {
1295                 error = ESTALE;
1296                 goto err;
1297         }
1298 
1299         if (is_system_labeled()) {
1300                 bslabel_t *clabel = req->rq_label;
1301 
1302                 ASSERT(clabel != NULL);
1303                 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1304                     "got client label from request(1)", struct svc_req *, req);
1305 
1306                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1307                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1308                             exi)) {
1309                                 resp->status = NFS3ERR_ACCES;
1310                                 goto err1;
1311                         }
1312                 }
1313         }
1314 
1315         ct.cc_sysid = 0;
1316         ct.cc_pid = 0;
1317         ct.cc_caller_id = nfs3_srv_caller_id;
1318         ct.cc_flags = CC_DONTBLOCK;
 
1366 
1367         if (vp->v_type != VREG) {
1368                 resp->status = NFS3ERR_INVAL;
1369                 goto err1;
1370         }
1371 
1372         if (crgetuid(cr) != bva.va_uid &&
1373             (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1374                 goto err;
1375 
1376         if (MANDLOCK(vp, bva.va_mode)) {
1377                 resp->status = NFS3ERR_ACCES;
1378                 goto err1;
1379         }
1380 
1381         if (args->count == 0) {
1382                 resp->status = NFS3_OK;
1383                 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1384                 resp->resok.count = 0;
1385                 resp->resok.committed = args->stable;
1386                 resp->resok.verf = write3verf;
1387                 goto out;
1388         }
1389 
1390         if (args->mblk != NULL) {
1391                 iovcnt = 0;
1392                 for (m = args->mblk; m != NULL; m = m->b_cont)
1393                         iovcnt++;
1394                 if (iovcnt <= MAX_IOVECS) {
1395 #ifdef DEBUG
1396                         rfs3_write_hits++;
1397 #endif
1398                         iovp = iov;
1399                 } else {
1400 #ifdef DEBUG
1401                         rfs3_write_misses++;
1402 #endif
1403                         iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1404                 }
1405                 mblk_to_iov(args->mblk, iovcnt, iovp);
1406 
 
1468 
1469         /*
1470          * If we were unable to get the V_WRITELOCK_TRUE, then we
1471          * may not have accurate after attrs, so check if
1472          * we have both attributes, they have a non-zero va_seq, and
1473          * va_seq has changed by exactly one,
1474          * if not, turn off the before attr.
1475          */
1476         if (rwlock_ret != V_WRITELOCK_TRUE) {
1477                 if (bvap == NULL || avap == NULL ||
1478                     bvap->va_seq == 0 || avap->va_seq == 0 ||
1479                     avap->va_seq != (bvap->va_seq + 1)) {
1480                         bvap = NULL;
1481                 }
1482         }
1483 
1484         resp->status = NFS3_OK;
1485         vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1486         resp->resok.count = args->count - uio.uio_resid;
1487         resp->resok.committed = args->stable;
1488         resp->resok.verf = write3verf;
1489         goto out;
1490 
1491 err:
1492         if (curthread->t_flag & T_WOULDBLOCK) {
1493                 curthread->t_flag &= ~T_WOULDBLOCK;
1494                 resp->status = NFS3ERR_JUKEBOX;
1495         } else
1496                 resp->status = puterrno3(error);
1497 err1:
1498         vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1499 out:
1500         DTRACE_NFSV3_4(op__write__done, struct svc_req *, req,
1501             cred_t *, cr, vnode_t *, vp, WRITE3res *, resp);
1502 
1503         if (vp != NULL) {
1504                 if (rwlock_ret != -1)
1505                         VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1506                 if (in_crit)
1507                         nbl_end_crit(vp);
1508                 VN_RELE(vp);
1509         }
1510 }
1511 
1512 void *
1513 rfs3_write_getfh(WRITE3args *args)
1514 {
1515 
1516         return (&args->file);
1517 }
1518 
1519 void
1520 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1521     struct svc_req *req, cred_t *cr, bool_t ro)
 
1526         vnode_t *tvp = NULL;
1527         vnode_t *dvp;
1528         struct vattr *vap;
1529         struct vattr va;
1530         struct vattr *dbvap;
1531         struct vattr dbva;
1532         struct vattr *davap;
1533         struct vattr dava;
1534         enum vcexcl excl;
1535         nfstime3 *mtime;
1536         len_t reqsize;
1537         bool_t trunc;
1538         struct sockaddr *ca;
1539         char *name = NULL;
1540 
1541         dbvap = NULL;
1542         davap = NULL;
1543 
1544         dvp = nfs3_fhtovp(&args->where.dir, exi);
1545 
1546         DTRACE_NFSV3_4(op__create__start, struct svc_req *, req,
1547             cred_t *, cr, vnode_t *, dvp, CREATE3args *, args);
1548 
1549         if (dvp == NULL) {
1550                 error = ESTALE;
1551                 goto out;
1552         }
1553 
1554         dbva.va_mask = AT_ALL;
1555         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1556         davap = dbvap;
1557 
1558         if (args->where.name == nfs3nametoolong) {
1559                 resp->status = NFS3ERR_NAMETOOLONG;
1560                 goto out1;
1561         }
1562 
1563         if (args->where.name == NULL || *(args->where.name) == '\0') {
1564                 resp->status = NFS3ERR_ACCES;
1565                 goto out1;
1566         }
1567 
 
1826         else
1827                 resp->resok.obj.handle_follows = TRUE;
1828 
1829         /*
1830          * Force modified data and metadata out to stable storage.
1831          */
1832         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1833         (void) VOP_FSYNC(dvp, 0, cr, NULL);
1834 
1835         VN_RELE(vp);
1836         if (tvp != NULL) {
1837                 if (in_crit)
1838                         nbl_end_crit(tvp);
1839                 VN_RELE(tvp);
1840         }
1841 
1842         resp->status = NFS3_OK;
1843         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1844         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1845 
1846         DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1847             cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1848 
1849         VN_RELE(dvp);
1850         return;
1851 
1852 out:
1853         if (curthread->t_flag & T_WOULDBLOCK) {
1854                 curthread->t_flag &= ~T_WOULDBLOCK;
1855                 resp->status = NFS3ERR_JUKEBOX;
1856         } else
1857                 resp->status = puterrno3(error);
1858 out1:
1859         DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
1860             cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
1861 
1862         if (name != NULL && name != args->where.name)
1863                 kmem_free(name, MAXPATHLEN + 1);
1864 
1865         if (tvp != NULL) {
1866                 if (in_crit)
1867                         nbl_end_crit(tvp);
1868                 VN_RELE(tvp);
1869         }
1870         if (dvp != NULL)
1871                 VN_RELE(dvp);
1872         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1873 }
1874 
1875 void *
1876 rfs3_create_getfh(CREATE3args *args)
1877 {
1878 
1879         return (&args->where.dir);
1880 }
 
1883 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1884     struct svc_req *req, cred_t *cr, bool_t ro)
1885 {
1886         int error;
1887         vnode_t *vp = NULL;
1888         vnode_t *dvp;
1889         struct vattr *vap;
1890         struct vattr va;
1891         struct vattr *dbvap;
1892         struct vattr dbva;
1893         struct vattr *davap;
1894         struct vattr dava;
1895         struct sockaddr *ca;
1896         char *name = NULL;
1897 
1898         dbvap = NULL;
1899         davap = NULL;
1900 
1901         dvp = nfs3_fhtovp(&args->where.dir, exi);
1902 
1903         DTRACE_NFSV3_4(op__mkdir__start, struct svc_req *, req,
1904             cred_t *, cr, vnode_t *, dvp, MKDIR3args *, args);
1905 
1906         if (dvp == NULL) {
1907                 error = ESTALE;
1908                 goto out;
1909         }
1910 
1911         dbva.va_mask = AT_ALL;
1912         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1913         davap = dbvap;
1914 
1915         if (args->where.name == nfs3nametoolong) {
1916                 resp->status = NFS3ERR_NAMETOOLONG;
1917                 goto out1;
1918         }
1919 
1920         if (args->where.name == NULL || *(args->where.name) == '\0') {
1921                 resp->status = NFS3ERR_ACCES;
1922                 goto out1;
1923         }
1924 
 
1983         error = makefh3(&resp->resok.obj.handle, vp, exi);
1984         if (error)
1985                 resp->resok.obj.handle_follows = FALSE;
1986         else
1987                 resp->resok.obj.handle_follows = TRUE;
1988 
1989         va.va_mask = AT_ALL;
1990         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
1991 
1992         /*
1993          * Force modified data and metadata out to stable storage.
1994          */
1995         (void) VOP_FSYNC(vp, 0, cr, NULL);
1996 
1997         VN_RELE(vp);
1998 
1999         resp->status = NFS3_OK;
2000         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2001         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2002 
2003         DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2004             cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2005         VN_RELE(dvp);
2006 
2007         return;
2008 
2009 out:
2010         if (curthread->t_flag & T_WOULDBLOCK) {
2011                 curthread->t_flag &= ~T_WOULDBLOCK;
2012                 resp->status = NFS3ERR_JUKEBOX;
2013         } else
2014                 resp->status = puterrno3(error);
2015 out1:
2016         DTRACE_NFSV3_4(op__mkdir__done, struct svc_req *, req,
2017             cred_t *, cr, vnode_t *, dvp, MKDIR3res *, resp);
2018         if (dvp != NULL)
2019                 VN_RELE(dvp);
2020         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2021 }
2022 
2023 void *
2024 rfs3_mkdir_getfh(MKDIR3args *args)
2025 {
2026 
2027         return (&args->where.dir);
2028 }
2029 
2030 void
2031 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2032     struct svc_req *req, cred_t *cr, bool_t ro)
2033 {
2034         int error;
2035         vnode_t *vp;
2036         vnode_t *dvp;
2037         struct vattr *vap;
2038         struct vattr va;
2039         struct vattr *dbvap;
2040         struct vattr dbva;
2041         struct vattr *davap;
2042         struct vattr dava;
2043         struct sockaddr *ca;
2044         char *name = NULL;
2045         char *symdata = NULL;
2046 
2047         dbvap = NULL;
2048         davap = NULL;
2049 
2050         dvp = nfs3_fhtovp(&args->where.dir, exi);
2051 
2052         DTRACE_NFSV3_4(op__symlink__start, struct svc_req *, req,
2053             cred_t *, cr, vnode_t *, dvp, SYMLINK3args *, args);
2054 
2055         if (dvp == NULL) {
2056                 error = ESTALE;
2057                 goto err;
2058         }
2059 
2060         dbva.va_mask = AT_ALL;
2061         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2062         davap = dbvap;
2063 
2064         if (args->where.name == nfs3nametoolong) {
2065                 resp->status = NFS3ERR_NAMETOOLONG;
2066                 goto err1;
2067         }
2068 
2069         if (args->where.name == NULL || *(args->where.name) == '\0') {
2070                 resp->status = NFS3ERR_ACCES;
2071                 goto err1;
2072         }
2073 
 
2170         VN_RELE(vp);
2171 
2172         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2173         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2174         goto out;
2175 
2176 err:
2177         if (curthread->t_flag & T_WOULDBLOCK) {
2178                 curthread->t_flag &= ~T_WOULDBLOCK;
2179                 resp->status = NFS3ERR_JUKEBOX;
2180         } else
2181                 resp->status = puterrno3(error);
2182 err1:
2183         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2184 out:
2185         if (name != NULL && name != args->where.name)
2186                 kmem_free(name, MAXPATHLEN + 1);
2187         if (symdata != NULL && symdata != args->symlink.symlink_data)
2188                 kmem_free(symdata, MAXPATHLEN + 1);
2189 
2190         DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
2191             cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
2192 
2193         if (dvp != NULL)
2194                 VN_RELE(dvp);
2195 }
2196 
2197 void *
2198 rfs3_symlink_getfh(SYMLINK3args *args)
2199 {
2200 
2201         return (&args->where.dir);
2202 }
2203 
2204 void
2205 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2206     struct svc_req *req, cred_t *cr, bool_t ro)
2207 {
2208         int error;
2209         vnode_t *vp;
2210         vnode_t *realvp;
2211         vnode_t *dvp;
2212         struct vattr *vap;
2213         struct vattr va;
2214         struct vattr *dbvap;
2215         struct vattr dbva;
2216         struct vattr *davap;
2217         struct vattr dava;
2218         int mode;
2219         enum vcexcl excl;
2220         struct sockaddr *ca;
2221         char *name = NULL;
2222 
2223         dbvap = NULL;
2224         davap = NULL;
2225 
2226         dvp = nfs3_fhtovp(&args->where.dir, exi);
2227 
2228         DTRACE_NFSV3_4(op__mknod__start, struct svc_req *, req,
2229             cred_t *, cr, vnode_t *, dvp, MKNOD3args *, args);
2230 
2231         if (dvp == NULL) {
2232                 error = ESTALE;
2233                 goto out;
2234         }
2235 
2236         dbva.va_mask = AT_ALL;
2237         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2238         davap = dbvap;
2239 
2240         if (args->where.name == nfs3nametoolong) {
2241                 resp->status = NFS3ERR_NAMETOOLONG;
2242                 goto out1;
2243         }
2244 
2245         if (args->where.name == NULL || *(args->where.name) == '\0') {
2246                 resp->status = NFS3ERR_ACCES;
2247                 goto out1;
2248         }
2249 
 
2355         else
2356                 resp->resok.obj.handle_follows = TRUE;
2357 
2358         va.va_mask = AT_ALL;
2359         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2360 
2361         /*
2362          * Force modified metadata out to stable storage.
2363          *
2364          * if a underlying vp exists, pass it to VOP_FSYNC
2365          */
2366         if (VOP_REALVP(vp, &realvp, NULL) == 0)
2367                 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2368         else
2369                 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2370 
2371         VN_RELE(vp);
2372 
2373         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2374         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2375         DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2376             cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2377         VN_RELE(dvp);
2378         return;
2379 
2380 out:
2381         if (curthread->t_flag & T_WOULDBLOCK) {
2382                 curthread->t_flag &= ~T_WOULDBLOCK;
2383                 resp->status = NFS3ERR_JUKEBOX;
2384         } else
2385                 resp->status = puterrno3(error);
2386 out1:
2387         DTRACE_NFSV3_4(op__mknod__done, struct svc_req *, req,
2388             cred_t *, cr, vnode_t *, dvp, MKNOD3res *, resp);
2389         if (dvp != NULL)
2390                 VN_RELE(dvp);
2391         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2392 }
2393 
2394 void *
2395 rfs3_mknod_getfh(MKNOD3args *args)
2396 {
2397 
2398         return (&args->where.dir);
2399 }
2400 
2401 void
2402 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2403     struct svc_req *req, cred_t *cr, bool_t ro)
2404 {
2405         int error = 0;
2406         vnode_t *vp;
2407         struct vattr *bvap;
2408         struct vattr bva;
2409         struct vattr *avap;
2410         struct vattr ava;
2411         vnode_t *targvp = NULL;
2412         struct sockaddr *ca;
2413         char *name = NULL;
2414 
2415         bvap = NULL;
2416         avap = NULL;
2417 
2418         vp = nfs3_fhtovp(&args->object.dir, exi);
2419 
2420         DTRACE_NFSV3_4(op__remove__start, struct svc_req *, req,
2421             cred_t *, cr, vnode_t *, vp, REMOVE3args *, args);
2422 
2423         if (vp == NULL) {
2424                 error = ESTALE;
2425                 goto err;
2426         }
2427 
2428         bva.va_mask = AT_ALL;
2429         bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2430         avap = bvap;
2431 
2432         if (vp->v_type != VDIR) {
2433                 resp->status = NFS3ERR_NOTDIR;
2434                 goto err1;
2435         }
2436 
2437         if (args->object.name == nfs3nametoolong) {
2438                 resp->status = NFS3ERR_NAMETOOLONG;
2439                 goto err1;
2440         }
2441 
 
2509          * Force modified data and metadata out to stable storage.
2510          */
2511         (void) VOP_FSYNC(vp, 0, cr, NULL);
2512 
2513         if (error)
2514                 goto err;
2515 
2516         resp->status = NFS3_OK;
2517         vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2518         goto out;
2519 
2520 err:
2521         if (curthread->t_flag & T_WOULDBLOCK) {
2522                 curthread->t_flag &= ~T_WOULDBLOCK;
2523                 resp->status = NFS3ERR_JUKEBOX;
2524         } else
2525                 resp->status = puterrno3(error);
2526 err1:
2527         vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2528 out:
2529         DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
2530             cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
2531 
2532         if (name != NULL && name != args->object.name)
2533                 kmem_free(name, MAXPATHLEN + 1);
2534 
2535         if (vp != NULL)
2536                 VN_RELE(vp);
2537 }
2538 
2539 void *
2540 rfs3_remove_getfh(REMOVE3args *args)
2541 {
2542 
2543         return (&args->object.dir);
2544 }
2545 
2546 void
2547 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2548     struct svc_req *req, cred_t *cr, bool_t ro)
2549 {
2550         int error;
2551         vnode_t *vp;
2552         struct vattr *bvap;
2553         struct vattr bva;
2554         struct vattr *avap;
2555         struct vattr ava;
2556         struct sockaddr *ca;
2557         char *name = NULL;
2558 
2559         bvap = NULL;
2560         avap = NULL;
2561 
2562         vp = nfs3_fhtovp(&args->object.dir, exi);
2563 
2564         DTRACE_NFSV3_4(op__rmdir__start, struct svc_req *, req,
2565             cred_t *, cr, vnode_t *, vp, RMDIR3args *, args);
2566 
2567         if (vp == NULL) {
2568                 error = ESTALE;
2569                 goto err;
2570         }
2571 
2572         bva.va_mask = AT_ALL;
2573         bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2574         avap = bvap;
2575 
2576         if (vp->v_type != VDIR) {
2577                 resp->status = NFS3ERR_NOTDIR;
2578                 goto err1;
2579         }
2580 
2581         if (args->object.name == nfs3nametoolong) {
2582                 resp->status = NFS3ERR_NAMETOOLONG;
2583                 goto err1;
2584         }
2585 
 
2601                     "got client label from request(1)", struct svc_req *, req);
2602 
2603                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2604                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2605                             exi)) {
2606                                 resp->status = NFS3ERR_ACCES;
2607                                 goto err1;
2608                         }
2609                 }
2610         }
2611 
2612         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2613         name = nfscmd_convname(ca, exi, args->object.name,
2614             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2615 
2616         if (name == NULL) {
2617                 resp->status = NFS3ERR_INVAL;
2618                 goto err1;
2619         }
2620 
2621         error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
2622 
2623         if (name != args->object.name)
2624                 kmem_free(name, MAXPATHLEN + 1);
2625 
2626         ava.va_mask = AT_ALL;
2627         avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2628 
2629         /*
2630          * Force modified data and metadata out to stable storage.
2631          */
2632         (void) VOP_FSYNC(vp, 0, cr, NULL);
2633 
2634         if (error) {
2635                 /*
2636                  * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2637                  * if the directory is not empty.  A System V NFS server
2638                  * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2639                  * over the wire.
2640                  */
2641                 if (error == EEXIST)
2642                         error = ENOTEMPTY;
2643                 goto err;
2644         }
2645 
2646         resp->status = NFS3_OK;
2647         vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2648         goto out;
2649 
2650 err:
2651         if (curthread->t_flag & T_WOULDBLOCK) {
2652                 curthread->t_flag &= ~T_WOULDBLOCK;
2653                 resp->status = NFS3ERR_JUKEBOX;
2654         } else
2655                 resp->status = puterrno3(error);
2656 err1:
2657         vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2658 out:
2659         DTRACE_NFSV3_4(op__rmdir__done, struct svc_req *, req,
2660             cred_t *, cr, vnode_t *, vp, RMDIR3res *, resp);
2661         if (vp != NULL)
2662                 VN_RELE(vp);
2663 
2664 }
2665 
2666 void *
2667 rfs3_rmdir_getfh(RMDIR3args *args)
2668 {
2669 
2670         return (&args->object.dir);
2671 }
2672 
2673 void
2674 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2675     struct svc_req *req, cred_t *cr, bool_t ro)
2676 {
2677         int error = 0;
2678         vnode_t *fvp;
2679         vnode_t *tvp;
2680         vnode_t *targvp;
 
2685         struct vattr *tbvap;
2686         struct vattr tbva;
2687         struct vattr *tavap;
2688         struct vattr tava;
2689         nfs_fh3 *fh3;
2690         struct exportinfo *to_exi;
2691         vnode_t *srcvp = NULL;
2692         bslabel_t *clabel;
2693         struct sockaddr *ca;
2694         char *name = NULL;
2695         char *toname = NULL;
2696 
2697         fbvap = NULL;
2698         favap = NULL;
2699         tbvap = NULL;
2700         tavap = NULL;
2701         tvp = NULL;
2702 
2703         fvp = nfs3_fhtovp(&args->from.dir, exi);
2704 
2705         DTRACE_NFSV3_4(op__rename__start, struct svc_req *, req,
2706             cred_t *, cr, vnode_t *, fvp, RENAME3args *, args);
2707 
2708         if (fvp == NULL) {
2709                 error = ESTALE;
2710                 goto err;
2711         }
2712 
2713         if (is_system_labeled()) {
2714                 clabel = req->rq_label;
2715                 ASSERT(clabel != NULL);
2716                 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2717                     "got client label from request(1)", struct svc_req *, req);
2718 
2719                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2720                         if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2721                             exi)) {
2722                                 resp->status = NFS3ERR_ACCES;
2723                                 goto err1;
2724                         }
2725                 }
2726         }
 
2803         /*
2804          * Check for a conflict with a non-blocking mandatory share
2805          * reservation or V4 delegations.
2806          */
2807         error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2808             NULL, cr, NULL, NULL, NULL);
2809         if (error != 0)
2810                 goto err;
2811 
2812         /*
2813          * If we rename a delegated file we should recall the
2814          * delegation, since future opens should fail or would
2815          * refer to a new file.
2816          */
2817         if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2818                 resp->status = NFS3ERR_JUKEBOX;
2819                 goto err1;
2820         }
2821 
2822         /*
2823          * Check for renaming over a delegated file.  Check rfs4_deleg_policy
2824          * first to avoid VOP_LOOKUP if possible.
2825          */
2826         if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
2827             VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2828             NULL, NULL, NULL) == 0) {
2829 
2830                 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2831                         VN_RELE(targvp);
2832                         resp->status = NFS3ERR_JUKEBOX;
2833                         goto err1;
2834                 }
2835                 VN_RELE(targvp);
2836         }
2837 
2838         if (!nbl_need_check(srcvp)) {
2839                 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2840         } else {
2841                 nbl_start_crit(srcvp, RW_READER);
2842                 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2843                         error = EACCES;
2844                 else
2845                         error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2846                 nbl_end_crit(srcvp);
 
2870         vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2871         goto out;
2872 
2873 err:
2874         if (curthread->t_flag & T_WOULDBLOCK) {
2875                 curthread->t_flag &= ~T_WOULDBLOCK;
2876                 resp->status = NFS3ERR_JUKEBOX;
2877         } else {
2878                 resp->status = puterrno3(error);
2879         }
2880 err1:
2881         vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2882         vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2883 
2884 out:
2885         if (name != NULL && name != args->from.name)
2886                 kmem_free(name, MAXPATHLEN + 1);
2887         if (toname != NULL && toname != args->to.name)
2888                 kmem_free(toname, MAXPATHLEN + 1);
2889 
2890         DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
2891             cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
2892         if (fvp != NULL)
2893                 VN_RELE(fvp);
2894         if (tvp != NULL)
2895                 VN_RELE(tvp);
2896 }
2897 
2898 void *
2899 rfs3_rename_getfh(RENAME3args *args)
2900 {
2901 
2902         return (&args->from.dir);
2903 }
2904 
2905 void
2906 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2907     struct svc_req *req, cred_t *cr, bool_t ro)
2908 {
2909         int error;
2910         vnode_t *vp;
2911         vnode_t *dvp;
2912         struct vattr *vap;
2913         struct vattr va;
2914         struct vattr *bvap;
2915         struct vattr bva;
2916         struct vattr *avap;
2917         struct vattr ava;
2918         nfs_fh3 *fh3;
2919         struct exportinfo *to_exi;
2920         bslabel_t *clabel;
2921         struct sockaddr *ca;
2922         char *name = NULL;
2923 
2924         vap = NULL;
2925         bvap = NULL;
2926         avap = NULL;
2927         dvp = NULL;
2928 
2929         vp = nfs3_fhtovp(&args->file, exi);
2930 
2931         DTRACE_NFSV3_4(op__link__start, struct svc_req *, req,
2932             cred_t *, cr, vnode_t *, vp, LINK3args *, args);
2933 
2934         if (vp == NULL) {
2935                 error = ESTALE;
2936                 goto out;
2937         }
2938 
2939         va.va_mask = AT_ALL;
2940         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2941 
2942         fh3 = &args->link.dir;
2943         to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
2944         if (to_exi == NULL) {
2945                 resp->status = NFS3ERR_ACCES;
2946                 goto out1;
2947         }
2948         exi_rele(to_exi);
2949 
2950         if (to_exi != exi) {
2951                 resp->status = NFS3ERR_XDEV;
2952                 goto out1;
 
3024         va.va_mask = AT_ALL;
3025         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3026         ava.va_mask = AT_ALL;
3027         avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3028 
3029         /*
3030          * Force modified data and metadata out to stable storage.
3031          */
3032         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3033         (void) VOP_FSYNC(dvp, 0, cr, NULL);
3034 
3035         if (error)
3036                 goto out;
3037 
3038         VN_RELE(dvp);
3039 
3040         resp->status = NFS3_OK;
3041         vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3042         vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3043 
3044         DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3045             cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3046 
3047         VN_RELE(vp);
3048 
3049         return;
3050 
3051 out:
3052         if (curthread->t_flag & T_WOULDBLOCK) {
3053                 curthread->t_flag &= ~T_WOULDBLOCK;
3054                 resp->status = NFS3ERR_JUKEBOX;
3055         } else
3056                 resp->status = puterrno3(error);
3057 out1:
3058         if (name != NULL && name != args->link.name)
3059                 kmem_free(name, MAXPATHLEN + 1);
3060 
3061         DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
3062             cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
3063 
3064         if (vp != NULL)
3065                 VN_RELE(vp);
3066         if (dvp != NULL)
3067                 VN_RELE(dvp);
3068         vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3069         vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3070 }
3071 
3072 void *
3073 rfs3_link_getfh(LINK3args *args)
3074 {
3075 
3076         return (&args->file);
3077 }
3078 
3079 /*
3080  * This macro defines the size of a response which contains attribute
3081  * information and one directory entry (whose length is specified by
3082  * the macro parameter).  If the incoming request is larger than this,
 
3110 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3111     struct svc_req *req, cred_t *cr, bool_t ro)
3112 {
3113         int error;
3114         vnode_t *vp;
3115         struct vattr *vap;
3116         struct vattr va;
3117         struct iovec iov;
3118         struct uio uio;
3119         char *data;
3120         int iseof;
3121         int bufsize;
3122         int namlen;
3123         uint_t count;
3124         struct sockaddr *ca;
3125 
3126         vap = NULL;
3127 
3128         vp = nfs3_fhtovp(&args->dir, exi);
3129 
3130         DTRACE_NFSV3_4(op__readdir__start, struct svc_req *, req,
3131             cred_t *, cr, vnode_t *, vp, READDIR3args *, args);
3132 
3133         if (vp == NULL) {
3134                 error = ESTALE;
3135                 goto out;
3136         }
3137 
3138         if (is_system_labeled()) {
3139                 bslabel_t *clabel = req->rq_label;
3140 
3141                 ASSERT(clabel != NULL);
3142                 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3143                     "got client label from request(1)", struct svc_req *, req);
3144 
3145                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3146                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3147                             exi)) {
3148                                 resp->status = NFS3ERR_ACCES;
3149                                 goto out1;
3150                         }
3151                 }
 
3275         /*
3276          * Don't do this.  It causes local disk writes when just
3277          * reading the file and the overhead is deemed larger
3278          * than the benefit.
3279          */
3280         /*
3281          * Force modified metadata out to stable storage.
3282          */
3283         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3284 #endif
3285 
3286         resp->status = NFS3_OK;
3287         vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3288         resp->resok.cookieverf = 0;
3289         resp->resok.reply.entries = (entry3 *)data;
3290         resp->resok.reply.eof = iseof;
3291         resp->resok.size = count - uio.uio_resid;
3292         resp->resok.count = args->count;
3293         resp->resok.freecount = count;
3294 
3295         DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3296             cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3297 
3298         VN_RELE(vp);
3299 
3300         return;
3301 
3302 out:
3303         if (curthread->t_flag & T_WOULDBLOCK) {
3304                 curthread->t_flag &= ~T_WOULDBLOCK;
3305                 resp->status = NFS3ERR_JUKEBOX;
3306         } else
3307                 resp->status = puterrno3(error);
3308 out1:
3309         DTRACE_NFSV3_4(op__readdir__done, struct svc_req *, req,
3310             cred_t *, cr, vnode_t *, vp, READDIR3res *, resp);
3311 
3312         if (vp != NULL) {
3313                 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3314                 VN_RELE(vp);
3315         }
3316         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3317 }
3318 
3319 void *
3320 rfs3_readdir_getfh(READDIR3args *args)
3321 {
3322 
3323         return (&args->dir);
3324 }
3325 
3326 void
3327 rfs3_readdir_free(READDIR3res *resp)
3328 {
3329 
3330         if (resp->status == NFS3_OK)
3331                 kmem_free(resp->resok.reply.entries, resp->resok.freecount);
 
3381         struct vattr nva;
3382         entryplus3_info *infop = NULL;
3383         int size = 0;
3384         int nents = 0;
3385         int bufsize = 0;
3386         int entrysize = 0;
3387         int tofit = 0;
3388         int rd_unit = rfs3_readdir_unit;
3389         int prev_len;
3390         int space_left;
3391         int i;
3392         uint_t *namlen = NULL;
3393         char *ndata = NULL;
3394         struct sockaddr *ca;
3395         size_t ret;
3396 
3397         vap = NULL;
3398 
3399         vp = nfs3_fhtovp(&args->dir, exi);
3400 
3401         DTRACE_NFSV3_4(op__readdirplus__start, struct svc_req *, req,
3402             cred_t *, cr, vnode_t *, vp, READDIRPLUS3args *, args);
3403 
3404         if (vp == NULL) {
3405                 error = ESTALE;
3406                 goto out;
3407         }
3408 
3409         if (is_system_labeled()) {
3410                 bslabel_t *clabel = req->rq_label;
3411 
3412                 ASSERT(clabel != NULL);
3413                 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3414                     char *, "got client label from request(1)",
3415                     struct svc_req *, req);
3416 
3417                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3418                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3419                             exi)) {
3420                                 resp->status = NFS3ERR_ACCES;
3421                                 goto out1;
3422                         }
 
3664          * reading the file and the overhead is deemed larger
3665          * than the benefit.
3666          */
3667         /*
3668          * Force modified metadata out to stable storage.
3669          */
3670         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3671 #endif
3672 
3673         kmem_free(namlen, args->dircount);
3674 
3675         resp->status = NFS3_OK;
3676         vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3677         resp->resok.cookieverf = 0;
3678         resp->resok.reply.entries = (entryplus3 *)ndata;
3679         resp->resok.reply.eof = iseof;
3680         resp->resok.size = nents;
3681         resp->resok.count = args->dircount - ret;
3682         resp->resok.maxcount = args->maxcount;
3683 
3684         DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3685             cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3686         if (ndata != data)
3687                 kmem_free(data, args->dircount);
3688 
3689 
3690         VN_RELE(vp);
3691 
3692         return;
3693 
3694 out:
3695         if (curthread->t_flag & T_WOULDBLOCK) {
3696                 curthread->t_flag &= ~T_WOULDBLOCK;
3697                 resp->status = NFS3ERR_JUKEBOX;
3698         } else {
3699                 resp->status = puterrno3(error);
3700         }
3701 out1:
3702         DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
3703             cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
3704 
3705         if (vp != NULL) {
3706                 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3707                 VN_RELE(vp);
3708         }
3709 
3710         if (namlen != NULL)
3711                 kmem_free(namlen, args->dircount);
3712 
3713         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3714 }
3715 
3716 void *
3717 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3718 {
3719 
3720         return (&args->dir);
3721 }
3722 
3723 void
3724 rfs3_readdirplus_free(READDIRPLUS3res *resp)
 
3729                 kmem_free(resp->resok.infop,
3730                     resp->resok.size * sizeof (struct entryplus3_info));
3731         }
3732 }
3733 
3734 /* ARGSUSED */
3735 void
3736 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3737     struct svc_req *req, cred_t *cr, bool_t ro)
3738 {
3739         int error;
3740         vnode_t *vp;
3741         struct vattr *vap;
3742         struct vattr va;
3743         struct statvfs64 sb;
3744 
3745         vap = NULL;
3746 
3747         vp = nfs3_fhtovp(&args->fsroot, exi);
3748 
3749         DTRACE_NFSV3_4(op__fsstat__start, struct svc_req *, req,
3750             cred_t *, cr, vnode_t *, vp, FSSTAT3args *, args);
3751 
3752         if (vp == NULL) {
3753                 error = ESTALE;
3754                 goto out;
3755         }
3756 
3757         if (is_system_labeled()) {
3758                 bslabel_t *clabel = req->rq_label;
3759 
3760                 ASSERT(clabel != NULL);
3761                 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3762                     "got client label from request(1)", struct svc_req *, req);
3763 
3764                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3765                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3766                             exi)) {
3767                                 resp->status = NFS3ERR_ACCES;
3768                                 goto out1;
3769                         }
3770                 }
 
3780 
3781         resp->status = NFS3_OK;
3782         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3783         if (sb.f_blocks != (fsblkcnt64_t)-1)
3784                 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3785         else
3786                 resp->resok.tbytes = (size3)sb.f_blocks;
3787         if (sb.f_bfree != (fsblkcnt64_t)-1)
3788                 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3789         else
3790                 resp->resok.fbytes = (size3)sb.f_bfree;
3791         if (sb.f_bavail != (fsblkcnt64_t)-1)
3792                 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3793         else
3794                 resp->resok.abytes = (size3)sb.f_bavail;
3795         resp->resok.tfiles = (size3)sb.f_files;
3796         resp->resok.ffiles = (size3)sb.f_ffree;
3797         resp->resok.afiles = (size3)sb.f_favail;
3798         resp->resok.invarsec = 0;
3799 
3800         DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3801             cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3802         VN_RELE(vp);
3803 
3804         return;
3805 
3806 out:
3807         if (curthread->t_flag & T_WOULDBLOCK) {
3808                 curthread->t_flag &= ~T_WOULDBLOCK;
3809                 resp->status = NFS3ERR_JUKEBOX;
3810         } else
3811                 resp->status = puterrno3(error);
3812 out1:
3813         DTRACE_NFSV3_4(op__fsstat__done, struct svc_req *, req,
3814             cred_t *, cr, vnode_t *, vp, FSSTAT3res *, resp);
3815 
3816         if (vp != NULL)
3817                 VN_RELE(vp);
3818         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3819 }
3820 
3821 void *
3822 rfs3_fsstat_getfh(FSSTAT3args *args)
3823 {
3824 
3825         return (&args->fsroot);
3826 }
3827 
3828 /* ARGSUSED */
3829 void
3830 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3831     struct svc_req *req, cred_t *cr, bool_t ro)
3832 {
3833         vnode_t *vp;
3834         struct vattr *vap;
3835         struct vattr va;
3836         uint32_t xfer_size;
3837         ulong_t l = 0;
3838         int error;
3839 
3840         vp = nfs3_fhtovp(&args->fsroot, exi);
3841 
3842         DTRACE_NFSV3_4(op__fsinfo__start, struct svc_req *, req,
3843             cred_t *, cr, vnode_t *, vp, FSINFO3args *, args);
3844 
3845         if (vp == NULL) {
3846                 if (curthread->t_flag & T_WOULDBLOCK) {
3847                         curthread->t_flag &= ~T_WOULDBLOCK;
3848                         resp->status = NFS3ERR_JUKEBOX;
3849                 } else
3850                         resp->status = NFS3ERR_STALE;
3851                 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3852                 goto out;
3853         }
3854 
3855         if (is_system_labeled()) {
3856                 bslabel_t *clabel = req->rq_label;
3857 
3858                 ASSERT(clabel != NULL);
3859                 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3860                     "got client label from request(1)", struct svc_req *, req);
3861 
3862                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3863                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
 
3897         /*
3898          * If the underlying file system does not support _PC_FILESIZEBITS,
3899          * return a reasonable default. Note that error code on VOP_PATHCONF
3900          * will be 0, even if the underlying file system does not support
3901          * _PC_FILESIZEBITS.
3902          */
3903         if (l == (ulong_t)-1) {
3904                 resp->resok.maxfilesize = MAXOFF32_T;
3905         } else {
3906                 if (l >= (sizeof (uint64_t) * 8))
3907                         resp->resok.maxfilesize = INT64_MAX;
3908                 else
3909                         resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3910         }
3911 
3912         resp->resok.time_delta.seconds = 0;
3913         resp->resok.time_delta.nseconds = 1000;
3914         resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3915             FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3916 
3917         DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3918             cred_t *, cr, vnode_t *, vp, FSINFO3res *, resp);
3919 
3920         VN_RELE(vp);
3921 
3922         return;
3923 
3924 out:
3925         DTRACE_NFSV3_4(op__fsinfo__done, struct svc_req *, req,
3926             cred_t *, cr, vnode_t *, NULL, FSINFO3res *, resp);
3927         if (vp != NULL)
3928                 VN_RELE(vp);
3929 }
3930 
3931 void *
3932 rfs3_fsinfo_getfh(FSINFO3args *args)
3933 {
3934         return (&args->fsroot);
3935 }
3936 
3937 /* ARGSUSED */
3938 void
3939 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *resp, struct exportinfo *exi,
3940     struct svc_req *req, cred_t *cr, bool_t ro)
3941 {
3942         int error;
3943         vnode_t *vp;
3944         struct vattr *vap;
3945         struct vattr va;
3946         ulong_t val;
3947 
3948         vap = NULL;
3949 
3950         vp = nfs3_fhtovp(&args->object, exi);
3951 
3952         DTRACE_NFSV3_4(op__pathconf__start, struct svc_req *, req,
3953             cred_t *, cr, vnode_t *, vp, PATHCONF3args *, args);
3954 
3955         if (vp == NULL) {
3956                 error = ESTALE;
3957                 goto out;
3958         }
3959 
3960         if (is_system_labeled()) {
3961                 bslabel_t *clabel = req->rq_label;
3962 
3963                 ASSERT(clabel != NULL);
3964                 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
3965                     "got client label from request(1)", struct svc_req *, req);
3966 
3967                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3968                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3969                             exi)) {
3970                                 resp->status = NFS3ERR_ACCES;
3971                                 goto out1;
3972                         }
3973                 }
 
3989         error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
3990         if (error)
3991                 goto out;
3992         if (val == 1)
3993                 resp->resok.info.no_trunc = TRUE;
3994         else
3995                 resp->resok.info.no_trunc = FALSE;
3996 
3997         error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
3998         if (error)
3999                 goto out;
4000         if (val == 1)
4001                 resp->resok.info.chown_restricted = TRUE;
4002         else
4003                 resp->resok.info.chown_restricted = FALSE;
4004 
4005         resp->status = NFS3_OK;
4006         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4007         resp->resok.info.case_insensitive = FALSE;
4008         resp->resok.info.case_preserving = TRUE;
4009         DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4010             cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
4011         VN_RELE(vp);
4012         return;
4013 
4014 out:
4015         if (curthread->t_flag & T_WOULDBLOCK) {
4016                 curthread->t_flag &= ~T_WOULDBLOCK;
4017                 resp->status = NFS3ERR_JUKEBOX;
4018         } else
4019                 resp->status = puterrno3(error);
4020 out1:
4021         DTRACE_NFSV3_4(op__pathconf__done, struct svc_req *, req,
4022             cred_t *, cr, vnode_t *, vp, PATHCONF3res *, resp);
4023         if (vp != NULL)
4024                 VN_RELE(vp);
4025         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4026 }
4027 
4028 void *
4029 rfs3_pathconf_getfh(PATHCONF3args *args)
4030 {
4031 
4032         return (&args->object);
4033 }
4034 
4035 void
4036 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4037     struct svc_req *req, cred_t *cr, bool_t ro)
4038 {
4039         int error;
4040         vnode_t *vp;
4041         struct vattr *bvap;
4042         struct vattr bva;
4043         struct vattr *avap;
4044         struct vattr ava;
4045 
4046         bvap = NULL;
4047         avap = NULL;
4048 
4049         vp = nfs3_fhtovp(&args->file, exi);
4050 
4051         DTRACE_NFSV3_4(op__commit__start, struct svc_req *, req,
4052             cred_t *, cr, vnode_t *, vp, COMMIT3args *, args);
4053 
4054         if (vp == NULL) {
4055                 error = ESTALE;
4056                 goto out;
4057         }
4058 
4059         bva.va_mask = AT_ALL;
4060         error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4061 
4062         /*
4063          * If we can't get the attributes, then we can't do the
4064          * right access checking.  So, we'll fail the request.
4065          */
4066         if (error)
4067                 goto out;
4068 
4069         bvap = &bva;
4070 
4071         if (rdonly(ro, vp)) {
4072                 resp->status = NFS3ERR_ROFS;
4073                 goto out1;
4074         }
4075 
4076         if (vp->v_type != VREG) {
4077                 resp->status = NFS3ERR_INVAL;
4078                 goto out1;
 
4091                                 resp->status = NFS3ERR_ACCES;
4092                                 goto out1;
4093                         }
4094                 }
4095         }
4096 
4097         if (crgetuid(cr) != bva.va_uid &&
4098             (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4099                 goto out;
4100 
4101         error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4102 
4103         ava.va_mask = AT_ALL;
4104         avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4105 
4106         if (error)
4107                 goto out;
4108 
4109         resp->status = NFS3_OK;
4110         vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4111         resp->resok.verf = write3verf;
4112 
4113         DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4114             cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4115 
4116         VN_RELE(vp);
4117 
4118         return;
4119 
4120 out:
4121         if (curthread->t_flag & T_WOULDBLOCK) {
4122                 curthread->t_flag &= ~T_WOULDBLOCK;
4123                 resp->status = NFS3ERR_JUKEBOX;
4124         } else
4125                 resp->status = puterrno3(error);
4126 out1:
4127         DTRACE_NFSV3_4(op__commit__done, struct svc_req *, req,
4128             cred_t *, cr, vnode_t *, vp, COMMIT3res *, resp);
4129 
4130         if (vp != NULL)
4131                 VN_RELE(vp);
4132         vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4133 }
4134 
4135 void *
4136 rfs3_commit_getfh(COMMIT3args *args)
4137 {
4138 
4139         return (&args->file);
4140 }
4141 
4142 static int
4143 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4144 {
4145 
4146         vap->va_mask = 0;
4147 
4148         if (sap->mode.set_it) {
 
4186                 /* check time validity */
4187                 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4188                         return (EOVERFLOW);
4189 #endif
4190                 /*
4191                  * nfs protocol defines times as unsigned so don't extend sign,
4192                  * unless sysadmin set nfs_allow_preepoch_time.
4193                  */
4194                 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4195                     sap->mtime.mtime.seconds);
4196                 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4197                 vap->va_mask |= AT_MTIME;
4198         } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4199                 gethrestime(&vap->va_mtime);
4200                 vap->va_mask |= AT_MTIME;
4201         }
4202 
4203         return (0);
4204 }
4205 
4206 static ftype3 vt_to_nf3[] = {
4207         0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4208 };
4209 
4210 static int
4211 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4212 {
4213 
4214         ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4215         /* Return error if time or size overflow */
4216         if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4217                 return (EOVERFLOW);
4218         }
4219         fap->type = vt_to_nf3[vap->va_type];
4220         fap->mode = (mode3)(vap->va_mode & MODEMASK);
4221         fap->nlink = (uint32)vap->va_nlink;
4222         if (vap->va_uid == UID_NOBODY)
4223                 fap->uid = (uid3)NFS_UID_NOBODY;
4224         else
4225                 fap->uid = (uid3)vap->va_uid;
4226         if (vap->va_gid == GID_NOBODY)
 
4268         if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4269                 poap->attributes = TRUE;
4270         } else
4271                 poap->attributes = FALSE;
4272 }
4273 
4274 void
4275 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4276 {
4277 
4278         /* don't return attrs if time overflow */
4279         if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4280                 poap->attributes = TRUE;
4281         } else
4282                 poap->attributes = FALSE;
4283 }
4284 
4285 static void
4286 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4287 {
4288 
4289         vattr_to_pre_op_attr(bvap, &wccp->before);
4290         vattr_to_post_op_attr(avap, &wccp->after);
4291 }
4292 
4293 void
4294 rfs3_srvrinit(void)
4295 {
4296         struct rfs3_verf_overlay {
4297                 uint_t id; /* a "unique" identifier */
4298                 int ts; /* a unique timestamp */
4299         } *verfp;
4300         timestruc_t now;
4301 
4302         /*
4303          * The following algorithm attempts to find a unique verifier
4304          * to be used as the write verifier returned from the server
4305          * to the client.  It is important that this verifier change
4306          * whenever the server reboots.  Of secondary importance, it
4307          * is important for the verifier to be unique between two
4308          * different servers.
4309          *
4310          * Thus, an attempt is made to use the system hostid and the
4311          * current time in seconds when the nfssrv kernel module is
4312          * loaded.  It is assumed that an NFS server will not be able
4313          * to boot and then to reboot in less than a second.  If the
4314          * hostid has not been set, then the current high resolution
4315          * time is used.  This will ensure different verifiers each
4316          * time the server reboots and minimize the chances that two
4317          * different servers will have the same verifier.
4318          */
4319 
4320 #ifndef lint
4321         /*
4322          * We ASSERT that this constant logic expression is
4323          * always true because in the past, it wasn't.
4324          */
4325         ASSERT(sizeof (*verfp) <= sizeof (write3verf));
4326 #endif
4327 
4328         gethrestime(&now);
4329         verfp = (struct rfs3_verf_overlay *)&write3verf;
4330         verfp->ts = (int)now.tv_sec;
4331         verfp->id = zone_get_hostid(NULL);
4332 
4333         if (verfp->id == 0)
4334                 verfp->id = (uint_t)now.tv_nsec;
4335 
4336         nfs3_srv_caller_id = fs_new_caller_id();
4337 
4338 }
4339 
4340 static int
4341 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4342 {
4343         struct clist    *wcl;
4344         int             wlist_len;
4345         count3          count = rok->count;
4346 
4347         wcl = args->wlist;
4348         if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE) {
4349                 return (FALSE);
4350         }
4351 
4352         wcl = args->wlist;
4353         rok->wlist_len = wlist_len;
4354         rok->wlist = wcl;
4355         return (TRUE);
4356 }
4357 
4358 void
4359 rfs3_srvrfini(void)
4360 {
4361         /* Nothing to do */
4362 }
 | 
 
 
   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 
  95 static nfs3_srv_t *
  96 nfs3_get_srv(void)
  97 {
  98         nfs_globals_t *ng = nfs_srv_getzg();
  99         nfs3_srv_t *srv = ng->nfs3_srv;
 100         ASSERT(srv != NULL);
 101         return (srv);
 102 }
 103 
 104 /* ARGSUSED */
 105 void
 106 rfs3_getattr(GETATTR3args *args, GETATTR3res *resp, struct exportinfo *exi,
 107     struct svc_req *req, cred_t *cr, bool_t ro)
 108 {
 109         int error;
 110         vnode_t *vp;
 111         struct vattr va;
 112 
 113         vp = nfs3_fhtovp(&args->object, exi);
 114 
 115         DTRACE_NFSV3_5(op__getattr__start, struct svc_req *, req,
 116             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 117             GETATTR3args *, args);
 118 
 119         if (vp == NULL) {
 120                 error = ESTALE;
 121                 goto out;
 122         }
 123 
 124         va.va_mask = AT_ALL;
 125         error = rfs4_delegated_getattr(vp, &va, 0, cr);
 126 
 127         if (!error) {
 128                 /* Lie about the object type for a referral */
 129                 if (vn_is_nfs_reparse(vp, cr))
 130                         va.va_type = VLNK;
 131 
 132                 /* overflow error if time or size is out of range */
 133                 error = vattr_to_fattr3(&va, &resp->resok.obj_attributes);
 134                 if (error)
 135                         goto out;
 136                 resp->status = NFS3_OK;
 137 
 138                 DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
 139                     cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 140                     GETATTR3res *, resp);
 141 
 142                 VN_RELE(vp);
 143 
 144                 return;
 145         }
 146 
 147 out:
 148         if (curthread->t_flag & T_WOULDBLOCK) {
 149                 curthread->t_flag &= ~T_WOULDBLOCK;
 150                 resp->status = NFS3ERR_JUKEBOX;
 151         } else
 152                 resp->status = puterrno3(error);
 153 
 154         DTRACE_NFSV3_5(op__getattr__done, struct svc_req *, req,
 155             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 156             GETATTR3res *, resp);
 157 
 158         if (vp != NULL)
 159                 VN_RELE(vp);
 160 }
 161 
 162 void *
 163 rfs3_getattr_getfh(GETATTR3args *args)
 164 {
 165 
 166         return (&args->object);
 167 }
 168 
 169 void
 170 rfs3_setattr(SETATTR3args *args, SETATTR3res *resp, struct exportinfo *exi,
 171     struct svc_req *req, cred_t *cr, bool_t ro)
 172 {
 173         int error;
 174         vnode_t *vp;
 175         struct vattr *bvap;
 176         struct vattr bva;
 177         struct vattr *avap;
 178         struct vattr ava;
 179         int flag;
 180         int in_crit = 0;
 181         struct flock64 bf;
 182         caller_context_t ct;
 183 
 184         bvap = NULL;
 185         avap = NULL;
 186 
 187         vp = nfs3_fhtovp(&args->object, exi);
 188 
 189         DTRACE_NFSV3_5(op__setattr__start, struct svc_req *, req,
 190             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 191             SETATTR3args *, args);
 192 
 193         if (vp == NULL) {
 194                 error = ESTALE;
 195                 goto out;
 196         }
 197 
 198         error = sattr3_to_vattr(&args->new_attributes, &ava);
 199         if (error)
 200                 goto out;
 201 
 202         if (is_system_labeled()) {
 203                 bslabel_t *clabel = req->rq_label;
 204 
 205                 ASSERT(clabel != NULL);
 206                 DTRACE_PROBE2(tx__rfs3__log__info__opsetattr__clabel, char *,
 207                     "got client label from request(1)", struct svc_req *, req);
 208 
 209                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
 210                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
 211                             exi)) {
 
 332                 goto out1;
 333         }
 334 
 335         ava.va_mask = AT_ALL;
 336         avap = rfs4_delegated_getattr(vp, &ava, 0, cr) ? NULL : &ava;
 337 
 338         /*
 339          * Force modified metadata out to stable storage.
 340          */
 341         (void) VOP_FSYNC(vp, FNODSYNC, cr, &ct);
 342 
 343         if (error)
 344                 goto out;
 345 
 346         if (in_crit)
 347                 nbl_end_crit(vp);
 348 
 349         resp->status = NFS3_OK;
 350         vattr_to_wcc_data(bvap, avap, &resp->resok.obj_wcc);
 351 
 352         DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
 353             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 354             SETATTR3res *, resp);
 355 
 356         VN_RELE(vp);
 357 
 358         return;
 359 
 360 out:
 361         if (curthread->t_flag & T_WOULDBLOCK) {
 362                 curthread->t_flag &= ~T_WOULDBLOCK;
 363                 resp->status = NFS3ERR_JUKEBOX;
 364         } else
 365                 resp->status = puterrno3(error);
 366 out1:
 367         DTRACE_NFSV3_5(op__setattr__done, struct svc_req *, req,
 368             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 369             SETATTR3res *, resp);
 370 
 371         if (vp != NULL) {
 372                 if (in_crit)
 373                         nbl_end_crit(vp);
 374                 VN_RELE(vp);
 375         }
 376         vattr_to_wcc_data(bvap, avap, &resp->resfail.obj_wcc);
 377 }
 378 
 379 void *
 380 rfs3_setattr_getfh(SETATTR3args *args)
 381 {
 382 
 383         return (&args->object);
 384 }
 385 
 386 /* ARGSUSED */
 387 void
 388 rfs3_lookup(LOOKUP3args *args, LOOKUP3res *resp, struct exportinfo *exi,
 389     struct svc_req *req, cred_t *cr, bool_t ro)
 
 394         struct vattr *vap;
 395         struct vattr va;
 396         struct vattr *dvap;
 397         struct vattr dva;
 398         nfs_fh3 *fhp;
 399         struct sec_ol sec = {0, 0};
 400         bool_t publicfh_flag = FALSE, auth_weak = FALSE;
 401         struct sockaddr *ca;
 402         char *name = NULL;
 403 
 404         dvap = NULL;
 405 
 406         if (exi != NULL)
 407                 exi_hold(exi);
 408 
 409         /*
 410          * Allow lookups from the root - the default
 411          * location of the public filehandle.
 412          */
 413         if (exi != NULL && (exi->exi_export.ex_flags & EX_PUBLIC)) {
 414                 ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
 415                 dvp = ZONE_ROOTVP();
 416                 VN_HOLD(dvp);
 417 
 418                 DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
 419                     cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 420                     LOOKUP3args *, args);
 421         } else {
 422                 dvp = nfs3_fhtovp(&args->what.dir, exi);
 423 
 424                 DTRACE_NFSV3_5(op__lookup__start, struct svc_req *, req,
 425                     cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 426                     LOOKUP3args *, args);
 427 
 428                 if (dvp == NULL) {
 429                         error = ESTALE;
 430                         goto out;
 431                 }
 432         }
 433 
 434         dva.va_mask = AT_ALL;
 435         dvap = VOP_GETATTR(dvp, &dva, 0, cr, NULL) ? NULL : &dva;
 436 
 437         if (args->what.name == nfs3nametoolong) {
 438                 resp->status = NFS3ERR_NAMETOOLONG;
 439                 goto out1;
 440         }
 441 
 442         if (args->what.name == NULL || *(args->what.name) == '\0') {
 443                 resp->status = NFS3ERR_ACCES;
 444                 goto out1;
 445         }
 446 
 447         fhp = &args->what.dir;
 448         ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL */
 449         if (strcmp(args->what.name, "..") == 0 &&
 450             EQFID(&exi->exi_fid, FH3TOFIDP(fhp))) {
 451                 if ((exi->exi_export.ex_flags & EX_NOHIDE) &&
 452                     ((dvp->v_flag & VROOT) || VN_IS_CURZONEROOT(dvp))) {
 453                         /*
 454                          * special case for ".." and 'nohide'exported root
 455                          */
 456                         if (rfs_climb_crossmnt(&dvp, &exi, cr) != 0) {
 457                                 resp->status = NFS3ERR_ACCES;
 458                                 goto out1;
 459                         }
 460                 } else {
 461                         resp->status = NFS3ERR_NOENT;
 462                         goto out1;
 463                 }
 464         }
 465 
 466         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 467         name = nfscmd_convname(ca, exi, args->what.name,
 468             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
 469 
 470         if (name == NULL) {
 471                 resp->status = NFS3ERR_ACCES;
 472                 goto out1;
 473         }
 474 
 475         /*
 476          * If the public filehandle is used then allow
 477          * a multi-component lookup
 478          */
 479         if (PUBLIC_FH3(&args->what.dir)) {
 480                 publicfh_flag = TRUE;
 481 
 482                 exi_rele(exi);
 483                 exi = NULL;
 484 
 485                 error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
 486                     &exi, &sec);
 487 
 488                 /*
 489                  * Since WebNFS may bypass MOUNT, we need to ensure this
 490                  * request didn't come from an unlabeled admin_low client.
 491                  */
 492                 if (is_system_labeled() && error == 0) {
 493                         int             addr_type;
 494                         void            *ipaddr;
 495                         tsol_tpc_t      *tp;
 496 
 497                         if (ca->sa_family == AF_INET) {
 498                                 addr_type = IPV4_VERSION;
 499                                 ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
 500                         } else if (ca->sa_family == AF_INET6) {
 501                                 addr_type = IPV6_VERSION;
 502                                 ipaddr = &((struct sockaddr_in6 *)
 503                                     ca)->sin6_addr;
 
 547 
 548         if (error)
 549                 goto out;
 550 
 551         if (sec.sec_flags & SEC_QUERY) {
 552                 error = makefh3_ol(&resp->resok.object, exi, sec.sec_index);
 553         } else {
 554                 error = makefh3(&resp->resok.object, vp, exi);
 555                 if (!error && publicfh_flag && !chk_clnt_sec(exi, req))
 556                         auth_weak = TRUE;
 557         }
 558 
 559         if (error) {
 560                 VN_RELE(vp);
 561                 goto out;
 562         }
 563 
 564         va.va_mask = AT_ALL;
 565         vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 566 
 567         VN_RELE(vp);
 568 
 569         resp->status = NFS3_OK;
 570         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 571         vattr_to_post_op_attr(dvap, &resp->resok.dir_attributes);
 572 
 573         /*
 574          * If it's public fh, no 0x81, and client's flavor is
 575          * invalid, set WebNFS status to WNFSERR_CLNT_FLAVOR now.
 576          * Then set RPC status to AUTH_TOOWEAK in common_dispatch.
 577          */
 578         if (auth_weak)
 579                 resp->status = (enum nfsstat3)WNFSERR_CLNT_FLAVOR;
 580 
 581         DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
 582             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 583             LOOKUP3res *, resp);
 584         VN_RELE(dvp);
 585         exi_rele(exi);
 586 
 587         return;
 588 
 589 out:
 590         if (curthread->t_flag & T_WOULDBLOCK) {
 591                 curthread->t_flag &= ~T_WOULDBLOCK;
 592                 resp->status = NFS3ERR_JUKEBOX;
 593         } else
 594                 resp->status = puterrno3(error);
 595 out1:
 596         DTRACE_NFSV3_5(op__lookup__done, struct svc_req *, req,
 597             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
 598             LOOKUP3res *, resp);
 599 
 600         if (exi != NULL)
 601                 exi_rele(exi);
 602 
 603         if (dvp != NULL)
 604                 VN_RELE(dvp);
 605         vattr_to_post_op_attr(dvap, &resp->resfail.dir_attributes);
 606 
 607 }
 608 
 609 void *
 610 rfs3_lookup_getfh(LOOKUP3args *args)
 611 {
 612 
 613         return (&args->what.dir);
 614 }
 615 
 616 /* ARGSUSED */
 617 void
 618 rfs3_access(ACCESS3args *args, ACCESS3res *resp, struct exportinfo *exi,
 619     struct svc_req *req, cred_t *cr, bool_t ro)
 620 {
 621         int error;
 622         vnode_t *vp;
 623         struct vattr *vap;
 624         struct vattr va;
 625         int checkwriteperm;
 626         boolean_t dominant_label = B_FALSE;
 627         boolean_t equal_label = B_FALSE;
 628         boolean_t admin_low_client;
 629 
 630         vap = NULL;
 631 
 632         vp = nfs3_fhtovp(&args->object, exi);
 633 
 634         DTRACE_NFSV3_5(op__access__start, struct svc_req *, req,
 635             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 636             ACCESS3args *, args);
 637 
 638         if (vp == NULL) {
 639                 error = ESTALE;
 640                 goto out;
 641         }
 642 
 643         /*
 644          * If the file system is exported read only, it is not appropriate
 645          * to check write permissions for regular files and directories.
 646          * Special files are interpreted by the client, so the underlying
 647          * permissions are sent back to the client for interpretation.
 648          */
 649         if (rdonly(ro, vp) && (vp->v_type == VREG || vp->v_type == VDIR))
 650                 checkwriteperm = 0;
 651         else
 652                 checkwriteperm = 1;
 653 
 654         /*
 655          * We need the mode so that we can correctly determine access
 656          * permissions relative to a mandatory lock file.  Access to
 
 726                     equal_label)
 727                         resp->resok.access |= ACCESS3_DELETE;
 728         }
 729         if (args->access & ACCESS3_EXECUTE) {
 730                 error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
 731                 if (error) {
 732                         if (curthread->t_flag & T_WOULDBLOCK)
 733                                 goto out;
 734                 } else if (!MANDLOCK(vp, va.va_mode) &&
 735                     (!is_system_labeled() || admin_low_client ||
 736                     dominant_label))
 737                         resp->resok.access |= ACCESS3_EXECUTE;
 738         }
 739 
 740         va.va_mask = AT_ALL;
 741         vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
 742 
 743         resp->status = NFS3_OK;
 744         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
 745 
 746         DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
 747             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 748             ACCESS3res *, resp);
 749 
 750         VN_RELE(vp);
 751 
 752         return;
 753 
 754 out:
 755         if (curthread->t_flag & T_WOULDBLOCK) {
 756                 curthread->t_flag &= ~T_WOULDBLOCK;
 757                 resp->status = NFS3ERR_JUKEBOX;
 758         } else
 759                 resp->status = puterrno3(error);
 760         DTRACE_NFSV3_5(op__access__done, struct svc_req *, req,
 761             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 762             ACCESS3res *, resp);
 763         if (vp != NULL)
 764                 VN_RELE(vp);
 765         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
 766 }
 767 
 768 void *
 769 rfs3_access_getfh(ACCESS3args *args)
 770 {
 771 
 772         return (&args->object);
 773 }
 774 
 775 /* ARGSUSED */
 776 void
 777 rfs3_readlink(READLINK3args *args, READLINK3res *resp, struct exportinfo *exi,
 778     struct svc_req *req, cred_t *cr, bool_t ro)
 779 {
 780         int error;
 781         vnode_t *vp;
 782         struct vattr *vap;
 783         struct vattr va;
 784         struct iovec iov;
 785         struct uio uio;
 786         char *data;
 787         struct sockaddr *ca;
 788         char *name = NULL;
 789         int is_referral = 0;
 790 
 791         vap = NULL;
 792 
 793         vp = nfs3_fhtovp(&args->symlink, exi);
 794 
 795         DTRACE_NFSV3_5(op__readlink__start, struct svc_req *, req,
 796             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 797             READLINK3args *, args);
 798 
 799         if (vp == NULL) {
 800                 error = ESTALE;
 801                 goto out;
 802         }
 803 
 804         va.va_mask = AT_ALL;
 805         error = VOP_GETATTR(vp, &va, 0, cr, NULL);
 806         if (error)
 807                 goto out;
 808 
 809         vap = &va;
 810 
 811         /* We lied about the object type for a referral */
 812         if (vn_is_nfs_reparse(vp, cr))
 813                 is_referral = 1;
 814 
 815         if (vp->v_type != VLNK && !is_referral) {
 816                 resp->status = NFS3ERR_INVAL;
 817                 goto out1;
 
 826                 bslabel_t *clabel = req->rq_label;
 827 
 828                 ASSERT(clabel != NULL);
 829                 DTRACE_PROBE2(tx__rfs3__log__info__opreadlink__clabel, char *,
 830                     "got client label from request(1)", struct svc_req *, req);
 831 
 832                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
 833                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
 834                             exi)) {
 835                                 resp->status = NFS3ERR_ACCES;
 836                                 goto out1;
 837                         }
 838                 }
 839         }
 840 
 841         data = kmem_alloc(MAXPATHLEN + 1, KM_SLEEP);
 842 
 843         if (is_referral) {
 844                 char *s;
 845                 size_t strsz;
 846                 kstat_named_t *stat = exi->exi_ne->ne_globals->svstat[NFS_V3];
 847 
 848                 /* Get an artificial symlink based on a referral */
 849                 s = build_symlink(vp, cr, &strsz);
 850                 stat[NFS_REFERLINKS].value.ui64++;
 851                 DTRACE_PROBE2(nfs3serv__func__referral__reflink,
 852                     vnode_t *, vp, char *, s);
 853                 if (s == NULL)
 854                         error = EINVAL;
 855                 else {
 856                         error = 0;
 857                         (void) strlcpy(data, s, MAXPATHLEN + 1);
 858                         kmem_free(s, strsz);
 859                 }
 860 
 861         } else {
 862 
 863                 iov.iov_base = data;
 864                 iov.iov_len = MAXPATHLEN;
 865                 uio.uio_iov = &iov;
 866                 uio.uio_iovcnt = 1;
 867                 uio.uio_segflg = UIO_SYSSPACE;
 868                 uio.uio_extflg = UIO_COPY_CACHED;
 869                 uio.uio_loffset = 0;
 870                 uio.uio_resid = MAXPATHLEN;
 
 898                 kmem_free(data, MAXPATHLEN + 1);
 899                 goto out;
 900         }
 901 
 902         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 903         name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
 904             MAXPATHLEN + 1);
 905 
 906         if (name == NULL) {
 907                 /*
 908                  * Even though the conversion failed, we return
 909                  * something. We just don't translate it.
 910                  */
 911                 name = data;
 912         }
 913 
 914         resp->status = NFS3_OK;
 915         vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
 916         resp->resok.data = name;
 917 
 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         VN_RELE(vp);
 922 
 923         if (name != data)
 924                 kmem_free(data, MAXPATHLEN + 1);
 925 
 926         return;
 927 
 928 out:
 929         if (curthread->t_flag & T_WOULDBLOCK) {
 930                 curthread->t_flag &= ~T_WOULDBLOCK;
 931                 resp->status = NFS3ERR_JUKEBOX;
 932         } else
 933                 resp->status = puterrno3(error);
 934 out1:
 935         DTRACE_NFSV3_5(op__readlink__done, struct svc_req *, req,
 936             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 937             READLINK3res *, resp);
 938         if (vp != NULL)
 939                 VN_RELE(vp);
 940         vattr_to_post_op_attr(vap, &resp->resfail.symlink_attributes);
 941 }
 942 
 943 void *
 944 rfs3_readlink_getfh(READLINK3args *args)
 945 {
 946 
 947         return (&args->symlink);
 948 }
 949 
 950 void
 951 rfs3_readlink_free(READLINK3res *resp)
 952 {
 953 
 954         if (resp->status == NFS3_OK)
 955                 kmem_free(resp->resok.data, MAXPATHLEN + 1);
 956 }
 957 
 
 967         int error;
 968         vnode_t *vp;
 969         struct vattr *vap;
 970         struct vattr va;
 971         struct iovec iov, *iovp = NULL;
 972         int iovcnt;
 973         struct uio uio;
 974         u_offset_t offset;
 975         mblk_t *mp = NULL;
 976         int in_crit = 0;
 977         int need_rwunlock = 0;
 978         caller_context_t ct;
 979         int rdma_used = 0;
 980         int loaned_buffers;
 981         struct uio *uiop;
 982 
 983         vap = NULL;
 984 
 985         vp = nfs3_fhtovp(&args->file, exi);
 986 
 987         DTRACE_NFSV3_5(op__read__start, struct svc_req *, req,
 988             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
 989             READ3args *, args);
 990 
 991 
 992         if (vp == NULL) {
 993                 error = ESTALE;
 994                 goto out;
 995         }
 996 
 997         if (args->wlist) {
 998                 if (args->count > clist_len(args->wlist)) {
 999                         error = EINVAL;
1000                         goto out;
1001                 }
1002                 rdma_used = 1;
1003         }
1004 
1005         /* use loaned buffers for TCP */
1006         loaned_buffers = (nfs_loaned_buffers && !rdma_used) ? 1 : 0;
1007 
1008         if (is_system_labeled()) {
1009                 bslabel_t *clabel = req->rq_label;
1010 
1011                 ASSERT(clabel != NULL);
 
1225                 resp->resok.eof = FALSE;
1226         resp->resok.data.data_len = resp->resok.count;
1227 
1228         if (mp)
1229                 rfs_rndup_mblks(mp, resp->resok.count, loaned_buffers);
1230 
1231         resp->resok.data.mp = mp;
1232         resp->resok.size = (uint_t)args->count;
1233 
1234         if (rdma_used) {
1235                 resp->resok.data.data_val = (caddr_t)iov.iov_base;
1236                 if (!rdma_setup_read_data3(args, &(resp->resok))) {
1237                         resp->status = NFS3ERR_INVAL;
1238                 }
1239         } else {
1240                 resp->resok.data.data_val = (caddr_t)mp->b_datap->db_base;
1241                 (resp->resok).wlist = NULL;
1242         }
1243 
1244 done:
1245         DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1246             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1247             READ3res *, resp);
1248 
1249         VN_RELE(vp);
1250 
1251         if (iovp != NULL)
1252                 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1253 
1254         return;
1255 
1256 out:
1257         if (curthread->t_flag & T_WOULDBLOCK) {
1258                 curthread->t_flag &= ~T_WOULDBLOCK;
1259                 resp->status = NFS3ERR_JUKEBOX;
1260         } else
1261                 resp->status = puterrno3(error);
1262 out1:
1263         DTRACE_NFSV3_5(op__read__done, struct svc_req *, req,
1264             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1265             READ3res *, resp);
1266 
1267         if (vp != NULL) {
1268                 if (need_rwunlock)
1269                         VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &ct);
1270                 if (in_crit)
1271                         nbl_end_crit(vp);
1272                 VN_RELE(vp);
1273         }
1274         vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
1275 
1276         if (iovp != NULL)
1277                 kmem_free(iovp, iovcnt * sizeof (struct iovec));
1278 }
1279 
1280 void
1281 rfs3_read_free(READ3res *resp)
1282 {
1283         mblk_t *mp;
1284 
1285         if (resp->status == NFS3_OK) {
 
1290 }
1291 
1292 void *
1293 rfs3_read_getfh(READ3args *args)
1294 {
1295 
1296         return (&args->file);
1297 }
1298 
1299 #define MAX_IOVECS      12
1300 
1301 #ifdef DEBUG
1302 static int rfs3_write_hits = 0;
1303 static int rfs3_write_misses = 0;
1304 #endif
1305 
1306 void
1307 rfs3_write(WRITE3args *args, WRITE3res *resp, struct exportinfo *exi,
1308     struct svc_req *req, cred_t *cr, bool_t ro)
1309 {
1310         nfs3_srv_t *ns;
1311         int error;
1312         vnode_t *vp;
1313         struct vattr *bvap = NULL;
1314         struct vattr bva;
1315         struct vattr *avap = NULL;
1316         struct vattr ava;
1317         u_offset_t rlimit;
1318         struct uio uio;
1319         struct iovec iov[MAX_IOVECS];
1320         mblk_t *m;
1321         struct iovec *iovp;
1322         int iovcnt;
1323         int ioflag;
1324         cred_t *savecred;
1325         int in_crit = 0;
1326         int rwlock_ret = -1;
1327         caller_context_t ct;
1328 
1329         vp = nfs3_fhtovp(&args->file, exi);
1330 
1331         DTRACE_NFSV3_5(op__write__start, struct svc_req *, req,
1332             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1333             WRITE3args *, args);
1334 
1335         if (vp == NULL) {
1336                 error = ESTALE;
1337                 goto err;
1338         }
1339 
1340         ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL. */
1341         ns = nfs3_get_srv();
1342 
1343         if (is_system_labeled()) {
1344                 bslabel_t *clabel = req->rq_label;
1345 
1346                 ASSERT(clabel != NULL);
1347                 DTRACE_PROBE2(tx__rfs3__log__info__opwrite__clabel, char *,
1348                     "got client label from request(1)", struct svc_req *, req);
1349 
1350                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
1351                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
1352                             exi)) {
1353                                 resp->status = NFS3ERR_ACCES;
1354                                 goto err1;
1355                         }
1356                 }
1357         }
1358 
1359         ct.cc_sysid = 0;
1360         ct.cc_pid = 0;
1361         ct.cc_caller_id = nfs3_srv_caller_id;
1362         ct.cc_flags = CC_DONTBLOCK;
 
1410 
1411         if (vp->v_type != VREG) {
1412                 resp->status = NFS3ERR_INVAL;
1413                 goto err1;
1414         }
1415 
1416         if (crgetuid(cr) != bva.va_uid &&
1417             (error = VOP_ACCESS(vp, VWRITE, 0, cr, &ct)))
1418                 goto err;
1419 
1420         if (MANDLOCK(vp, bva.va_mode)) {
1421                 resp->status = NFS3ERR_ACCES;
1422                 goto err1;
1423         }
1424 
1425         if (args->count == 0) {
1426                 resp->status = NFS3_OK;
1427                 vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1428                 resp->resok.count = 0;
1429                 resp->resok.committed = args->stable;
1430                 resp->resok.verf = ns->write3verf;
1431                 goto out;
1432         }
1433 
1434         if (args->mblk != NULL) {
1435                 iovcnt = 0;
1436                 for (m = args->mblk; m != NULL; m = m->b_cont)
1437                         iovcnt++;
1438                 if (iovcnt <= MAX_IOVECS) {
1439 #ifdef DEBUG
1440                         rfs3_write_hits++;
1441 #endif
1442                         iovp = iov;
1443                 } else {
1444 #ifdef DEBUG
1445                         rfs3_write_misses++;
1446 #endif
1447                         iovp = kmem_alloc(sizeof (*iovp) * iovcnt, KM_SLEEP);
1448                 }
1449                 mblk_to_iov(args->mblk, iovcnt, iovp);
1450 
 
1512 
1513         /*
1514          * If we were unable to get the V_WRITELOCK_TRUE, then we
1515          * may not have accurate after attrs, so check if
1516          * we have both attributes, they have a non-zero va_seq, and
1517          * va_seq has changed by exactly one,
1518          * if not, turn off the before attr.
1519          */
1520         if (rwlock_ret != V_WRITELOCK_TRUE) {
1521                 if (bvap == NULL || avap == NULL ||
1522                     bvap->va_seq == 0 || avap->va_seq == 0 ||
1523                     avap->va_seq != (bvap->va_seq + 1)) {
1524                         bvap = NULL;
1525                 }
1526         }
1527 
1528         resp->status = NFS3_OK;
1529         vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
1530         resp->resok.count = args->count - uio.uio_resid;
1531         resp->resok.committed = args->stable;
1532         resp->resok.verf = ns->write3verf;
1533         goto out;
1534 
1535 err:
1536         if (curthread->t_flag & T_WOULDBLOCK) {
1537                 curthread->t_flag &= ~T_WOULDBLOCK;
1538                 resp->status = NFS3ERR_JUKEBOX;
1539         } else
1540                 resp->status = puterrno3(error);
1541 err1:
1542         vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
1543 out:
1544         DTRACE_NFSV3_5(op__write__done, struct svc_req *, req,
1545             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
1546             WRITE3res *, resp);
1547 
1548         if (vp != NULL) {
1549                 if (rwlock_ret != -1)
1550                         VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &ct);
1551                 if (in_crit)
1552                         nbl_end_crit(vp);
1553                 VN_RELE(vp);
1554         }
1555 }
1556 
1557 void *
1558 rfs3_write_getfh(WRITE3args *args)
1559 {
1560 
1561         return (&args->file);
1562 }
1563 
1564 void
1565 rfs3_create(CREATE3args *args, CREATE3res *resp, struct exportinfo *exi,
1566     struct svc_req *req, cred_t *cr, bool_t ro)
 
1571         vnode_t *tvp = NULL;
1572         vnode_t *dvp;
1573         struct vattr *vap;
1574         struct vattr va;
1575         struct vattr *dbvap;
1576         struct vattr dbva;
1577         struct vattr *davap;
1578         struct vattr dava;
1579         enum vcexcl excl;
1580         nfstime3 *mtime;
1581         len_t reqsize;
1582         bool_t trunc;
1583         struct sockaddr *ca;
1584         char *name = NULL;
1585 
1586         dbvap = NULL;
1587         davap = NULL;
1588 
1589         dvp = nfs3_fhtovp(&args->where.dir, exi);
1590 
1591         DTRACE_NFSV3_5(op__create__start, struct svc_req *, req,
1592             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1593             CREATE3args *, args);
1594 
1595         if (dvp == NULL) {
1596                 error = ESTALE;
1597                 goto out;
1598         }
1599 
1600         dbva.va_mask = AT_ALL;
1601         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1602         davap = dbvap;
1603 
1604         if (args->where.name == nfs3nametoolong) {
1605                 resp->status = NFS3ERR_NAMETOOLONG;
1606                 goto out1;
1607         }
1608 
1609         if (args->where.name == NULL || *(args->where.name) == '\0') {
1610                 resp->status = NFS3ERR_ACCES;
1611                 goto out1;
1612         }
1613 
 
1872         else
1873                 resp->resok.obj.handle_follows = TRUE;
1874 
1875         /*
1876          * Force modified data and metadata out to stable storage.
1877          */
1878         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
1879         (void) VOP_FSYNC(dvp, 0, cr, NULL);
1880 
1881         VN_RELE(vp);
1882         if (tvp != NULL) {
1883                 if (in_crit)
1884                         nbl_end_crit(tvp);
1885                 VN_RELE(tvp);
1886         }
1887 
1888         resp->status = NFS3_OK;
1889         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
1890         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
1891 
1892         DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1893             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1894             CREATE3res *, resp);
1895 
1896         VN_RELE(dvp);
1897         return;
1898 
1899 out:
1900         if (curthread->t_flag & T_WOULDBLOCK) {
1901                 curthread->t_flag &= ~T_WOULDBLOCK;
1902                 resp->status = NFS3ERR_JUKEBOX;
1903         } else
1904                 resp->status = puterrno3(error);
1905 out1:
1906         DTRACE_NFSV3_5(op__create__done, struct svc_req *, req,
1907             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1908             CREATE3res *, resp);
1909 
1910         if (name != NULL && name != args->where.name)
1911                 kmem_free(name, MAXPATHLEN + 1);
1912 
1913         if (tvp != NULL) {
1914                 if (in_crit)
1915                         nbl_end_crit(tvp);
1916                 VN_RELE(tvp);
1917         }
1918         if (dvp != NULL)
1919                 VN_RELE(dvp);
1920         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
1921 }
1922 
1923 void *
1924 rfs3_create_getfh(CREATE3args *args)
1925 {
1926 
1927         return (&args->where.dir);
1928 }
 
1931 rfs3_mkdir(MKDIR3args *args, MKDIR3res *resp, struct exportinfo *exi,
1932     struct svc_req *req, cred_t *cr, bool_t ro)
1933 {
1934         int error;
1935         vnode_t *vp = NULL;
1936         vnode_t *dvp;
1937         struct vattr *vap;
1938         struct vattr va;
1939         struct vattr *dbvap;
1940         struct vattr dbva;
1941         struct vattr *davap;
1942         struct vattr dava;
1943         struct sockaddr *ca;
1944         char *name = NULL;
1945 
1946         dbvap = NULL;
1947         davap = NULL;
1948 
1949         dvp = nfs3_fhtovp(&args->where.dir, exi);
1950 
1951         DTRACE_NFSV3_5(op__mkdir__start, struct svc_req *, req,
1952             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
1953             MKDIR3args *, args);
1954 
1955         if (dvp == NULL) {
1956                 error = ESTALE;
1957                 goto out;
1958         }
1959 
1960         dbva.va_mask = AT_ALL;
1961         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
1962         davap = dbvap;
1963 
1964         if (args->where.name == nfs3nametoolong) {
1965                 resp->status = NFS3ERR_NAMETOOLONG;
1966                 goto out1;
1967         }
1968 
1969         if (args->where.name == NULL || *(args->where.name) == '\0') {
1970                 resp->status = NFS3ERR_ACCES;
1971                 goto out1;
1972         }
1973 
 
2032         error = makefh3(&resp->resok.obj.handle, vp, exi);
2033         if (error)
2034                 resp->resok.obj.handle_follows = FALSE;
2035         else
2036                 resp->resok.obj.handle_follows = TRUE;
2037 
2038         va.va_mask = AT_ALL;
2039         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2040 
2041         /*
2042          * Force modified data and metadata out to stable storage.
2043          */
2044         (void) VOP_FSYNC(vp, 0, cr, NULL);
2045 
2046         VN_RELE(vp);
2047 
2048         resp->status = NFS3_OK;
2049         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2050         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2051 
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         VN_RELE(dvp);
2056 
2057         return;
2058 
2059 out:
2060         if (curthread->t_flag & T_WOULDBLOCK) {
2061                 curthread->t_flag &= ~T_WOULDBLOCK;
2062                 resp->status = NFS3ERR_JUKEBOX;
2063         } else
2064                 resp->status = puterrno3(error);
2065 out1:
2066         DTRACE_NFSV3_5(op__mkdir__done, struct svc_req *, req,
2067             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2068             MKDIR3res *, resp);
2069         if (dvp != NULL)
2070                 VN_RELE(dvp);
2071         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2072 }
2073 
2074 void *
2075 rfs3_mkdir_getfh(MKDIR3args *args)
2076 {
2077 
2078         return (&args->where.dir);
2079 }
2080 
2081 void
2082 rfs3_symlink(SYMLINK3args *args, SYMLINK3res *resp, struct exportinfo *exi,
2083     struct svc_req *req, cred_t *cr, bool_t ro)
2084 {
2085         int error;
2086         vnode_t *vp;
2087         vnode_t *dvp;
2088         struct vattr *vap;
2089         struct vattr va;
2090         struct vattr *dbvap;
2091         struct vattr dbva;
2092         struct vattr *davap;
2093         struct vattr dava;
2094         struct sockaddr *ca;
2095         char *name = NULL;
2096         char *symdata = NULL;
2097 
2098         dbvap = NULL;
2099         davap = NULL;
2100 
2101         dvp = nfs3_fhtovp(&args->where.dir, exi);
2102 
2103         DTRACE_NFSV3_5(op__symlink__start, struct svc_req *, req,
2104             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2105             SYMLINK3args *, args);
2106 
2107         if (dvp == NULL) {
2108                 error = ESTALE;
2109                 goto err;
2110         }
2111 
2112         dbva.va_mask = AT_ALL;
2113         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2114         davap = dbvap;
2115 
2116         if (args->where.name == nfs3nametoolong) {
2117                 resp->status = NFS3ERR_NAMETOOLONG;
2118                 goto err1;
2119         }
2120 
2121         if (args->where.name == NULL || *(args->where.name) == '\0') {
2122                 resp->status = NFS3ERR_ACCES;
2123                 goto err1;
2124         }
2125 
 
2222         VN_RELE(vp);
2223 
2224         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2225         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2226         goto out;
2227 
2228 err:
2229         if (curthread->t_flag & T_WOULDBLOCK) {
2230                 curthread->t_flag &= ~T_WOULDBLOCK;
2231                 resp->status = NFS3ERR_JUKEBOX;
2232         } else
2233                 resp->status = puterrno3(error);
2234 err1:
2235         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2236 out:
2237         if (name != NULL && name != args->where.name)
2238                 kmem_free(name, MAXPATHLEN + 1);
2239         if (symdata != NULL && symdata != args->symlink.symlink_data)
2240                 kmem_free(symdata, MAXPATHLEN + 1);
2241 
2242         DTRACE_NFSV3_5(op__symlink__done, struct svc_req *, req,
2243             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2244             SYMLINK3res *, resp);
2245 
2246         if (dvp != NULL)
2247                 VN_RELE(dvp);
2248 }
2249 
2250 void *
2251 rfs3_symlink_getfh(SYMLINK3args *args)
2252 {
2253 
2254         return (&args->where.dir);
2255 }
2256 
2257 void
2258 rfs3_mknod(MKNOD3args *args, MKNOD3res *resp, struct exportinfo *exi,
2259     struct svc_req *req, cred_t *cr, bool_t ro)
2260 {
2261         int error;
2262         vnode_t *vp;
2263         vnode_t *realvp;
2264         vnode_t *dvp;
2265         struct vattr *vap;
2266         struct vattr va;
2267         struct vattr *dbvap;
2268         struct vattr dbva;
2269         struct vattr *davap;
2270         struct vattr dava;
2271         int mode;
2272         enum vcexcl excl;
2273         struct sockaddr *ca;
2274         char *name = NULL;
2275 
2276         dbvap = NULL;
2277         davap = NULL;
2278 
2279         dvp = nfs3_fhtovp(&args->where.dir, exi);
2280 
2281         DTRACE_NFSV3_5(op__mknod__start, struct svc_req *, req,
2282             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2283             MKNOD3args *, args);
2284 
2285         if (dvp == NULL) {
2286                 error = ESTALE;
2287                 goto out;
2288         }
2289 
2290         dbva.va_mask = AT_ALL;
2291         dbvap = VOP_GETATTR(dvp, &dbva, 0, cr, NULL) ? NULL : &dbva;
2292         davap = dbvap;
2293 
2294         if (args->where.name == nfs3nametoolong) {
2295                 resp->status = NFS3ERR_NAMETOOLONG;
2296                 goto out1;
2297         }
2298 
2299         if (args->where.name == NULL || *(args->where.name) == '\0') {
2300                 resp->status = NFS3ERR_ACCES;
2301                 goto out1;
2302         }
2303 
 
2409         else
2410                 resp->resok.obj.handle_follows = TRUE;
2411 
2412         va.va_mask = AT_ALL;
2413         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
2414 
2415         /*
2416          * Force modified metadata out to stable storage.
2417          *
2418          * if a underlying vp exists, pass it to VOP_FSYNC
2419          */
2420         if (VOP_REALVP(vp, &realvp, NULL) == 0)
2421                 (void) VOP_FSYNC(realvp, FNODSYNC, cr, NULL);
2422         else
2423                 (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
2424 
2425         VN_RELE(vp);
2426 
2427         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
2428         vattr_to_wcc_data(dbvap, davap, &resp->resok.dir_wcc);
2429         DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2430             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2431             MKNOD3res *, resp);
2432         VN_RELE(dvp);
2433         return;
2434 
2435 out:
2436         if (curthread->t_flag & T_WOULDBLOCK) {
2437                 curthread->t_flag &= ~T_WOULDBLOCK;
2438                 resp->status = NFS3ERR_JUKEBOX;
2439         } else
2440                 resp->status = puterrno3(error);
2441 out1:
2442         DTRACE_NFSV3_5(op__mknod__done, struct svc_req *, req,
2443             cred_t *, cr, vnode_t *, dvp, struct exportinfo *, exi,
2444             MKNOD3res *, resp);
2445         if (dvp != NULL)
2446                 VN_RELE(dvp);
2447         vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
2448 }
2449 
2450 void *
2451 rfs3_mknod_getfh(MKNOD3args *args)
2452 {
2453 
2454         return (&args->where.dir);
2455 }
2456 
2457 void
2458 rfs3_remove(REMOVE3args *args, REMOVE3res *resp, struct exportinfo *exi,
2459     struct svc_req *req, cred_t *cr, bool_t ro)
2460 {
2461         int error = 0;
2462         vnode_t *vp;
2463         struct vattr *bvap;
2464         struct vattr bva;
2465         struct vattr *avap;
2466         struct vattr ava;
2467         vnode_t *targvp = NULL;
2468         struct sockaddr *ca;
2469         char *name = NULL;
2470 
2471         bvap = NULL;
2472         avap = NULL;
2473 
2474         vp = nfs3_fhtovp(&args->object.dir, exi);
2475 
2476         DTRACE_NFSV3_5(op__remove__start, struct svc_req *, req,
2477             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2478             REMOVE3args *, args);
2479 
2480         if (vp == NULL) {
2481                 error = ESTALE;
2482                 goto err;
2483         }
2484 
2485         bva.va_mask = AT_ALL;
2486         bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2487         avap = bvap;
2488 
2489         if (vp->v_type != VDIR) {
2490                 resp->status = NFS3ERR_NOTDIR;
2491                 goto err1;
2492         }
2493 
2494         if (args->object.name == nfs3nametoolong) {
2495                 resp->status = NFS3ERR_NAMETOOLONG;
2496                 goto err1;
2497         }
2498 
 
2566          * Force modified data and metadata out to stable storage.
2567          */
2568         (void) VOP_FSYNC(vp, 0, cr, NULL);
2569 
2570         if (error)
2571                 goto err;
2572 
2573         resp->status = NFS3_OK;
2574         vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2575         goto out;
2576 
2577 err:
2578         if (curthread->t_flag & T_WOULDBLOCK) {
2579                 curthread->t_flag &= ~T_WOULDBLOCK;
2580                 resp->status = NFS3ERR_JUKEBOX;
2581         } else
2582                 resp->status = puterrno3(error);
2583 err1:
2584         vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2585 out:
2586         DTRACE_NFSV3_5(op__remove__done, struct svc_req *, req,
2587             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2588             REMOVE3res *, resp);
2589 
2590         if (name != NULL && name != args->object.name)
2591                 kmem_free(name, MAXPATHLEN + 1);
2592 
2593         if (vp != NULL)
2594                 VN_RELE(vp);
2595 }
2596 
2597 void *
2598 rfs3_remove_getfh(REMOVE3args *args)
2599 {
2600 
2601         return (&args->object.dir);
2602 }
2603 
2604 void
2605 rfs3_rmdir(RMDIR3args *args, RMDIR3res *resp, struct exportinfo *exi,
2606     struct svc_req *req, cred_t *cr, bool_t ro)
2607 {
2608         int error;
2609         vnode_t *vp;
2610         struct vattr *bvap;
2611         struct vattr bva;
2612         struct vattr *avap;
2613         struct vattr ava;
2614         struct sockaddr *ca;
2615         char *name = NULL;
2616 
2617         bvap = NULL;
2618         avap = NULL;
2619 
2620         vp = nfs3_fhtovp(&args->object.dir, exi);
2621 
2622         DTRACE_NFSV3_5(op__rmdir__start, struct svc_req *, req,
2623             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2624             RMDIR3args *, args);
2625 
2626         if (vp == NULL) {
2627                 error = ESTALE;
2628                 goto err;
2629         }
2630 
2631         bva.va_mask = AT_ALL;
2632         bvap = VOP_GETATTR(vp, &bva, 0, cr, NULL) ? NULL : &bva;
2633         avap = bvap;
2634 
2635         if (vp->v_type != VDIR) {
2636                 resp->status = NFS3ERR_NOTDIR;
2637                 goto err1;
2638         }
2639 
2640         if (args->object.name == nfs3nametoolong) {
2641                 resp->status = NFS3ERR_NAMETOOLONG;
2642                 goto err1;
2643         }
2644 
 
2660                     "got client label from request(1)", struct svc_req *, req);
2661 
2662                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2663                         if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK,
2664                             exi)) {
2665                                 resp->status = NFS3ERR_ACCES;
2666                                 goto err1;
2667                         }
2668                 }
2669         }
2670 
2671         ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
2672         name = nfscmd_convname(ca, exi, args->object.name,
2673             NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
2674 
2675         if (name == NULL) {
2676                 resp->status = NFS3ERR_INVAL;
2677                 goto err1;
2678         }
2679 
2680         ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
2681         error = VOP_RMDIR(vp, name, ZONE_ROOTVP(), cr, NULL, 0);
2682 
2683         if (name != args->object.name)
2684                 kmem_free(name, MAXPATHLEN + 1);
2685 
2686         ava.va_mask = AT_ALL;
2687         avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
2688 
2689         /*
2690          * Force modified data and metadata out to stable storage.
2691          */
2692         (void) VOP_FSYNC(vp, 0, cr, NULL);
2693 
2694         if (error) {
2695                 /*
2696                  * System V defines rmdir to return EEXIST, not ENOTEMPTY,
2697                  * if the directory is not empty.  A System V NFS server
2698                  * needs to map NFS3ERR_EXIST to NFS3ERR_NOTEMPTY to transmit
2699                  * over the wire.
2700                  */
2701                 if (error == EEXIST)
2702                         error = ENOTEMPTY;
2703                 goto err;
2704         }
2705 
2706         resp->status = NFS3_OK;
2707         vattr_to_wcc_data(bvap, avap, &resp->resok.dir_wcc);
2708         goto out;
2709 
2710 err:
2711         if (curthread->t_flag & T_WOULDBLOCK) {
2712                 curthread->t_flag &= ~T_WOULDBLOCK;
2713                 resp->status = NFS3ERR_JUKEBOX;
2714         } else
2715                 resp->status = puterrno3(error);
2716 err1:
2717         vattr_to_wcc_data(bvap, avap, &resp->resfail.dir_wcc);
2718 out:
2719         DTRACE_NFSV3_5(op__rmdir__done, struct svc_req *, req,
2720             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2721             RMDIR3res *, resp);
2722         if (vp != NULL)
2723                 VN_RELE(vp);
2724 
2725 }
2726 
2727 void *
2728 rfs3_rmdir_getfh(RMDIR3args *args)
2729 {
2730 
2731         return (&args->object.dir);
2732 }
2733 
2734 void
2735 rfs3_rename(RENAME3args *args, RENAME3res *resp, struct exportinfo *exi,
2736     struct svc_req *req, cred_t *cr, bool_t ro)
2737 {
2738         int error = 0;
2739         vnode_t *fvp;
2740         vnode_t *tvp;
2741         vnode_t *targvp;
 
2746         struct vattr *tbvap;
2747         struct vattr tbva;
2748         struct vattr *tavap;
2749         struct vattr tava;
2750         nfs_fh3 *fh3;
2751         struct exportinfo *to_exi;
2752         vnode_t *srcvp = NULL;
2753         bslabel_t *clabel;
2754         struct sockaddr *ca;
2755         char *name = NULL;
2756         char *toname = NULL;
2757 
2758         fbvap = NULL;
2759         favap = NULL;
2760         tbvap = NULL;
2761         tavap = NULL;
2762         tvp = NULL;
2763 
2764         fvp = nfs3_fhtovp(&args->from.dir, exi);
2765 
2766         DTRACE_NFSV3_5(op__rename__start, struct svc_req *, req,
2767             cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2768             RENAME3args *, args);
2769 
2770         if (fvp == NULL) {
2771                 error = ESTALE;
2772                 goto err;
2773         }
2774 
2775         if (is_system_labeled()) {
2776                 clabel = req->rq_label;
2777                 ASSERT(clabel != NULL);
2778                 DTRACE_PROBE2(tx__rfs3__log__info__oprename__clabel, char *,
2779                     "got client label from request(1)", struct svc_req *, req);
2780 
2781                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
2782                         if (!do_rfs_label_check(clabel, fvp, EQUALITY_CHECK,
2783                             exi)) {
2784                                 resp->status = NFS3ERR_ACCES;
2785                                 goto err1;
2786                         }
2787                 }
2788         }
 
2865         /*
2866          * Check for a conflict with a non-blocking mandatory share
2867          * reservation or V4 delegations.
2868          */
2869         error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
2870             NULL, cr, NULL, NULL, NULL);
2871         if (error != 0)
2872                 goto err;
2873 
2874         /*
2875          * If we rename a delegated file we should recall the
2876          * delegation, since future opens should fail or would
2877          * refer to a new file.
2878          */
2879         if (rfs4_check_delegated(FWRITE, srcvp, FALSE)) {
2880                 resp->status = NFS3ERR_JUKEBOX;
2881                 goto err1;
2882         }
2883 
2884         /*
2885          * Check for renaming over a delegated file.  Check nfs4_deleg_policy
2886          * first to avoid VOP_LOOKUP if possible.
2887          */
2888         if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE &&
2889             VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
2890             NULL, NULL, NULL) == 0) {
2891 
2892                 if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
2893                         VN_RELE(targvp);
2894                         resp->status = NFS3ERR_JUKEBOX;
2895                         goto err1;
2896                 }
2897                 VN_RELE(targvp);
2898         }
2899 
2900         if (!nbl_need_check(srcvp)) {
2901                 error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2902         } else {
2903                 nbl_start_crit(srcvp, RW_READER);
2904                 if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
2905                         error = EACCES;
2906                 else
2907                         error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
2908                 nbl_end_crit(srcvp);
 
2932         vattr_to_wcc_data(tbvap, tavap, &resp->resok.todir_wcc);
2933         goto out;
2934 
2935 err:
2936         if (curthread->t_flag & T_WOULDBLOCK) {
2937                 curthread->t_flag &= ~T_WOULDBLOCK;
2938                 resp->status = NFS3ERR_JUKEBOX;
2939         } else {
2940                 resp->status = puterrno3(error);
2941         }
2942 err1:
2943         vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
2944         vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
2945 
2946 out:
2947         if (name != NULL && name != args->from.name)
2948                 kmem_free(name, MAXPATHLEN + 1);
2949         if (toname != NULL && toname != args->to.name)
2950                 kmem_free(toname, MAXPATHLEN + 1);
2951 
2952         DTRACE_NFSV3_5(op__rename__done, struct svc_req *, req,
2953             cred_t *, cr, vnode_t *, fvp, struct exportinfo *, exi,
2954             RENAME3res *, resp);
2955         if (fvp != NULL)
2956                 VN_RELE(fvp);
2957         if (tvp != NULL)
2958                 VN_RELE(tvp);
2959 }
2960 
2961 void *
2962 rfs3_rename_getfh(RENAME3args *args)
2963 {
2964 
2965         return (&args->from.dir);
2966 }
2967 
2968 void
2969 rfs3_link(LINK3args *args, LINK3res *resp, struct exportinfo *exi,
2970     struct svc_req *req, cred_t *cr, bool_t ro)
2971 {
2972         int error;
2973         vnode_t *vp;
2974         vnode_t *dvp;
2975         struct vattr *vap;
2976         struct vattr va;
2977         struct vattr *bvap;
2978         struct vattr bva;
2979         struct vattr *avap;
2980         struct vattr ava;
2981         nfs_fh3 *fh3;
2982         struct exportinfo *to_exi;
2983         bslabel_t *clabel;
2984         struct sockaddr *ca;
2985         char *name = NULL;
2986 
2987         vap = NULL;
2988         bvap = NULL;
2989         avap = NULL;
2990         dvp = NULL;
2991 
2992         vp = nfs3_fhtovp(&args->file, exi);
2993 
2994         DTRACE_NFSV3_5(op__link__start, struct svc_req *, req,
2995             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
2996             LINK3args *, args);
2997 
2998         if (vp == NULL) {
2999                 error = ESTALE;
3000                 goto out;
3001         }
3002 
3003         va.va_mask = AT_ALL;
3004         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3005 
3006         fh3 = &args->link.dir;
3007         to_exi = checkexport(&fh3->fh3_fsid, FH3TOXFIDP(fh3));
3008         if (to_exi == NULL) {
3009                 resp->status = NFS3ERR_ACCES;
3010                 goto out1;
3011         }
3012         exi_rele(to_exi);
3013 
3014         if (to_exi != exi) {
3015                 resp->status = NFS3ERR_XDEV;
3016                 goto out1;
 
3088         va.va_mask = AT_ALL;
3089         vap = VOP_GETATTR(vp, &va, 0, cr, NULL) ? NULL : &va;
3090         ava.va_mask = AT_ALL;
3091         avap = VOP_GETATTR(dvp, &ava, 0, cr, NULL) ? NULL : &ava;
3092 
3093         /*
3094          * Force modified data and metadata out to stable storage.
3095          */
3096         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3097         (void) VOP_FSYNC(dvp, 0, cr, NULL);
3098 
3099         if (error)
3100                 goto out;
3101 
3102         VN_RELE(dvp);
3103 
3104         resp->status = NFS3_OK;
3105         vattr_to_post_op_attr(vap, &resp->resok.file_attributes);
3106         vattr_to_wcc_data(bvap, avap, &resp->resok.linkdir_wcc);
3107 
3108         DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3109             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3110             LINK3res *, resp);
3111 
3112         VN_RELE(vp);
3113 
3114         return;
3115 
3116 out:
3117         if (curthread->t_flag & T_WOULDBLOCK) {
3118                 curthread->t_flag &= ~T_WOULDBLOCK;
3119                 resp->status = NFS3ERR_JUKEBOX;
3120         } else
3121                 resp->status = puterrno3(error);
3122 out1:
3123         if (name != NULL && name != args->link.name)
3124                 kmem_free(name, MAXPATHLEN + 1);
3125 
3126         DTRACE_NFSV3_5(op__link__done, struct svc_req *, req,
3127             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3128             LINK3res *, resp);
3129 
3130         if (vp != NULL)
3131                 VN_RELE(vp);
3132         if (dvp != NULL)
3133                 VN_RELE(dvp);
3134         vattr_to_post_op_attr(vap, &resp->resfail.file_attributes);
3135         vattr_to_wcc_data(bvap, avap, &resp->resfail.linkdir_wcc);
3136 }
3137 
3138 void *
3139 rfs3_link_getfh(LINK3args *args)
3140 {
3141 
3142         return (&args->file);
3143 }
3144 
3145 /*
3146  * This macro defines the size of a response which contains attribute
3147  * information and one directory entry (whose length is specified by
3148  * the macro parameter).  If the incoming request is larger than this,
 
3176 rfs3_readdir(READDIR3args *args, READDIR3res *resp, struct exportinfo *exi,
3177     struct svc_req *req, cred_t *cr, bool_t ro)
3178 {
3179         int error;
3180         vnode_t *vp;
3181         struct vattr *vap;
3182         struct vattr va;
3183         struct iovec iov;
3184         struct uio uio;
3185         char *data;
3186         int iseof;
3187         int bufsize;
3188         int namlen;
3189         uint_t count;
3190         struct sockaddr *ca;
3191 
3192         vap = NULL;
3193 
3194         vp = nfs3_fhtovp(&args->dir, exi);
3195 
3196         DTRACE_NFSV3_5(op__readdir__start, struct svc_req *, req,
3197             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3198             READDIR3args *, args);
3199 
3200         if (vp == NULL) {
3201                 error = ESTALE;
3202                 goto out;
3203         }
3204 
3205         if (is_system_labeled()) {
3206                 bslabel_t *clabel = req->rq_label;
3207 
3208                 ASSERT(clabel != NULL);
3209                 DTRACE_PROBE2(tx__rfs3__log__info__opreaddir__clabel, char *,
3210                     "got client label from request(1)", struct svc_req *, req);
3211 
3212                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3213                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3214                             exi)) {
3215                                 resp->status = NFS3ERR_ACCES;
3216                                 goto out1;
3217                         }
3218                 }
 
3342         /*
3343          * Don't do this.  It causes local disk writes when just
3344          * reading the file and the overhead is deemed larger
3345          * than the benefit.
3346          */
3347         /*
3348          * Force modified metadata out to stable storage.
3349          */
3350         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3351 #endif
3352 
3353         resp->status = NFS3_OK;
3354         vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3355         resp->resok.cookieverf = 0;
3356         resp->resok.reply.entries = (entry3 *)data;
3357         resp->resok.reply.eof = iseof;
3358         resp->resok.size = count - uio.uio_resid;
3359         resp->resok.count = args->count;
3360         resp->resok.freecount = count;
3361 
3362         DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3363             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3364             READDIR3res *, resp);
3365 
3366         VN_RELE(vp);
3367 
3368         return;
3369 
3370 out:
3371         if (curthread->t_flag & T_WOULDBLOCK) {
3372                 curthread->t_flag &= ~T_WOULDBLOCK;
3373                 resp->status = NFS3ERR_JUKEBOX;
3374         } else
3375                 resp->status = puterrno3(error);
3376 out1:
3377         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3378 
3379         DTRACE_NFSV3_5(op__readdir__done, struct svc_req *, req,
3380             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3381             READDIR3res *, resp);
3382 
3383         if (vp != NULL) {
3384                 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3385                 VN_RELE(vp);
3386         }
3387         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3388 }
3389 
3390 void *
3391 rfs3_readdir_getfh(READDIR3args *args)
3392 {
3393 
3394         return (&args->dir);
3395 }
3396 
3397 void
3398 rfs3_readdir_free(READDIR3res *resp)
3399 {
3400 
3401         if (resp->status == NFS3_OK)
3402                 kmem_free(resp->resok.reply.entries, resp->resok.freecount);
 
3452         struct vattr nva;
3453         entryplus3_info *infop = NULL;
3454         int size = 0;
3455         int nents = 0;
3456         int bufsize = 0;
3457         int entrysize = 0;
3458         int tofit = 0;
3459         int rd_unit = rfs3_readdir_unit;
3460         int prev_len;
3461         int space_left;
3462         int i;
3463         uint_t *namlen = NULL;
3464         char *ndata = NULL;
3465         struct sockaddr *ca;
3466         size_t ret;
3467 
3468         vap = NULL;
3469 
3470         vp = nfs3_fhtovp(&args->dir, exi);
3471 
3472         DTRACE_NFSV3_5(op__readdirplus__start, struct svc_req *, req,
3473             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3474             READDIRPLUS3args *, args);
3475 
3476         if (vp == NULL) {
3477                 error = ESTALE;
3478                 goto out;
3479         }
3480 
3481         if (is_system_labeled()) {
3482                 bslabel_t *clabel = req->rq_label;
3483 
3484                 ASSERT(clabel != NULL);
3485                 DTRACE_PROBE2(tx__rfs3__log__info__opreaddirplus__clabel,
3486                     char *, "got client label from request(1)",
3487                     struct svc_req *, req);
3488 
3489                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3490                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3491                             exi)) {
3492                                 resp->status = NFS3ERR_ACCES;
3493                                 goto out1;
3494                         }
 
3736          * reading the file and the overhead is deemed larger
3737          * than the benefit.
3738          */
3739         /*
3740          * Force modified metadata out to stable storage.
3741          */
3742         (void) VOP_FSYNC(vp, FNODSYNC, cr, NULL);
3743 #endif
3744 
3745         kmem_free(namlen, args->dircount);
3746 
3747         resp->status = NFS3_OK;
3748         vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
3749         resp->resok.cookieverf = 0;
3750         resp->resok.reply.entries = (entryplus3 *)ndata;
3751         resp->resok.reply.eof = iseof;
3752         resp->resok.size = nents;
3753         resp->resok.count = args->dircount - ret;
3754         resp->resok.maxcount = args->maxcount;
3755 
3756         DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3757             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3758             READDIRPLUS3res *, resp);
3759 
3760         VN_RELE(vp);
3761 
3762         return;
3763 
3764 out:
3765         if (curthread->t_flag & T_WOULDBLOCK) {
3766                 curthread->t_flag &= ~T_WOULDBLOCK;
3767                 resp->status = NFS3ERR_JUKEBOX;
3768         } else {
3769                 resp->status = puterrno3(error);
3770         }
3771 out1:
3772         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3773 
3774         DTRACE_NFSV3_5(op__readdirplus__done, struct svc_req *, req,
3775             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3776             READDIRPLUS3res *, resp);
3777 
3778         if (vp != NULL) {
3779                 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
3780                 VN_RELE(vp);
3781         }
3782 
3783         if (namlen != NULL)
3784                 kmem_free(namlen, args->dircount);
3785 
3786         vattr_to_post_op_attr(vap, &resp->resfail.dir_attributes);
3787 }
3788 
3789 void *
3790 rfs3_readdirplus_getfh(READDIRPLUS3args *args)
3791 {
3792 
3793         return (&args->dir);
3794 }
3795 
3796 void
3797 rfs3_readdirplus_free(READDIRPLUS3res *resp)
 
3802                 kmem_free(resp->resok.infop,
3803                     resp->resok.size * sizeof (struct entryplus3_info));
3804         }
3805 }
3806 
3807 /* ARGSUSED */
3808 void
3809 rfs3_fsstat(FSSTAT3args *args, FSSTAT3res *resp, struct exportinfo *exi,
3810     struct svc_req *req, cred_t *cr, bool_t ro)
3811 {
3812         int error;
3813         vnode_t *vp;
3814         struct vattr *vap;
3815         struct vattr va;
3816         struct statvfs64 sb;
3817 
3818         vap = NULL;
3819 
3820         vp = nfs3_fhtovp(&args->fsroot, exi);
3821 
3822         DTRACE_NFSV3_5(op__fsstat__start, struct svc_req *, req,
3823             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3824             FSSTAT3args *, args);
3825 
3826         if (vp == NULL) {
3827                 error = ESTALE;
3828                 goto out;
3829         }
3830 
3831         if (is_system_labeled()) {
3832                 bslabel_t *clabel = req->rq_label;
3833 
3834                 ASSERT(clabel != NULL);
3835                 DTRACE_PROBE2(tx__rfs3__log__info__opfsstat__clabel, char *,
3836                     "got client label from request(1)", struct svc_req *, req);
3837 
3838                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3839                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
3840                             exi)) {
3841                                 resp->status = NFS3ERR_ACCES;
3842                                 goto out1;
3843                         }
3844                 }
 
3854 
3855         resp->status = NFS3_OK;
3856         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
3857         if (sb.f_blocks != (fsblkcnt64_t)-1)
3858                 resp->resok.tbytes = (size3)sb.f_frsize * (size3)sb.f_blocks;
3859         else
3860                 resp->resok.tbytes = (size3)sb.f_blocks;
3861         if (sb.f_bfree != (fsblkcnt64_t)-1)
3862                 resp->resok.fbytes = (size3)sb.f_frsize * (size3)sb.f_bfree;
3863         else
3864                 resp->resok.fbytes = (size3)sb.f_bfree;
3865         if (sb.f_bavail != (fsblkcnt64_t)-1)
3866                 resp->resok.abytes = (size3)sb.f_frsize * (size3)sb.f_bavail;
3867         else
3868                 resp->resok.abytes = (size3)sb.f_bavail;
3869         resp->resok.tfiles = (size3)sb.f_files;
3870         resp->resok.ffiles = (size3)sb.f_ffree;
3871         resp->resok.afiles = (size3)sb.f_favail;
3872         resp->resok.invarsec = 0;
3873 
3874         DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3875             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3876             FSSTAT3res *, resp);
3877         VN_RELE(vp);
3878 
3879         return;
3880 
3881 out:
3882         if (curthread->t_flag & T_WOULDBLOCK) {
3883                 curthread->t_flag &= ~T_WOULDBLOCK;
3884                 resp->status = NFS3ERR_JUKEBOX;
3885         } else
3886                 resp->status = puterrno3(error);
3887 out1:
3888         DTRACE_NFSV3_5(op__fsstat__done, struct svc_req *, req,
3889             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3890             FSSTAT3res *, resp);
3891 
3892         if (vp != NULL)
3893                 VN_RELE(vp);
3894         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
3895 }
3896 
3897 void *
3898 rfs3_fsstat_getfh(FSSTAT3args *args)
3899 {
3900 
3901         return (&args->fsroot);
3902 }
3903 
3904 /* ARGSUSED */
3905 void
3906 rfs3_fsinfo(FSINFO3args *args, FSINFO3res *resp, struct exportinfo *exi,
3907     struct svc_req *req, cred_t *cr, bool_t ro)
3908 {
3909         vnode_t *vp;
3910         struct vattr *vap;
3911         struct vattr va;
3912         uint32_t xfer_size;
3913         ulong_t l = 0;
3914         int error;
3915 
3916         vp = nfs3_fhtovp(&args->fsroot, exi);
3917 
3918         DTRACE_NFSV3_5(op__fsinfo__start, struct svc_req *, req,
3919             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3920             FSINFO3args *, args);
3921 
3922         if (vp == NULL) {
3923                 if (curthread->t_flag & T_WOULDBLOCK) {
3924                         curthread->t_flag &= ~T_WOULDBLOCK;
3925                         resp->status = NFS3ERR_JUKEBOX;
3926                 } else
3927                         resp->status = NFS3ERR_STALE;
3928                 vattr_to_post_op_attr(NULL, &resp->resfail.obj_attributes);
3929                 goto out;
3930         }
3931 
3932         if (is_system_labeled()) {
3933                 bslabel_t *clabel = req->rq_label;
3934 
3935                 ASSERT(clabel != NULL);
3936                 DTRACE_PROBE2(tx__rfs3__log__info__opfsinfo__clabel, char *,
3937                     "got client label from request(1)", struct svc_req *, req);
3938 
3939                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
3940                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
 
3974         /*
3975          * If the underlying file system does not support _PC_FILESIZEBITS,
3976          * return a reasonable default. Note that error code on VOP_PATHCONF
3977          * will be 0, even if the underlying file system does not support
3978          * _PC_FILESIZEBITS.
3979          */
3980         if (l == (ulong_t)-1) {
3981                 resp->resok.maxfilesize = MAXOFF32_T;
3982         } else {
3983                 if (l >= (sizeof (uint64_t) * 8))
3984                         resp->resok.maxfilesize = INT64_MAX;
3985                 else
3986                         resp->resok.maxfilesize = (1LL << (l-1)) - 1;
3987         }
3988 
3989         resp->resok.time_delta.seconds = 0;
3990         resp->resok.time_delta.nseconds = 1000;
3991         resp->resok.properties = FSF3_LINK | FSF3_SYMLINK |
3992             FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
3993 
3994         DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
3995             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
3996             FSINFO3res *, resp);
3997 
3998         VN_RELE(vp);
3999 
4000         return;
4001 
4002 out:
4003         DTRACE_NFSV3_5(op__fsinfo__done, struct svc_req *, req,
4004             cred_t *, cr, vnode_t *, NULL, struct exportinfo *, exi,
4005             FSINFO3res *, resp);
4006         if (vp != NULL)
4007                 VN_RELE(vp);
4008 }
4009 
4010 void *
4011 rfs3_fsinfo_getfh(FSINFO3args *args)
4012 {
4013         return (&args->fsroot);
4014 }
4015 
4016 /* ARGSUSED */
4017 void
4018 rfs3_pathconf(PATHCONF3args *args, PATHCONF3res *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 *vap;
4024         struct vattr va;
4025         ulong_t val;
4026 
4027         vap = NULL;
4028 
4029         vp = nfs3_fhtovp(&args->object, exi);
4030 
4031         DTRACE_NFSV3_5(op__pathconf__start, struct svc_req *, req,
4032             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4033             PATHCONF3args *, args);
4034 
4035         if (vp == NULL) {
4036                 error = ESTALE;
4037                 goto out;
4038         }
4039 
4040         if (is_system_labeled()) {
4041                 bslabel_t *clabel = req->rq_label;
4042 
4043                 ASSERT(clabel != NULL);
4044                 DTRACE_PROBE2(tx__rfs3__log__info__oppathconf__clabel, char *,
4045                     "got client label from request(1)", struct svc_req *, req);
4046 
4047                 if (!blequal(&l_admin_low->tsl_label, clabel)) {
4048                         if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
4049                             exi)) {
4050                                 resp->status = NFS3ERR_ACCES;
4051                                 goto out1;
4052                         }
4053                 }
 
4069         error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &val, cr, NULL);
4070         if (error)
4071                 goto out;
4072         if (val == 1)
4073                 resp->resok.info.no_trunc = TRUE;
4074         else
4075                 resp->resok.info.no_trunc = FALSE;
4076 
4077         error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &val, cr, NULL);
4078         if (error)
4079                 goto out;
4080         if (val == 1)
4081                 resp->resok.info.chown_restricted = TRUE;
4082         else
4083                 resp->resok.info.chown_restricted = FALSE;
4084 
4085         resp->status = NFS3_OK;
4086         vattr_to_post_op_attr(vap, &resp->resok.obj_attributes);
4087         resp->resok.info.case_insensitive = FALSE;
4088         resp->resok.info.case_preserving = TRUE;
4089         DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4090             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4091             PATHCONF3res *, resp);
4092         VN_RELE(vp);
4093         return;
4094 
4095 out:
4096         if (curthread->t_flag & T_WOULDBLOCK) {
4097                 curthread->t_flag &= ~T_WOULDBLOCK;
4098                 resp->status = NFS3ERR_JUKEBOX;
4099         } else
4100                 resp->status = puterrno3(error);
4101 out1:
4102         DTRACE_NFSV3_5(op__pathconf__done, struct svc_req *, req,
4103             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4104             PATHCONF3res *, resp);
4105         if (vp != NULL)
4106                 VN_RELE(vp);
4107         vattr_to_post_op_attr(vap, &resp->resfail.obj_attributes);
4108 }
4109 
4110 void *
4111 rfs3_pathconf_getfh(PATHCONF3args *args)
4112 {
4113 
4114         return (&args->object);
4115 }
4116 
4117 void
4118 rfs3_commit(COMMIT3args *args, COMMIT3res *resp, struct exportinfo *exi,
4119     struct svc_req *req, cred_t *cr, bool_t ro)
4120 {
4121         nfs3_srv_t *ns;
4122         int error;
4123         vnode_t *vp;
4124         struct vattr *bvap;
4125         struct vattr bva;
4126         struct vattr *avap;
4127         struct vattr ava;
4128 
4129         bvap = NULL;
4130         avap = NULL;
4131 
4132         vp = nfs3_fhtovp(&args->file, exi);
4133 
4134         DTRACE_NFSV3_5(op__commit__start, struct svc_req *, req,
4135             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4136             COMMIT3args *, args);
4137 
4138         if (vp == NULL) {
4139                 error = ESTALE;
4140                 goto out;
4141         }
4142 
4143         ASSERT3U(curzone->zone_id, ==, exi->exi_zoneid); /* exi is non-NULL. */
4144         ns = nfs3_get_srv();
4145         bva.va_mask = AT_ALL;
4146         error = VOP_GETATTR(vp, &bva, 0, cr, NULL);
4147 
4148         /*
4149          * If we can't get the attributes, then we can't do the
4150          * right access checking.  So, we'll fail the request.
4151          */
4152         if (error)
4153                 goto out;
4154 
4155         bvap = &bva;
4156 
4157         if (rdonly(ro, vp)) {
4158                 resp->status = NFS3ERR_ROFS;
4159                 goto out1;
4160         }
4161 
4162         if (vp->v_type != VREG) {
4163                 resp->status = NFS3ERR_INVAL;
4164                 goto out1;
 
4177                                 resp->status = NFS3ERR_ACCES;
4178                                 goto out1;
4179                         }
4180                 }
4181         }
4182 
4183         if (crgetuid(cr) != bva.va_uid &&
4184             (error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL)))
4185                 goto out;
4186 
4187         error = VOP_FSYNC(vp, FSYNC, cr, NULL);
4188 
4189         ava.va_mask = AT_ALL;
4190         avap = VOP_GETATTR(vp, &ava, 0, cr, NULL) ? NULL : &ava;
4191 
4192         if (error)
4193                 goto out;
4194 
4195         resp->status = NFS3_OK;
4196         vattr_to_wcc_data(bvap, avap, &resp->resok.file_wcc);
4197         resp->resok.verf = ns->write3verf;
4198 
4199         DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4200             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4201             COMMIT3res *, resp);
4202 
4203         VN_RELE(vp);
4204 
4205         return;
4206 
4207 out:
4208         if (curthread->t_flag & T_WOULDBLOCK) {
4209                 curthread->t_flag &= ~T_WOULDBLOCK;
4210                 resp->status = NFS3ERR_JUKEBOX;
4211         } else
4212                 resp->status = puterrno3(error);
4213 out1:
4214         DTRACE_NFSV3_5(op__commit__done, struct svc_req *, req,
4215             cred_t *, cr, vnode_t *, vp, struct exportinfo *, exi,
4216             COMMIT3res *, resp);
4217 
4218         if (vp != NULL)
4219                 VN_RELE(vp);
4220         vattr_to_wcc_data(bvap, avap, &resp->resfail.file_wcc);
4221 }
4222 
4223 void *
4224 rfs3_commit_getfh(COMMIT3args *args)
4225 {
4226 
4227         return (&args->file);
4228 }
4229 
4230 static int
4231 sattr3_to_vattr(sattr3 *sap, struct vattr *vap)
4232 {
4233 
4234         vap->va_mask = 0;
4235 
4236         if (sap->mode.set_it) {
 
4274                 /* check time validity */
4275                 if (!NFS3_TIME_OK(sap->mtime.mtime.seconds))
4276                         return (EOVERFLOW);
4277 #endif
4278                 /*
4279                  * nfs protocol defines times as unsigned so don't extend sign,
4280                  * unless sysadmin set nfs_allow_preepoch_time.
4281                  */
4282                 NFS_TIME_T_CONVERT(vap->va_mtime.tv_sec,
4283                     sap->mtime.mtime.seconds);
4284                 vap->va_mtime.tv_nsec = (uint32_t)sap->mtime.mtime.nseconds;
4285                 vap->va_mask |= AT_MTIME;
4286         } else if (sap->mtime.set_it == SET_TO_SERVER_TIME) {
4287                 gethrestime(&vap->va_mtime);
4288                 vap->va_mask |= AT_MTIME;
4289         }
4290 
4291         return (0);
4292 }
4293 
4294 static const ftype3 vt_to_nf3[] = {
4295         0, NF3REG, NF3DIR, NF3BLK, NF3CHR, NF3LNK, NF3FIFO, 0, 0, NF3SOCK, 0
4296 };
4297 
4298 static int
4299 vattr_to_fattr3(struct vattr *vap, fattr3 *fap)
4300 {
4301 
4302         ASSERT(vap->va_type >= VNON && vap->va_type <= VBAD);
4303         /* Return error if time or size overflow */
4304         if (! (NFS_VAP_TIME_OK(vap) && NFS3_SIZE_OK(vap->va_size))) {
4305                 return (EOVERFLOW);
4306         }
4307         fap->type = vt_to_nf3[vap->va_type];
4308         fap->mode = (mode3)(vap->va_mode & MODEMASK);
4309         fap->nlink = (uint32)vap->va_nlink;
4310         if (vap->va_uid == UID_NOBODY)
4311                 fap->uid = (uid3)NFS_UID_NOBODY;
4312         else
4313                 fap->uid = (uid3)vap->va_uid;
4314         if (vap->va_gid == GID_NOBODY)
 
4356         if ((vap != NULL) && !vattr_to_wcc_attr(vap, &poap->attr)) {
4357                 poap->attributes = TRUE;
4358         } else
4359                 poap->attributes = FALSE;
4360 }
4361 
4362 void
4363 vattr_to_post_op_attr(struct vattr *vap, post_op_attr *poap)
4364 {
4365 
4366         /* don't return attrs if time overflow */
4367         if ((vap != NULL) && !vattr_to_fattr3(vap, &poap->attr)) {
4368                 poap->attributes = TRUE;
4369         } else
4370                 poap->attributes = FALSE;
4371 }
4372 
4373 static void
4374 vattr_to_wcc_data(struct vattr *bvap, struct vattr *avap, wcc_data *wccp)
4375 {
4376         vattr_to_pre_op_attr(bvap, &wccp->before);
4377         vattr_to_post_op_attr(avap, &wccp->after);
4378 }
4379 
4380 static int
4381 rdma_setup_read_data3(READ3args *args, READ3resok *rok)
4382 {
4383         struct clist    *wcl;
4384         int             wlist_len;
4385         count3          count = rok->count;
4386 
4387         wcl = args->wlist;
4388         if (rdma_setup_read_chunks(wcl, count, &wlist_len) == FALSE)
4389                 return (FALSE);
4390 
4391         wcl = args->wlist;
4392         rok->wlist_len = wlist_len;
4393         rok->wlist = wcl;
4394         return (TRUE);
4395 }
4396 
4397 void
4398 rfs3_srv_zone_init(nfs_globals_t *ng)
4399 {
4400         nfs3_srv_t *ns;
4401         struct rfs3_verf_overlay {
4402                 uint_t id; /* a "unique" identifier */
4403                 int ts; /* a unique timestamp */
4404         } *verfp;
4405         timestruc_t now;
4406 
4407         ns = kmem_zalloc(sizeof (*ns), KM_SLEEP);
4408 
4409         /*
4410          * The following algorithm attempts to find a unique verifier
4411          * to be used as the write verifier returned from the server
4412          * to the client.  It is important that this verifier change
4413          * whenever the server reboots.  Of secondary importance, it
4414          * is important for the verifier to be unique between two
4415          * different servers.
4416          *
4417          * Thus, an attempt is made to use the system hostid and the
4418          * current time in seconds when the nfssrv kernel module is
4419          * loaded.  It is assumed that an NFS server will not be able
4420          * to boot and then to reboot in less than a second.  If the
4421          * hostid has not been set, then the current high resolution
4422          * time is used.  This will ensure different verifiers each
4423          * time the server reboots and minimize the chances that two
4424          * different servers will have the same verifier.
4425          */
4426 
4427 #ifndef lint
4428         /*
4429          * We ASSERT that this constant logic expression is
4430          * always true because in the past, it wasn't.
4431          */
4432         ASSERT(sizeof (*verfp) <= sizeof (ns->write3verf));
4433 #endif
4434 
4435         gethrestime(&now);
4436         verfp = (struct rfs3_verf_overlay *)&ns->write3verf;
4437         verfp->ts = (int)now.tv_sec;
4438         verfp->id = zone_get_hostid(NULL);
4439 
4440         if (verfp->id == 0)
4441                 verfp->id = (uint_t)now.tv_nsec;
4442 
4443         ng->nfs3_srv = ns;
4444 }
4445 
4446 void
4447 rfs3_srv_zone_fini(nfs_globals_t *ng)
4448 {
4449         nfs3_srv_t *ns = ng->nfs3_srv;
4450 
4451         ng->nfs3_srv = NULL;
4452 
4453         kmem_free(ns, sizeof (*ns));
4454 }
4455 
4456 void
4457 rfs3_srvrinit(void)
4458 {
4459         nfs3_srv_caller_id = fs_new_caller_id();
4460 }
4461 
4462 void
4463 rfs3_srvrfini(void)
4464 {
4465         /* Nothing to do */
4466 }
 |