The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs/nfs_vnops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: nfs_vnops.c,v 1.267 2008/10/15 14:21:35 pooka Exp $    */
    2 
    3 /*
    4  * Copyright (c) 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Rick Macklem at The University of Guelph.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  *      @(#)nfs_vnops.c 8.19 (Berkeley) 7/31/95
   35  */
   36 
   37 /*
   38  * vnode op calls for Sun NFS version 2 and 3
   39  */
   40 
   41 #include <sys/cdefs.h>
   42 __KERNEL_RCSID(0, "$NetBSD: nfs_vnops.c,v 1.267 2008/10/15 14:21:35 pooka Exp $");
   43 
   44 #include "opt_nfs.h"
   45 #include "opt_uvmhist.h"
   46 
   47 #include <sys/param.h>
   48 #include <sys/proc.h>
   49 #include <sys/kernel.h>
   50 #include <sys/systm.h>
   51 #include <sys/resourcevar.h>
   52 #include <sys/mount.h>
   53 #include <sys/buf.h>
   54 #include <sys/condvar.h>
   55 #include <sys/disk.h>
   56 #include <sys/malloc.h>
   57 #include <sys/kmem.h>
   58 #include <sys/mbuf.h>
   59 #include <sys/mutex.h>
   60 #include <sys/namei.h>
   61 #include <sys/vnode.h>
   62 #include <sys/dirent.h>
   63 #include <sys/fcntl.h>
   64 #include <sys/hash.h>
   65 #include <sys/lockf.h>
   66 #include <sys/stat.h>
   67 #include <sys/unistd.h>
   68 #include <sys/kauth.h>
   69 
   70 #include <uvm/uvm_extern.h>
   71 #include <uvm/uvm.h>
   72 
   73 #include <miscfs/fifofs/fifo.h>
   74 #include <miscfs/genfs/genfs.h>
   75 #include <miscfs/genfs/genfs_node.h>
   76 #include <miscfs/specfs/specdev.h>
   77 
   78 #include <nfs/rpcv2.h>
   79 #include <nfs/nfsproto.h>
   80 #include <nfs/nfs.h>
   81 #include <nfs/nfsnode.h>
   82 #include <nfs/nfsmount.h>
   83 #include <nfs/xdr_subs.h>
   84 #include <nfs/nfsm_subs.h>
   85 #include <nfs/nfs_var.h>
   86 
   87 #include <net/if.h>
   88 #include <netinet/in.h>
   89 #include <netinet/in_var.h>
   90 
   91 /*
   92  * Global vfs data structures for nfs
   93  */
   94 int (**nfsv2_vnodeop_p) __P((void *));
   95 const struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
   96         { &vop_default_desc, vn_default_error },
   97         { &vop_lookup_desc, nfs_lookup },               /* lookup */
   98         { &vop_create_desc, nfs_create },               /* create */
   99         { &vop_mknod_desc, nfs_mknod },                 /* mknod */
  100         { &vop_open_desc, nfs_open },                   /* open */
  101         { &vop_close_desc, nfs_close },                 /* close */
  102         { &vop_access_desc, nfs_access },               /* access */
  103         { &vop_getattr_desc, nfs_getattr },             /* getattr */
  104         { &vop_setattr_desc, nfs_setattr },             /* setattr */
  105         { &vop_read_desc, nfs_read },                   /* read */
  106         { &vop_write_desc, nfs_write },                 /* write */
  107         { &vop_fcntl_desc, genfs_fcntl },               /* fcntl */
  108         { &vop_ioctl_desc, nfs_ioctl },                 /* ioctl */
  109         { &vop_poll_desc, nfs_poll },                   /* poll */
  110         { &vop_kqfilter_desc, nfs_kqfilter },           /* kqfilter */
  111         { &vop_revoke_desc, nfs_revoke },               /* revoke */
  112         { &vop_mmap_desc, nfs_mmap },                   /* mmap */
  113         { &vop_fsync_desc, nfs_fsync },                 /* fsync */
  114         { &vop_seek_desc, nfs_seek },                   /* seek */
  115         { &vop_remove_desc, nfs_remove },               /* remove */
  116         { &vop_link_desc, nfs_link },                   /* link */
  117         { &vop_rename_desc, nfs_rename },               /* rename */
  118         { &vop_mkdir_desc, nfs_mkdir },                 /* mkdir */
  119         { &vop_rmdir_desc, nfs_rmdir },                 /* rmdir */
  120         { &vop_symlink_desc, nfs_symlink },             /* symlink */
  121         { &vop_readdir_desc, nfs_readdir },             /* readdir */
  122         { &vop_readlink_desc, nfs_readlink },           /* readlink */
  123         { &vop_abortop_desc, nfs_abortop },             /* abortop */
  124         { &vop_inactive_desc, nfs_inactive },           /* inactive */
  125         { &vop_reclaim_desc, nfs_reclaim },             /* reclaim */
  126         { &vop_lock_desc, nfs_lock },                   /* lock */
  127         { &vop_unlock_desc, nfs_unlock },               /* unlock */
  128         { &vop_bmap_desc, nfs_bmap },                   /* bmap */
  129         { &vop_strategy_desc, nfs_strategy },           /* strategy */
  130         { &vop_print_desc, nfs_print },                 /* print */
  131         { &vop_islocked_desc, nfs_islocked },           /* islocked */
  132         { &vop_pathconf_desc, nfs_pathconf },           /* pathconf */
  133         { &vop_advlock_desc, nfs_advlock },             /* advlock */
  134         { &vop_bwrite_desc, genfs_badop },              /* bwrite */
  135         { &vop_getpages_desc, nfs_getpages },           /* getpages */
  136         { &vop_putpages_desc, genfs_putpages },         /* putpages */
  137         { NULL, NULL }
  138 };
  139 const struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
  140         { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
  141 
  142 /*
  143  * Special device vnode ops
  144  */
  145 int (**spec_nfsv2nodeop_p) __P((void *));
  146 const struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
  147         { &vop_default_desc, vn_default_error },
  148         { &vop_lookup_desc, spec_lookup },              /* lookup */
  149         { &vop_create_desc, spec_create },              /* create */
  150         { &vop_mknod_desc, spec_mknod },                /* mknod */
  151         { &vop_open_desc, spec_open },                  /* open */
  152         { &vop_close_desc, nfsspec_close },             /* close */
  153         { &vop_access_desc, nfsspec_access },           /* access */
  154         { &vop_getattr_desc, nfs_getattr },             /* getattr */
  155         { &vop_setattr_desc, nfs_setattr },             /* setattr */
  156         { &vop_read_desc, nfsspec_read },               /* read */
  157         { &vop_write_desc, nfsspec_write },             /* write */
  158         { &vop_fcntl_desc, genfs_fcntl },               /* fcntl */
  159         { &vop_ioctl_desc, spec_ioctl },                /* ioctl */
  160         { &vop_poll_desc, spec_poll },                  /* poll */
  161         { &vop_kqfilter_desc, spec_kqfilter },          /* kqfilter */
  162         { &vop_revoke_desc, spec_revoke },              /* revoke */
  163         { &vop_mmap_desc, spec_mmap },                  /* mmap */
  164         { &vop_fsync_desc, spec_fsync },                /* fsync */
  165         { &vop_seek_desc, spec_seek },                  /* seek */
  166         { &vop_remove_desc, spec_remove },              /* remove */
  167         { &vop_link_desc, spec_link },                  /* link */
  168         { &vop_rename_desc, spec_rename },              /* rename */
  169         { &vop_mkdir_desc, spec_mkdir },                /* mkdir */
  170         { &vop_rmdir_desc, spec_rmdir },                /* rmdir */
  171         { &vop_symlink_desc, spec_symlink },            /* symlink */
  172         { &vop_readdir_desc, spec_readdir },            /* readdir */
  173         { &vop_readlink_desc, spec_readlink },          /* readlink */
  174         { &vop_abortop_desc, spec_abortop },            /* abortop */
  175         { &vop_inactive_desc, nfs_inactive },           /* inactive */
  176         { &vop_reclaim_desc, nfs_reclaim },             /* reclaim */
  177         { &vop_lock_desc, nfs_lock },                   /* lock */
  178         { &vop_unlock_desc, nfs_unlock },               /* unlock */
  179         { &vop_bmap_desc, spec_bmap },                  /* bmap */
  180         { &vop_strategy_desc, spec_strategy },          /* strategy */
  181         { &vop_print_desc, nfs_print },                 /* print */
  182         { &vop_islocked_desc, nfs_islocked },           /* islocked */
  183         { &vop_pathconf_desc, spec_pathconf },          /* pathconf */
  184         { &vop_advlock_desc, spec_advlock },            /* advlock */
  185         { &vop_bwrite_desc, spec_bwrite },              /* bwrite */
  186         { &vop_getpages_desc, spec_getpages },          /* getpages */
  187         { &vop_putpages_desc, spec_putpages },          /* putpages */
  188         { NULL, NULL }
  189 };
  190 const struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
  191         { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
  192 
  193 int (**fifo_nfsv2nodeop_p) __P((void *));
  194 const struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
  195         { &vop_default_desc, vn_default_error },
  196         { &vop_lookup_desc, fifo_lookup },              /* lookup */
  197         { &vop_create_desc, fifo_create },              /* create */
  198         { &vop_mknod_desc, fifo_mknod },                /* mknod */
  199         { &vop_open_desc, fifo_open },                  /* open */
  200         { &vop_close_desc, nfsfifo_close },             /* close */
  201         { &vop_access_desc, nfsspec_access },           /* access */
  202         { &vop_getattr_desc, nfs_getattr },             /* getattr */
  203         { &vop_setattr_desc, nfs_setattr },             /* setattr */
  204         { &vop_read_desc, nfsfifo_read },               /* read */
  205         { &vop_write_desc, nfsfifo_write },             /* write */
  206         { &vop_fcntl_desc, genfs_fcntl },               /* fcntl */
  207         { &vop_ioctl_desc, fifo_ioctl },                /* ioctl */
  208         { &vop_poll_desc, fifo_poll },                  /* poll */
  209         { &vop_kqfilter_desc, fifo_kqfilter },          /* kqfilter */
  210         { &vop_revoke_desc, fifo_revoke },              /* revoke */
  211         { &vop_mmap_desc, fifo_mmap },                  /* mmap */
  212         { &vop_fsync_desc, nfs_fsync },                 /* fsync */
  213         { &vop_seek_desc, fifo_seek },                  /* seek */
  214         { &vop_remove_desc, fifo_remove },              /* remove */
  215         { &vop_link_desc, fifo_link },                  /* link */
  216         { &vop_rename_desc, fifo_rename },              /* rename */
  217         { &vop_mkdir_desc, fifo_mkdir },                /* mkdir */
  218         { &vop_rmdir_desc, fifo_rmdir },                /* rmdir */
  219         { &vop_symlink_desc, fifo_symlink },            /* symlink */
  220         { &vop_readdir_desc, fifo_readdir },            /* readdir */
  221         { &vop_readlink_desc, fifo_readlink },          /* readlink */
  222         { &vop_abortop_desc, fifo_abortop },            /* abortop */
  223         { &vop_inactive_desc, nfs_inactive },           /* inactive */
  224         { &vop_reclaim_desc, nfs_reclaim },             /* reclaim */
  225         { &vop_lock_desc, nfs_lock },                   /* lock */
  226         { &vop_unlock_desc, nfs_unlock },               /* unlock */
  227         { &vop_bmap_desc, fifo_bmap },                  /* bmap */
  228         { &vop_strategy_desc, genfs_badop },            /* strategy */
  229         { &vop_print_desc, nfs_print },                 /* print */
  230         { &vop_islocked_desc, nfs_islocked },           /* islocked */
  231         { &vop_pathconf_desc, fifo_pathconf },          /* pathconf */
  232         { &vop_advlock_desc, fifo_advlock },            /* advlock */
  233         { &vop_bwrite_desc, genfs_badop },              /* bwrite */
  234         { &vop_putpages_desc, fifo_putpages },          /* putpages */
  235         { NULL, NULL }
  236 };
  237 const struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
  238         { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
  239 
  240 static int nfs_linkrpc(struct vnode *, struct vnode *, const char *,
  241     size_t, kauth_cred_t, struct lwp *);
  242 static void nfs_writerpc_extfree(struct mbuf *, void *, size_t, void *);
  243 
  244 /*
  245  * Global variables
  246  */
  247 extern u_int32_t nfs_true, nfs_false;
  248 extern u_int32_t nfs_xdrneg1;
  249 extern const nfstype nfsv3_type[9];
  250 
  251 int nfs_numasync = 0;
  252 #define DIRHDSIZ        _DIRENT_NAMEOFF(dp)
  253 #define UIO_ADVANCE(uio, siz) \
  254     (void)((uio)->uio_resid -= (siz), \
  255     (uio)->uio_iov->iov_base = (char *)(uio)->uio_iov->iov_base + (siz), \
  256     (uio)->uio_iov->iov_len -= (siz))
  257 
  258 static void nfs_cache_enter(struct vnode *, struct vnode *,
  259     struct componentname *);
  260 
  261 static void
  262 nfs_cache_enter(struct vnode *dvp, struct vnode *vp,
  263     struct componentname *cnp)
  264 {
  265         struct nfsnode *dnp = VTONFS(dvp);
  266 
  267         if (vp != NULL) {
  268                 struct nfsnode *np = VTONFS(vp);
  269 
  270                 np->n_ctime = np->n_vattr->va_ctime.tv_sec;
  271         }
  272 
  273         if (!timespecisset(&dnp->n_nctime))
  274                 dnp->n_nctime = dnp->n_vattr->va_mtime;
  275 
  276         cache_enter(dvp, vp, cnp);
  277 }
  278 
  279 /*
  280  * nfs null call from vfs.
  281  */
  282 int
  283 nfs_null(vp, cred, l)
  284         struct vnode *vp;
  285         kauth_cred_t cred;
  286         struct lwp *l;
  287 {
  288         char *bpos, *dpos;
  289         int error = 0;
  290         struct mbuf *mreq, *mrep, *md, *mb;
  291         struct nfsnode *np = VTONFS(vp);
  292 
  293         nfsm_reqhead(np, NFSPROC_NULL, 0);
  294         nfsm_request(np, NFSPROC_NULL, l, cred);
  295         nfsm_reqdone;
  296         return (error);
  297 }
  298 
  299 /*
  300  * nfs access vnode op.
  301  * For nfs version 2, just return ok. File accesses may fail later.
  302  * For nfs version 3, use the access rpc to check accessibility. If file modes
  303  * are changed on the server, accesses might still fail later.
  304  */
  305 int
  306 nfs_access(v)
  307         void *v;
  308 {
  309         struct vop_access_args /* {
  310                 struct vnode *a_vp;
  311                 int  a_mode;
  312                 kauth_cred_t a_cred;
  313         } */ *ap = v;
  314         struct vnode *vp = ap->a_vp;
  315 #ifndef NFS_V2_ONLY
  316         u_int32_t *tl;
  317         char *cp;
  318         int32_t t1, t2;
  319         char *bpos, *dpos, *cp2;
  320         int error = 0, attrflag;
  321         struct mbuf *mreq, *mrep, *md, *mb;
  322         u_int32_t mode, rmode;
  323         const int v3 = NFS_ISV3(vp);
  324 #endif
  325         int cachevalid;
  326         struct nfsnode *np = VTONFS(vp);
  327         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
  328 
  329         cachevalid = (np->n_accstamp != -1 &&
  330             (time_uptime - np->n_accstamp) < nfs_attrtimeo(nmp, np) &&
  331             np->n_accuid == kauth_cred_geteuid(ap->a_cred));
  332 
  333         /*
  334          * Check access cache first. If this request has been made for this
  335          * uid shortly before, use the cached result.
  336          */
  337         if (cachevalid) {
  338                 if (!np->n_accerror) {
  339                         if  ((np->n_accmode & ap->a_mode) == ap->a_mode)
  340                                 return np->n_accerror;
  341                 } else if ((np->n_accmode & ap->a_mode) == np->n_accmode)
  342                         return np->n_accerror;
  343         }
  344 
  345 #ifndef NFS_V2_ONLY
  346         /*
  347          * For nfs v3, do an access rpc, otherwise you are stuck emulating
  348          * ufs_access() locally using the vattr. This may not be correct,
  349          * since the server may apply other access criteria such as
  350          * client uid-->server uid mapping that we do not know about, but
  351          * this is better than just returning anything that is lying about
  352          * in the cache.
  353          */
  354         if (v3) {
  355                 nfsstats.rpccnt[NFSPROC_ACCESS]++;
  356                 nfsm_reqhead(np, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
  357                 nfsm_fhtom(np, v3);
  358                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
  359                 if (ap->a_mode & VREAD)
  360                         mode = NFSV3ACCESS_READ;
  361                 else
  362                         mode = 0;
  363                 if (vp->v_type != VDIR) {
  364                         if (ap->a_mode & VWRITE)
  365                                 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
  366                         if (ap->a_mode & VEXEC)
  367                                 mode |= NFSV3ACCESS_EXECUTE;
  368                 } else {
  369                         if (ap->a_mode & VWRITE)
  370                                 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
  371                                          NFSV3ACCESS_DELETE);
  372                         if (ap->a_mode & VEXEC)
  373                                 mode |= NFSV3ACCESS_LOOKUP;
  374                 }
  375                 *tl = txdr_unsigned(mode);
  376                 nfsm_request(np, NFSPROC_ACCESS, curlwp, ap->a_cred);
  377                 nfsm_postop_attr(vp, attrflag, 0);
  378                 if (!error) {
  379                         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
  380                         rmode = fxdr_unsigned(u_int32_t, *tl);
  381                         /*
  382                          * The NFS V3 spec does not clarify whether or not
  383                          * the returned access bits can be a superset of
  384                          * the ones requested, so...
  385                          */
  386                         if ((rmode & mode) != mode)
  387                                 error = EACCES;
  388                 }
  389                 nfsm_reqdone;
  390         } else
  391 #endif
  392                 return (nfsspec_access(ap));
  393 #ifndef NFS_V2_ONLY
  394         /*
  395          * Disallow write attempts on filesystems mounted read-only;
  396          * unless the file is a socket, fifo, or a block or character
  397          * device resident on the filesystem.
  398          */
  399         if (!error && (ap->a_mode & VWRITE) &&
  400             (vp->v_mount->mnt_flag & MNT_RDONLY)) {
  401                 switch (vp->v_type) {
  402                 case VREG:
  403                 case VDIR:
  404                 case VLNK:
  405                         error = EROFS;
  406                 default:
  407                         break;
  408                 }
  409         }
  410 
  411         if (!error || error == EACCES) {
  412                 /*
  413                  * If we got the same result as for a previous,
  414                  * different request, OR it in. Don't update
  415                  * the timestamp in that case.
  416                  */
  417                 if (cachevalid && np->n_accstamp != -1 &&
  418                     error == np->n_accerror) {
  419                         if (!error)
  420                                 np->n_accmode |= ap->a_mode;
  421                         else if ((np->n_accmode & ap->a_mode) == ap->a_mode)
  422                                 np->n_accmode = ap->a_mode;
  423                 } else {
  424                         np->n_accstamp = time_uptime;
  425                         np->n_accuid = kauth_cred_geteuid(ap->a_cred);
  426                         np->n_accmode = ap->a_mode;
  427                         np->n_accerror = error;
  428                 }
  429         }
  430 
  431         return (error);
  432 #endif
  433 }
  434 
  435 /*
  436  * nfs open vnode op
  437  * Check to see if the type is ok
  438  * and that deletion is not in progress.
  439  * For paged in text files, you will need to flush the page cache
  440  * if consistency is lost.
  441  */
  442 /* ARGSUSED */
  443 int
  444 nfs_open(v)
  445         void *v;
  446 {
  447         struct vop_open_args /* {
  448                 struct vnode *a_vp;
  449                 int  a_mode;
  450                 kauth_cred_t a_cred;
  451         } */ *ap = v;
  452         struct vnode *vp = ap->a_vp;
  453         struct nfsnode *np = VTONFS(vp);
  454         int error;
  455 
  456         if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
  457                 return (EACCES);
  458         }
  459 
  460         if (ap->a_mode & FREAD) {
  461                 if (np->n_rcred != NULL)
  462                         kauth_cred_free(np->n_rcred);
  463                 np->n_rcred = ap->a_cred;
  464                 kauth_cred_hold(np->n_rcred);
  465         }
  466         if (ap->a_mode & FWRITE) {
  467                 if (np->n_wcred != NULL)
  468                         kauth_cred_free(np->n_wcred);
  469                 np->n_wcred = ap->a_cred;
  470                 kauth_cred_hold(np->n_wcred);
  471         }
  472 
  473         error = nfs_flushstalebuf(vp, ap->a_cred, curlwp, 0);
  474         if (error)
  475                 return error;
  476 
  477         NFS_INVALIDATE_ATTRCACHE(np); /* For Open/Close consistency */
  478 
  479         return (0);
  480 }
  481 
  482 /*
  483  * nfs close vnode op
  484  * What an NFS client should do upon close after writing is a debatable issue.
  485  * Most NFS clients push delayed writes to the server upon close, basically for
  486  * two reasons:
  487  * 1 - So that any write errors may be reported back to the client process
  488  *     doing the close system call. By far the two most likely errors are
  489  *     NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
  490  * 2 - To put a worst case upper bound on cache inconsistency between
  491  *     multiple clients for the file.
  492  * There is also a consistency problem for Version 2 of the protocol w.r.t.
  493  * not being able to tell if other clients are writing a file concurrently,
  494  * since there is no way of knowing if the changed modify time in the reply
  495  * is only due to the write for this client.
  496  * (NFS Version 3 provides weak cache consistency data in the reply that
  497  *  should be sufficient to detect and handle this case.)
  498  *
  499  * The current code does the following:
  500  * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
  501  * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
  502  *                     or commit them (this satisfies 1 and 2 except for the
  503  *                     case where the server crashes after this close but
  504  *                     before the commit RPC, which is felt to be "good
  505  *                     enough". Changing the last argument to nfs_flush() to
  506  *                     a 1 would force a commit operation, if it is felt a
  507  *                     commit is necessary now.
  508  */
  509 /* ARGSUSED */
  510 int
  511 nfs_close(v)
  512         void *v;
  513 {
  514         struct vop_close_args /* {
  515                 struct vnodeop_desc *a_desc;
  516                 struct vnode *a_vp;
  517                 int  a_fflag;
  518                 kauth_cred_t a_cred;
  519         } */ *ap = v;
  520         struct vnode *vp = ap->a_vp;
  521         struct nfsnode *np = VTONFS(vp);
  522         int error = 0;
  523         UVMHIST_FUNC("nfs_close"); UVMHIST_CALLED(ubchist);
  524 
  525         if (vp->v_type == VREG) {
  526             if (np->n_flag & NMODIFIED) {
  527 #ifndef NFS_V2_ONLY
  528                 if (NFS_ISV3(vp)) {
  529                     error = nfs_flush(vp, ap->a_cred, MNT_WAIT, curlwp, 0);
  530                     np->n_flag &= ~NMODIFIED;
  531                 } else
  532 #endif
  533                     error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, curlwp, 1);
  534                 NFS_INVALIDATE_ATTRCACHE(np);
  535             }
  536             if (np->n_flag & NWRITEERR) {
  537                 np->n_flag &= ~NWRITEERR;
  538                 error = np->n_error;
  539             }
  540         }
  541         UVMHIST_LOG(ubchist, "returning %d", error,0,0,0);
  542         return (error);
  543 }
  544 
  545 /*
  546  * nfs getattr call from vfs.
  547  */
  548 int
  549 nfs_getattr(v)
  550         void *v;
  551 {
  552         struct vop_getattr_args /* {
  553                 struct vnode *a_vp;
  554                 struct vattr *a_vap;
  555                 kauth_cred_t a_cred;
  556         } */ *ap = v;
  557         struct vnode *vp = ap->a_vp;
  558         struct nfsnode *np = VTONFS(vp);
  559         char *cp;
  560         u_int32_t *tl;
  561         int32_t t1, t2;
  562         char *bpos, *dpos;
  563         int error = 0;
  564         struct mbuf *mreq, *mrep, *md, *mb;
  565         const int v3 = NFS_ISV3(vp);
  566 
  567         /*
  568          * Update local times for special files.
  569          */
  570         if (np->n_flag & (NACC | NUPD))
  571                 np->n_flag |= NCHG;
  572 
  573         /*
  574          * if we have delayed truncation, do it now.
  575          */
  576         nfs_delayedtruncate(vp);
  577 
  578         /*
  579          * First look in the cache.
  580          */
  581         if (nfs_getattrcache(vp, ap->a_vap) == 0)
  582                 return (0);
  583         nfsstats.rpccnt[NFSPROC_GETATTR]++;
  584         nfsm_reqhead(np, NFSPROC_GETATTR, NFSX_FH(v3));
  585         nfsm_fhtom(np, v3);
  586         nfsm_request(np, NFSPROC_GETATTR, curlwp, ap->a_cred);
  587         if (!error) {
  588                 nfsm_loadattr(vp, ap->a_vap, 0);
  589                 if (vp->v_type == VDIR &&
  590                     ap->a_vap->va_blocksize < NFS_DIRFRAGSIZ)
  591                         ap->a_vap->va_blocksize = NFS_DIRFRAGSIZ;
  592         }
  593         nfsm_reqdone;
  594         return (error);
  595 }
  596 
  597 /*
  598  * nfs setattr call.
  599  */
  600 int
  601 nfs_setattr(v)
  602         void *v;
  603 {
  604         struct vop_setattr_args /* {
  605                 struct vnodeop_desc *a_desc;
  606                 struct vnode *a_vp;
  607                 struct vattr *a_vap;
  608                 kauth_cred_t a_cred;
  609         } */ *ap = v;
  610         struct vnode *vp = ap->a_vp;
  611         struct nfsnode *np = VTONFS(vp);
  612         struct vattr *vap = ap->a_vap;
  613         int error = 0;
  614         u_quad_t tsize = 0;
  615 
  616         /*
  617          * Setting of flags is not supported.
  618          */
  619         if (vap->va_flags != VNOVAL)
  620                 return (EOPNOTSUPP);
  621 
  622         /*
  623          * Disallow write attempts if the filesystem is mounted read-only.
  624          */
  625         if ((vap->va_uid != (uid_t)VNOVAL ||
  626             vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
  627             vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
  628             (vp->v_mount->mnt_flag & MNT_RDONLY))
  629                 return (EROFS);
  630         if (vap->va_size != VNOVAL) {
  631                 if (vap->va_size > VFSTONFS(vp->v_mount)->nm_maxfilesize) {
  632                         return EFBIG;
  633                 }
  634                 switch (vp->v_type) {
  635                 case VDIR:
  636                         return (EISDIR);
  637                 case VCHR:
  638                 case VBLK:
  639                 case VSOCK:
  640                 case VFIFO:
  641                         if (vap->va_mtime.tv_sec == VNOVAL &&
  642                             vap->va_atime.tv_sec == VNOVAL &&
  643                             vap->va_mode == (mode_t)VNOVAL &&
  644                             vap->va_uid == (uid_t)VNOVAL &&
  645                             vap->va_gid == (gid_t)VNOVAL)
  646                                 return (0);
  647                         vap->va_size = VNOVAL;
  648                         break;
  649                 default:
  650                         /*
  651                          * Disallow write attempts if the filesystem is
  652                          * mounted read-only.
  653                          */
  654                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  655                                 return (EROFS);
  656                         genfs_node_wrlock(vp);
  657                         uvm_vnp_setsize(vp, vap->va_size);
  658                         tsize = np->n_size;
  659                         np->n_size = vap->va_size;
  660                         if (vap->va_size == 0)
  661                                 error = nfs_vinvalbuf(vp, 0,
  662                                      ap->a_cred, curlwp, 1);
  663                         else
  664                                 error = nfs_vinvalbuf(vp, V_SAVE,
  665                                      ap->a_cred, curlwp, 1);
  666                         if (error) {
  667                                 uvm_vnp_setsize(vp, tsize);
  668                                 genfs_node_unlock(vp);
  669                                 return (error);
  670                         }
  671                         np->n_vattr->va_size = vap->va_size;
  672                 }
  673         } else {
  674                 /*
  675                  * flush files before setattr because a later write of
  676                  * cached data might change timestamps or reset sugid bits
  677                  */
  678                 if ((vap->va_mtime.tv_sec != VNOVAL ||
  679                      vap->va_atime.tv_sec != VNOVAL ||
  680                      vap->va_mode != VNOVAL) &&
  681                     vp->v_type == VREG &&
  682                     (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
  683                                            curlwp, 1)) == EINTR)
  684                         return (error);
  685         }
  686         error = nfs_setattrrpc(vp, vap, ap->a_cred, curlwp);
  687         if (vap->va_size != VNOVAL) {
  688                 if (error) {
  689                         np->n_size = np->n_vattr->va_size = tsize;
  690                         uvm_vnp_setsize(vp, np->n_size);
  691                 }
  692                 genfs_node_unlock(vp);
  693         }
  694         VN_KNOTE(vp, NOTE_ATTRIB);
  695         return (error);
  696 }
  697 
  698 /*
  699  * Do an nfs setattr rpc.
  700  */
  701 int
  702 nfs_setattrrpc(vp, vap, cred, l)
  703         struct vnode *vp;
  704         struct vattr *vap;
  705         kauth_cred_t cred;
  706         struct lwp *l;
  707 {
  708         struct nfsv2_sattr *sp;
  709         char *cp;
  710         int32_t t1, t2;
  711         char *bpos, *dpos;
  712         u_int32_t *tl;
  713         int error = 0;
  714         struct mbuf *mreq, *mrep, *md, *mb;
  715         const int v3 = NFS_ISV3(vp);
  716         struct nfsnode *np = VTONFS(vp);
  717 #ifndef NFS_V2_ONLY
  718         int wccflag = NFSV3_WCCRATTR;
  719         char *cp2;
  720 #endif
  721 
  722         nfsstats.rpccnt[NFSPROC_SETATTR]++;
  723         nfsm_reqhead(np, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
  724         nfsm_fhtom(np, v3);
  725 #ifndef NFS_V2_ONLY
  726         if (v3) {
  727                 nfsm_v3attrbuild(vap, true);
  728                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
  729                 *tl = nfs_false;
  730         } else {
  731 #endif
  732                 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
  733                 if (vap->va_mode == (mode_t)VNOVAL)
  734                         sp->sa_mode = nfs_xdrneg1;
  735                 else
  736                         sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
  737                 if (vap->va_uid == (uid_t)VNOVAL)
  738                         sp->sa_uid = nfs_xdrneg1;
  739                 else
  740                         sp->sa_uid = txdr_unsigned(vap->va_uid);
  741                 if (vap->va_gid == (gid_t)VNOVAL)
  742                         sp->sa_gid = nfs_xdrneg1;
  743                 else
  744                         sp->sa_gid = txdr_unsigned(vap->va_gid);
  745                 sp->sa_size = txdr_unsigned(vap->va_size);
  746                 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
  747                 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
  748 #ifndef NFS_V2_ONLY
  749         }
  750 #endif
  751         nfsm_request(np, NFSPROC_SETATTR, l, cred);
  752 #ifndef NFS_V2_ONLY
  753         if (v3) {
  754                 nfsm_wcc_data(vp, wccflag, NAC_NOTRUNC, false);
  755         } else
  756 #endif
  757                 nfsm_loadattr(vp, (struct vattr *)0, NAC_NOTRUNC);
  758         nfsm_reqdone;
  759         return (error);
  760 }
  761 
  762 /*
  763  * nfs lookup call, one step at a time...
  764  * First look in cache
  765  * If not found, unlock the directory nfsnode and do the rpc
  766  *
  767  * This code is full of lock/unlock statements and checks, because
  768  * we continue after cache_lookup has finished (we need to check
  769  * with the attr cache and do an rpc if it has timed out). This means
  770  * that the locking effects of cache_lookup have to be taken into
  771  * account.
  772  */
  773 int
  774 nfs_lookup(v)
  775         void *v;
  776 {
  777         struct vop_lookup_args /* {
  778                 struct vnodeop_desc *a_desc;
  779                 struct vnode *a_dvp;
  780                 struct vnode **a_vpp;
  781                 struct componentname *a_cnp;
  782         } */ *ap = v;
  783         struct componentname *cnp = ap->a_cnp;
  784         struct vnode *dvp = ap->a_dvp;
  785         struct vnode **vpp = ap->a_vpp;
  786         int flags;
  787         struct vnode *newvp;
  788         u_int32_t *tl;
  789         char *cp;
  790         int32_t t1, t2;
  791         char *bpos, *dpos, *cp2;
  792         struct mbuf *mreq, *mrep, *md, *mb;
  793         long len;
  794         nfsfh_t *fhp;
  795         struct nfsnode *np;
  796         int error = 0, attrflag, fhsize;
  797         const int v3 = NFS_ISV3(dvp);
  798 
  799         flags = cnp->cn_flags;
  800 
  801         *vpp = NULLVP;
  802         newvp = NULLVP;
  803         if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
  804             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
  805                 return (EROFS);
  806         if (dvp->v_type != VDIR)
  807                 return (ENOTDIR);
  808 
  809         /*
  810          * RFC1813(nfsv3) 3.2 says clients should handle "." by themselves.
  811          */
  812         if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
  813                 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred);
  814                 if (error)
  815                         return error;
  816                 if (cnp->cn_nameiop == RENAME && (flags & ISLASTCN))
  817                         return EISDIR;
  818                 VREF(dvp);
  819                 *vpp = dvp;
  820                 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
  821                         cnp->cn_flags |= SAVENAME;
  822                 return 0;
  823         }
  824 
  825         np = VTONFS(dvp);
  826 
  827         /*
  828          * Before tediously performing a linear scan of the directory,
  829          * check the name cache to see if the directory/name pair
  830          * we are looking for is known already.
  831          * If the directory/name pair is found in the name cache,
  832          * we have to ensure the directory has not changed from
  833          * the time the cache entry has been created. If it has,
  834          * the cache entry has to be ignored.
  835          */
  836         error = cache_lookup_raw(dvp, vpp, cnp);
  837         KASSERT(dvp != *vpp);
  838         if (error >= 0) {
  839                 struct vattr vattr;
  840                 int err2;
  841 
  842                 if (error && error != ENOENT) {
  843                         *vpp = NULLVP;
  844                         return error;
  845                 }
  846 
  847                 err2 = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred);
  848                 if (err2 != 0) {
  849                         if (error == 0)
  850                                 vrele(*vpp);
  851                         *vpp = NULLVP;
  852                         return err2;
  853                 }
  854 
  855                 if (VOP_GETATTR(dvp, &vattr, cnp->cn_cred)
  856                     || timespeccmp(&vattr.va_mtime,
  857                     &VTONFS(dvp)->n_nctime, !=)) {
  858                         if (error == 0) {
  859                                 vrele(*vpp);
  860                                 *vpp = NULLVP;
  861                         }
  862                         cache_purge1(dvp, NULL, PURGE_CHILDREN);
  863                         timespecclear(&np->n_nctime);
  864                         goto dorpc;
  865                 }
  866 
  867                 if (error == ENOENT) {
  868                         goto noentry;
  869                 }
  870 
  871                 newvp = *vpp;
  872                 if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred)
  873                     && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
  874                         nfsstats.lookupcache_hits++;
  875                         if ((flags & ISDOTDOT) != 0) {
  876                                 VOP_UNLOCK(dvp, 0);
  877                         }
  878                         error = vn_lock(newvp, LK_EXCLUSIVE);
  879                         if ((flags & ISDOTDOT) != 0) {
  880                                 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
  881                         }
  882                         if (error) {
  883                                 /* newvp has been revoked. */
  884                                 vrele(newvp);
  885                                 *vpp = NULL;
  886                                 return error;
  887                         }
  888                         if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
  889                                 cnp->cn_flags |= SAVENAME;
  890                         KASSERT(newvp->v_type != VNON);
  891                         return (0);
  892                 }
  893                 cache_purge1(newvp, NULL, PURGE_PARENTS);
  894                 vrele(newvp);
  895                 *vpp = NULLVP;
  896         }
  897 dorpc:
  898 #if 0
  899         /*
  900          * because nfsv3 has the same CREATE semantics as ours,
  901          * we don't have to perform LOOKUPs beforehand.
  902          *
  903          * XXX ideally we can do the same for nfsv2 in the case of !O_EXCL.
  904          * XXX although we have no way to know if O_EXCL is requested or not.
  905          */
  906 
  907         if (v3 && cnp->cn_nameiop == CREATE &&
  908             (flags & (ISLASTCN|ISDOTDOT)) == ISLASTCN &&
  909             (dvp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
  910                 cnp->cn_flags |= SAVENAME;
  911                 return (EJUSTRETURN);
  912         }
  913 #endif /* 0 */
  914 
  915         error = 0;
  916         newvp = NULLVP;
  917         nfsstats.lookupcache_misses++;
  918         nfsstats.rpccnt[NFSPROC_LOOKUP]++;
  919         len = cnp->cn_namelen;
  920         nfsm_reqhead(np, NFSPROC_LOOKUP,
  921                 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
  922         nfsm_fhtom(np, v3);
  923         nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
  924         nfsm_request(np, NFSPROC_LOOKUP, curlwp, cnp->cn_cred);
  925         if (error) {
  926                 nfsm_postop_attr(dvp, attrflag, 0);
  927                 m_freem(mrep);
  928                 goto nfsmout;
  929         }
  930         nfsm_getfh(fhp, fhsize, v3);
  931 
  932         /*
  933          * Handle RENAME case...
  934          */
  935         if (cnp->cn_nameiop == RENAME && (flags & ISLASTCN)) {
  936                 if (NFS_CMPFH(np, fhp, fhsize)) {
  937                         m_freem(mrep);
  938                         return (EISDIR);
  939                 }
  940                 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
  941                 if (error) {
  942                         m_freem(mrep);
  943                         return error;
  944                 }
  945                 newvp = NFSTOV(np);
  946 #ifndef NFS_V2_ONLY
  947                 if (v3) {
  948                         nfsm_postop_attr(newvp, attrflag, 0);
  949                         nfsm_postop_attr(dvp, attrflag, 0);
  950                 } else
  951 #endif
  952                         nfsm_loadattr(newvp, (struct vattr *)0, 0);
  953                 *vpp = newvp;
  954                 m_freem(mrep);
  955                 cnp->cn_flags |= SAVENAME;
  956                 goto validate;
  957         }
  958 
  959         /*
  960          * The postop attr handling is duplicated for each if case,
  961          * because it should be done while dvp is locked (unlocking
  962          * dvp is different for each case).
  963          */
  964 
  965         if (NFS_CMPFH(np, fhp, fhsize)) {
  966                 /*
  967                  * "." lookup
  968                  */
  969                 VREF(dvp);
  970                 newvp = dvp;
  971 #ifndef NFS_V2_ONLY
  972                 if (v3) {
  973                         nfsm_postop_attr(newvp, attrflag, 0);
  974                         nfsm_postop_attr(dvp, attrflag, 0);
  975                 } else
  976 #endif
  977                         nfsm_loadattr(newvp, (struct vattr *)0, 0);
  978         } else if (flags & ISDOTDOT) {
  979                 /*
  980                  * ".." lookup
  981                  */
  982                 VOP_UNLOCK(dvp, 0);
  983                 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
  984                 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
  985                 if (error) {
  986                         m_freem(mrep);
  987                         return error;
  988                 }
  989                 newvp = NFSTOV(np);
  990 
  991 #ifndef NFS_V2_ONLY
  992                 if (v3) {
  993                         nfsm_postop_attr(newvp, attrflag, 0);
  994                         nfsm_postop_attr(dvp, attrflag, 0);
  995                 } else
  996 #endif
  997                         nfsm_loadattr(newvp, (struct vattr *)0, 0);
  998         } else {
  999                 /*
 1000                  * Other lookups.
 1001                  */
 1002                 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
 1003                 if (error) {
 1004                         m_freem(mrep);
 1005                         return error;
 1006                 }
 1007                 newvp = NFSTOV(np);
 1008 #ifndef NFS_V2_ONLY
 1009                 if (v3) {
 1010                         nfsm_postop_attr(newvp, attrflag, 0);
 1011                         nfsm_postop_attr(dvp, attrflag, 0);
 1012                 } else
 1013 #endif
 1014                         nfsm_loadattr(newvp, (struct vattr *)0, 0);
 1015         }
 1016         if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
 1017                 cnp->cn_flags |= SAVENAME;
 1018         if ((cnp->cn_flags & MAKEENTRY) &&
 1019             (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
 1020                 nfs_cache_enter(dvp, newvp, cnp);
 1021         }
 1022         *vpp = newvp;
 1023         nfsm_reqdone;
 1024         if (error) {
 1025                 /*
 1026                  * We get here only because of errors returned by
 1027                  * the RPC. Otherwise we'll have returned above
 1028                  * (the nfsm_* macros will jump to nfsm_reqdone
 1029                  * on error).
 1030                  */
 1031                 if (error == ENOENT && (cnp->cn_flags & MAKEENTRY) &&
 1032                     cnp->cn_nameiop != CREATE) {
 1033                         nfs_cache_enter(dvp, NULL, cnp);
 1034                 }
 1035                 if (newvp != NULLVP) {
 1036                         if (newvp == dvp) {
 1037                                 vrele(newvp);
 1038                         } else {
 1039                                 vput(newvp);
 1040                         }
 1041                 }
 1042 noentry:
 1043                 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
 1044                     (flags & ISLASTCN) && error == ENOENT) {
 1045                         if (dvp->v_mount->mnt_flag & MNT_RDONLY) {
 1046                                 error = EROFS;
 1047                         } else {
 1048                                 error = EJUSTRETURN;
 1049                                 cnp->cn_flags |= SAVENAME;
 1050                         }
 1051                 }
 1052                 *vpp = NULL;
 1053                 return error;
 1054         }
 1055 
 1056 validate:
 1057         /*
 1058          * make sure we have valid type and size.
 1059          */
 1060 
 1061         newvp = *vpp;
 1062         if (newvp->v_type == VNON) {
 1063                 struct vattr vattr; /* dummy */
 1064 
 1065                 KASSERT(VTONFS(newvp)->n_attrstamp == 0);
 1066                 error = VOP_GETATTR(newvp, &vattr, cnp->cn_cred);
 1067                 if (error) {
 1068                         vput(newvp);
 1069                         *vpp = NULL;
 1070                 }
 1071         }
 1072 
 1073         return error;
 1074 }
 1075 
 1076 /*
 1077  * nfs read call.
 1078  * Just call nfs_bioread() to do the work.
 1079  */
 1080 int
 1081 nfs_read(v)
 1082         void *v;
 1083 {
 1084         struct vop_read_args /* {
 1085                 struct vnode *a_vp;
 1086                 struct uio *a_uio;
 1087                 int  a_ioflag;
 1088                 kauth_cred_t a_cred;
 1089         } */ *ap = v;
 1090         struct vnode *vp = ap->a_vp;
 1091 
 1092         if (vp->v_type != VREG)
 1093                 return EISDIR;
 1094         return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred, 0));
 1095 }
 1096 
 1097 /*
 1098  * nfs readlink call
 1099  */
 1100 int
 1101 nfs_readlink(v)
 1102         void *v;
 1103 {
 1104         struct vop_readlink_args /* {
 1105                 struct vnode *a_vp;
 1106                 struct uio *a_uio;
 1107                 kauth_cred_t a_cred;
 1108         } */ *ap = v;
 1109         struct vnode *vp = ap->a_vp;
 1110         struct nfsnode *np = VTONFS(vp);
 1111 
 1112         if (vp->v_type != VLNK)
 1113                 return (EPERM);
 1114 
 1115         if (np->n_rcred != NULL) {
 1116                 kauth_cred_free(np->n_rcred);
 1117         }
 1118         np->n_rcred = ap->a_cred;
 1119         kauth_cred_hold(np->n_rcred);
 1120 
 1121         return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred, 0));
 1122 }
 1123 
 1124 /*
 1125  * Do a readlink rpc.
 1126  * Called by nfs_doio() from below the buffer cache.
 1127  */
 1128 int
 1129 nfs_readlinkrpc(vp, uiop, cred)
 1130         struct vnode *vp;
 1131         struct uio *uiop;
 1132         kauth_cred_t cred;
 1133 {
 1134         u_int32_t *tl;
 1135         char *cp;
 1136         int32_t t1, t2;
 1137         char *bpos, *dpos, *cp2;
 1138         int error = 0;
 1139         uint32_t len;
 1140         struct mbuf *mreq, *mrep, *md, *mb;
 1141         const int v3 = NFS_ISV3(vp);
 1142         struct nfsnode *np = VTONFS(vp);
 1143 #ifndef NFS_V2_ONLY
 1144         int attrflag;
 1145 #endif
 1146 
 1147         nfsstats.rpccnt[NFSPROC_READLINK]++;
 1148         nfsm_reqhead(np, NFSPROC_READLINK, NFSX_FH(v3));
 1149         nfsm_fhtom(np, v3);
 1150         nfsm_request(np, NFSPROC_READLINK, curlwp, cred);
 1151 #ifndef NFS_V2_ONLY
 1152         if (v3)
 1153                 nfsm_postop_attr(vp, attrflag, 0);
 1154 #endif
 1155         if (!error) {
 1156 #ifndef NFS_V2_ONLY
 1157                 if (v3) {
 1158                         nfsm_dissect(tl, uint32_t *, NFSX_UNSIGNED);
 1159                         len = fxdr_unsigned(uint32_t, *tl);
 1160                         if (len > MAXPATHLEN) {
 1161                                 /*
 1162                                  * this pathname is too long for us.
 1163                                  */
 1164                                 m_freem(mrep);
 1165                                 /* Solaris returns EINVAL. should we follow? */
 1166                                 error = ENAMETOOLONG;
 1167                                 goto nfsmout;
 1168                         }
 1169                 } else
 1170 #endif
 1171                 {
 1172                         nfsm_strsiz(len, NFS_MAXPATHLEN);
 1173                 }
 1174                 nfsm_mtouio(uiop, len);
 1175         }
 1176         nfsm_reqdone;
 1177         return (error);
 1178 }
 1179 
 1180 /*
 1181  * nfs read rpc call
 1182  * Ditto above
 1183  */
 1184 int
 1185 nfs_readrpc(vp, uiop)
 1186         struct vnode *vp;
 1187         struct uio *uiop;
 1188 {
 1189         u_int32_t *tl;
 1190         char *cp;
 1191         int32_t t1, t2;
 1192         char *bpos, *dpos, *cp2;
 1193         struct mbuf *mreq, *mrep, *md, *mb;
 1194         struct nfsmount *nmp;
 1195         int error = 0, len, retlen, tsiz, eof, byte_count;
 1196         const int v3 = NFS_ISV3(vp);
 1197         struct nfsnode *np = VTONFS(vp);
 1198 #ifndef NFS_V2_ONLY
 1199         int attrflag;
 1200 #endif
 1201 
 1202 #ifndef nolint
 1203         eof = 0;
 1204 #endif
 1205         nmp = VFSTONFS(vp->v_mount);
 1206         tsiz = uiop->uio_resid;
 1207         if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize)
 1208                 return (EFBIG);
 1209         iostat_busy(nmp->nm_stats);
 1210         byte_count = 0; /* count bytes actually transferred */
 1211         while (tsiz > 0) {
 1212                 nfsstats.rpccnt[NFSPROC_READ]++;
 1213                 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
 1214                 nfsm_reqhead(np, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
 1215                 nfsm_fhtom(np, v3);
 1216                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED * 3);
 1217 #ifndef NFS_V2_ONLY
 1218                 if (v3) {
 1219                         txdr_hyper(uiop->uio_offset, tl);
 1220                         *(tl + 2) = txdr_unsigned(len);
 1221                 } else
 1222 #endif
 1223                 {
 1224                         *tl++ = txdr_unsigned(uiop->uio_offset);
 1225                         *tl++ = txdr_unsigned(len);
 1226                         *tl = 0;
 1227                 }
 1228                 nfsm_request(np, NFSPROC_READ, curlwp, np->n_rcred);
 1229 #ifndef NFS_V2_ONLY
 1230                 if (v3) {
 1231                         nfsm_postop_attr(vp, attrflag, NAC_NOTRUNC);
 1232                         if (error) {
 1233                                 m_freem(mrep);
 1234                                 goto nfsmout;
 1235                         }
 1236                         nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1237                         eof = fxdr_unsigned(int, *(tl + 1));
 1238                 } else
 1239 #endif
 1240                         nfsm_loadattr(vp, (struct vattr *)0, NAC_NOTRUNC);
 1241                 nfsm_strsiz(retlen, nmp->nm_rsize);
 1242                 nfsm_mtouio(uiop, retlen);
 1243                 m_freem(mrep);
 1244                 tsiz -= retlen;
 1245                 byte_count += retlen;
 1246 #ifndef NFS_V2_ONLY
 1247                 if (v3) {
 1248                         if (eof || retlen == 0)
 1249                                 tsiz = 0;
 1250                 } else
 1251 #endif
 1252                 if (retlen < len)
 1253                         tsiz = 0;
 1254         }
 1255 nfsmout:
 1256         iostat_unbusy(nmp->nm_stats, byte_count, 1);
 1257         return (error);
 1258 }
 1259 
 1260 struct nfs_writerpc_context {
 1261         kmutex_t nwc_lock;
 1262         kcondvar_t nwc_cv;
 1263         int nwc_mbufcount;
 1264 };
 1265 
 1266 /*
 1267  * free mbuf used to refer protected pages while write rpc call.
 1268  * called at splvm.
 1269  */
 1270 static void
 1271 nfs_writerpc_extfree(struct mbuf *m, void *tbuf, size_t size, void *arg)
 1272 {
 1273         struct nfs_writerpc_context *ctx = arg;
 1274 
 1275         KASSERT(m != NULL);
 1276         KASSERT(ctx != NULL);
 1277         pool_cache_put(mb_cache, m);
 1278         mutex_enter(&ctx->nwc_lock);
 1279         if (--ctx->nwc_mbufcount == 0) {
 1280                 cv_signal(&ctx->nwc_cv);
 1281         }
 1282         mutex_exit(&ctx->nwc_lock);
 1283 }
 1284 
 1285 /*
 1286  * nfs write call
 1287  */
 1288 int
 1289 nfs_writerpc(vp, uiop, iomode, pageprotected, stalewriteverfp)
 1290         struct vnode *vp;
 1291         struct uio *uiop;
 1292         int *iomode;
 1293         bool pageprotected;
 1294         bool *stalewriteverfp;
 1295 {
 1296         u_int32_t *tl;
 1297         char *cp;
 1298         int32_t t1, t2;
 1299         char *bpos, *dpos;
 1300         struct mbuf *mreq, *mrep, *md, *mb;
 1301         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 1302         int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR;
 1303         const int v3 = NFS_ISV3(vp);
 1304         int committed = NFSV3WRITE_FILESYNC;
 1305         struct nfsnode *np = VTONFS(vp);
 1306         struct nfs_writerpc_context ctx;
 1307         int byte_count;
 1308         struct lwp *l = NULL;
 1309         size_t origresid;
 1310 #ifndef NFS_V2_ONLY
 1311         char *cp2;
 1312         int rlen, commit;
 1313 #endif
 1314 
 1315         mutex_init(&ctx.nwc_lock, MUTEX_DRIVER, IPL_VM);
 1316         cv_init(&ctx.nwc_cv, "nfsmblk");
 1317         ctx.nwc_mbufcount = 1;
 1318 
 1319         if (vp->v_mount->mnt_flag & MNT_RDONLY) {
 1320                 panic("writerpc readonly vp %p", vp);
 1321         }
 1322 
 1323 #ifdef DIAGNOSTIC
 1324         if (uiop->uio_iovcnt != 1)
 1325                 panic("nfs: writerpc iovcnt > 1");
 1326 #endif
 1327         tsiz = uiop->uio_resid;
 1328         if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize)
 1329                 return (EFBIG);
 1330         if (pageprotected) {
 1331                 l = curlwp;
 1332                 uvm_lwp_hold(l);
 1333         }
 1334 retry:
 1335         origresid = uiop->uio_resid;
 1336         KASSERT(origresid == uiop->uio_iov->iov_len);
 1337         iostat_busy(nmp->nm_stats);
 1338         byte_count = 0; /* count of bytes actually written */
 1339         while (tsiz > 0) {
 1340                 uint32_t datalen; /* data bytes need to be allocated in mbuf */
 1341                 uint32_t backup;
 1342                 bool stalewriteverf = false;
 1343 
 1344                 nfsstats.rpccnt[NFSPROC_WRITE]++;
 1345                 len = min(tsiz, nmp->nm_wsize);
 1346                 datalen = pageprotected ? 0 : nfsm_rndup(len);
 1347                 nfsm_reqhead(np, NFSPROC_WRITE,
 1348                         NFSX_FH(v3) + 5 * NFSX_UNSIGNED + datalen);
 1349                 nfsm_fhtom(np, v3);
 1350 #ifndef NFS_V2_ONLY
 1351                 if (v3) {
 1352                         nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1353                         txdr_hyper(uiop->uio_offset, tl);
 1354                         tl += 2;
 1355                         *tl++ = txdr_unsigned(len);
 1356                         *tl++ = txdr_unsigned(*iomode);
 1357                         *tl = txdr_unsigned(len);
 1358                 } else
 1359 #endif
 1360                 {
 1361                         u_int32_t x;
 1362 
 1363                         nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1364                         /* Set both "begin" and "current" to non-garbage. */
 1365                         x = txdr_unsigned((u_int32_t)uiop->uio_offset);
 1366                         *tl++ = x;      /* "begin offset" */
 1367                         *tl++ = x;      /* "current offset" */
 1368                         x = txdr_unsigned(len);
 1369                         *tl++ = x;      /* total to this offset */
 1370                         *tl = x;        /* size of this write */
 1371 
 1372                 }
 1373                 if (pageprotected) {
 1374                         /*
 1375                          * since we know pages can't be modified during i/o,
 1376                          * no need to copy them for us.
 1377                          */
 1378                         struct mbuf *m;
 1379                         struct iovec *iovp = uiop->uio_iov;
 1380 
 1381                         m = m_get(M_WAIT, MT_DATA);
 1382                         MCLAIM(m, &nfs_mowner);
 1383                         MEXTADD(m, iovp->iov_base, len, M_MBUF,
 1384                             nfs_writerpc_extfree, &ctx);
 1385                         m->m_flags |= M_EXT_ROMAP;
 1386                         m->m_len = len;
 1387                         mb->m_next = m;
 1388                         /*
 1389                          * no need to maintain mb and bpos here
 1390                          * because no one care them later.
 1391                          */
 1392 #if 0
 1393                         mb = m;
 1394                         bpos = mtod(void *, mb) + mb->m_len;
 1395 #endif
 1396                         UIO_ADVANCE(uiop, len);
 1397                         uiop->uio_offset += len;
 1398                         mutex_enter(&ctx.nwc_lock);
 1399                         ctx.nwc_mbufcount++;
 1400                         mutex_exit(&ctx.nwc_lock);
 1401                         nfs_zeropad(mb, 0, nfsm_padlen(len));
 1402                 } else {
 1403                         nfsm_uiotom(uiop, len);
 1404                 }
 1405                 nfsm_request(np, NFSPROC_WRITE, curlwp, np->n_wcred);
 1406 #ifndef NFS_V2_ONLY
 1407                 if (v3) {
 1408                         wccflag = NFSV3_WCCCHK;
 1409                         nfsm_wcc_data(vp, wccflag, NAC_NOTRUNC, !error);
 1410                         if (!error) {
 1411                                 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED
 1412                                         + NFSX_V3WRITEVERF);
 1413                                 rlen = fxdr_unsigned(int, *tl++);
 1414                                 if (rlen == 0) {
 1415                                         error = NFSERR_IO;
 1416                                         m_freem(mrep);
 1417                                         break;
 1418                                 } else if (rlen < len) {
 1419                                         backup = len - rlen;
 1420                                         UIO_ADVANCE(uiop, -backup);
 1421                                         uiop->uio_offset -= backup;
 1422                                         len = rlen;
 1423                                 }
 1424                                 commit = fxdr_unsigned(int, *tl++);
 1425 
 1426                                 /*
 1427                                  * Return the lowest committment level
 1428                                  * obtained by any of the RPCs.
 1429                                  */
 1430                                 if (committed == NFSV3WRITE_FILESYNC)
 1431                                         committed = commit;
 1432                                 else if (committed == NFSV3WRITE_DATASYNC &&
 1433                                         commit == NFSV3WRITE_UNSTABLE)
 1434                                         committed = commit;
 1435                                 mutex_enter(&nmp->nm_lock);
 1436                                 if ((nmp->nm_iflag & NFSMNT_HASWRITEVERF) == 0){
 1437                                         memcpy(nmp->nm_writeverf, tl,
 1438                                             NFSX_V3WRITEVERF);
 1439                                         nmp->nm_iflag |= NFSMNT_HASWRITEVERF;
 1440                                 } else if ((nmp->nm_iflag &
 1441                                     NFSMNT_STALEWRITEVERF) ||
 1442                                     memcmp(tl, nmp->nm_writeverf,
 1443                                     NFSX_V3WRITEVERF)) {
 1444                                         memcpy(nmp->nm_writeverf, tl,
 1445                                             NFSX_V3WRITEVERF);
 1446                                         /*
 1447                                          * note NFSMNT_STALEWRITEVERF
 1448                                          * if we're the first thread to
 1449                                          * notice it.
 1450                                          */
 1451                                         if ((nmp->nm_iflag &
 1452                                             NFSMNT_STALEWRITEVERF) == 0) {
 1453                                                 stalewriteverf = true;
 1454                                                 nmp->nm_iflag |=
 1455                                                     NFSMNT_STALEWRITEVERF;
 1456                                         }
 1457                                 }
 1458                                 mutex_exit(&nmp->nm_lock);
 1459                         }
 1460                 } else
 1461 #endif
 1462                         nfsm_loadattr(vp, (struct vattr *)0, NAC_NOTRUNC);
 1463                 if (wccflag)
 1464                         VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr->va_mtime;
 1465                 m_freem(mrep);
 1466                 if (error)
 1467                         break;
 1468                 tsiz -= len;
 1469                 byte_count += len;
 1470                 if (stalewriteverf) {
 1471                         *stalewriteverfp = true;
 1472                         stalewriteverf = false;
 1473                         if (committed == NFSV3WRITE_UNSTABLE &&
 1474                             len != origresid) {
 1475                                 /*
 1476                                  * if our write requests weren't atomic but
 1477                                  * unstable, datas in previous iterations
 1478                                  * might have already been lost now.
 1479                                  * then, we should resend them to nfsd.
 1480                                  */
 1481                                 backup = origresid - tsiz;
 1482                                 UIO_ADVANCE(uiop, -backup);
 1483                                 uiop->uio_offset -= backup;
 1484                                 tsiz = origresid;
 1485                                 goto retry;
 1486                         }
 1487                 }
 1488         }
 1489 nfsmout:
 1490         iostat_unbusy(nmp->nm_stats, byte_count, 0);
 1491         if (pageprotected) {
 1492                 /*
 1493                  * wait until mbufs go away.
 1494                  * retransmitted mbufs can survive longer than rpc requests
 1495                  * themselves.
 1496                  */
 1497                 mutex_enter(&ctx.nwc_lock);
 1498                 ctx.nwc_mbufcount--;
 1499                 while (ctx.nwc_mbufcount > 0) {
 1500                         cv_wait(&ctx.nwc_cv, &ctx.nwc_lock);
 1501                 }
 1502                 mutex_exit(&ctx.nwc_lock);
 1503                 uvm_lwp_rele(l);
 1504         }
 1505         mutex_destroy(&ctx.nwc_lock);
 1506         cv_destroy(&ctx.nwc_cv);
 1507         *iomode = committed;
 1508         if (error)
 1509                 uiop->uio_resid = tsiz;
 1510         return (error);
 1511 }
 1512 
 1513 /*
 1514  * nfs mknod rpc
 1515  * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
 1516  * mode set to specify the file type and the size field for rdev.
 1517  */
 1518 int
 1519 nfs_mknodrpc(dvp, vpp, cnp, vap)
 1520         struct vnode *dvp;
 1521         struct vnode **vpp;
 1522         struct componentname *cnp;
 1523         struct vattr *vap;
 1524 {
 1525         struct nfsv2_sattr *sp;
 1526         u_int32_t *tl;
 1527         char *cp;
 1528         int32_t t1, t2;
 1529         struct vnode *newvp = (struct vnode *)0;
 1530         struct nfsnode *dnp, *np;
 1531         char *cp2;
 1532         char *bpos, *dpos;
 1533         int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
 1534         struct mbuf *mreq, *mrep, *md, *mb;
 1535         u_int32_t rdev;
 1536         const int v3 = NFS_ISV3(dvp);
 1537 
 1538         if (vap->va_type == VCHR || vap->va_type == VBLK)
 1539                 rdev = txdr_unsigned(vap->va_rdev);
 1540         else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
 1541                 rdev = nfs_xdrneg1;
 1542         else {
 1543                 VOP_ABORTOP(dvp, cnp);
 1544                 vput(dvp);
 1545                 return (EOPNOTSUPP);
 1546         }
 1547         nfsstats.rpccnt[NFSPROC_MKNOD]++;
 1548         dnp = VTONFS(dvp);
 1549         nfsm_reqhead(dnp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
 1550                 + nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
 1551         nfsm_fhtom(dnp, v3);
 1552         nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
 1553 #ifndef NFS_V2_ONLY
 1554         if (v3) {
 1555                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
 1556                 *tl++ = vtonfsv3_type(vap->va_type);
 1557                 nfsm_v3attrbuild(vap, false);
 1558                 if (vap->va_type == VCHR || vap->va_type == VBLK) {
 1559                         nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1560                         *tl++ = txdr_unsigned(major(vap->va_rdev));
 1561                         *tl = txdr_unsigned(minor(vap->va_rdev));
 1562                 }
 1563         } else
 1564 #endif
 1565         {
 1566                 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
 1567                 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
 1568                 sp->sa_uid = nfs_xdrneg1;
 1569                 sp->sa_gid = nfs_xdrneg1;
 1570                 sp->sa_size = rdev;
 1571                 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
 1572                 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
 1573         }
 1574         nfsm_request(dnp, NFSPROC_MKNOD, curlwp, cnp->cn_cred);
 1575         if (!error) {
 1576                 nfsm_mtofh(dvp, newvp, v3, gotvp);
 1577                 if (!gotvp) {
 1578                         error = nfs_lookitup(dvp, cnp->cn_nameptr,
 1579                             cnp->cn_namelen, cnp->cn_cred, curlwp, &np);
 1580                         if (!error)
 1581                                 newvp = NFSTOV(np);
 1582                 }
 1583         }
 1584 #ifndef NFS_V2_ONLY
 1585         if (v3)
 1586                 nfsm_wcc_data(dvp, wccflag, 0, !error);
 1587 #endif
 1588         nfsm_reqdone;
 1589         if (error) {
 1590                 if (newvp)
 1591                         vput(newvp);
 1592         } else {
 1593                 if (cnp->cn_flags & MAKEENTRY)
 1594                         nfs_cache_enter(dvp, newvp, cnp);
 1595                 *vpp = newvp;
 1596         }
 1597         PNBUF_PUT(cnp->cn_pnbuf);
 1598         VTONFS(dvp)->n_flag |= NMODIFIED;
 1599         if (!wccflag)
 1600                 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp));
 1601         vput(dvp);
 1602         return (error);
 1603 }
 1604 
 1605 /*
 1606  * nfs mknod vop
 1607  * just call nfs_mknodrpc() to do the work.
 1608  */
 1609 /* ARGSUSED */
 1610 int
 1611 nfs_mknod(v)
 1612         void *v;
 1613 {
 1614         struct vop_mknod_args /* {
 1615                 struct vnode *a_dvp;
 1616                 struct vnode **a_vpp;
 1617                 struct componentname *a_cnp;
 1618                 struct vattr *a_vap;
 1619         } */ *ap = v;
 1620         struct vnode *dvp = ap->a_dvp;
 1621         struct componentname *cnp = ap->a_cnp;
 1622         int error;
 1623 
 1624         error = nfs_mknodrpc(dvp, ap->a_vpp, cnp, ap->a_vap);
 1625         VN_KNOTE(dvp, NOTE_WRITE);
 1626         if (error == 0 || error == EEXIST)
 1627                 cache_purge1(dvp, cnp, 0);
 1628         return (error);
 1629 }
 1630 
 1631 /*
 1632  * nfs file create call
 1633  */
 1634 int
 1635 nfs_create(v)
 1636         void *v;
 1637 {
 1638         struct vop_create_args /* {
 1639                 struct vnode *a_dvp;
 1640                 struct vnode **a_vpp;
 1641                 struct componentname *a_cnp;
 1642                 struct vattr *a_vap;
 1643         } */ *ap = v;
 1644         struct vnode *dvp = ap->a_dvp;
 1645         struct vattr *vap = ap->a_vap;
 1646         struct componentname *cnp = ap->a_cnp;
 1647         struct nfsv2_sattr *sp;
 1648         u_int32_t *tl;
 1649         char *cp;
 1650         int32_t t1, t2;
 1651         struct nfsnode *dnp, *np = (struct nfsnode *)0;
 1652         struct vnode *newvp = (struct vnode *)0;
 1653         char *bpos, *dpos, *cp2;
 1654         int error, wccflag = NFSV3_WCCRATTR, gotvp = 0;
 1655         struct mbuf *mreq, *mrep, *md, *mb;
 1656         const int v3 = NFS_ISV3(dvp);
 1657         u_int32_t excl_mode = NFSV3CREATE_UNCHECKED;
 1658 
 1659         /*
 1660          * Oops, not for me..
 1661          */
 1662         if (vap->va_type == VSOCK)
 1663                 return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
 1664 
 1665         KASSERT(vap->va_type == VREG);
 1666 
 1667 #ifdef VA_EXCLUSIVE
 1668         if (vap->va_vaflags & VA_EXCLUSIVE) {
 1669                 excl_mode = NFSV3CREATE_EXCLUSIVE;
 1670         }
 1671 #endif
 1672 again:
 1673         error = 0;
 1674         nfsstats.rpccnt[NFSPROC_CREATE]++;
 1675         dnp = VTONFS(dvp);
 1676         nfsm_reqhead(dnp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
 1677                 nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
 1678         nfsm_fhtom(dnp, v3);
 1679         nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
 1680 #ifndef NFS_V2_ONLY
 1681         if (v3) {
 1682                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
 1683                 if (excl_mode == NFSV3CREATE_EXCLUSIVE) {
 1684                         *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE);
 1685                         nfsm_build(tl, u_int32_t *, NFSX_V3CREATEVERF);
 1686                         *tl++ = arc4random();
 1687                         *tl = arc4random();
 1688                 } else {
 1689                         *tl = txdr_unsigned(excl_mode);
 1690                         nfsm_v3attrbuild(vap, false);
 1691                 }
 1692         } else
 1693 #endif
 1694         {
 1695                 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
 1696                 sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
 1697                 sp->sa_uid = nfs_xdrneg1;
 1698                 sp->sa_gid = nfs_xdrneg1;
 1699                 sp->sa_size = 0;
 1700                 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
 1701                 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
 1702         }
 1703         nfsm_request(dnp, NFSPROC_CREATE, curlwp, cnp->cn_cred);
 1704         if (!error) {
 1705                 nfsm_mtofh(dvp, newvp, v3, gotvp);
 1706                 if (!gotvp) {
 1707                         error = nfs_lookitup(dvp, cnp->cn_nameptr,
 1708                             cnp->cn_namelen, cnp->cn_cred, curlwp, &np);
 1709                         if (!error)
 1710                                 newvp = NFSTOV(np);
 1711                 }
 1712         }
 1713 #ifndef NFS_V2_ONLY
 1714         if (v3)
 1715                 nfsm_wcc_data(dvp, wccflag, 0, !error);
 1716 #endif
 1717         nfsm_reqdone;
 1718         if (error) {
 1719                 /*
 1720                  * nfs_request maps NFSERR_NOTSUPP to ENOTSUP.
 1721                  */
 1722                 if (v3 && error == ENOTSUP) {
 1723                         if (excl_mode == NFSV3CREATE_EXCLUSIVE) {
 1724                                 excl_mode = NFSV3CREATE_GUARDED;
 1725                                 goto again;
 1726                         } else if (excl_mode == NFSV3CREATE_GUARDED) {
 1727                                 excl_mode = NFSV3CREATE_UNCHECKED;
 1728                                 goto again;
 1729                         }
 1730                 }
 1731         } else if (v3 && (excl_mode == NFSV3CREATE_EXCLUSIVE)) {
 1732                 struct timespec ts;
 1733 
 1734                 getnanotime(&ts);
 1735 
 1736                 /*
 1737                  * make sure that we'll update timestamps as
 1738                  * most server implementations use them to store
 1739                  * the create verifier.
 1740                  *
 1741                  * XXX it's better to use TOSERVER always.
 1742                  */
 1743 
 1744                 if (vap->va_atime.tv_sec == VNOVAL)
 1745                         vap->va_atime = ts;
 1746                 if (vap->va_mtime.tv_sec == VNOVAL)
 1747                         vap->va_mtime = ts;
 1748 
 1749                 error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, curlwp);
 1750         }
 1751         if (error == 0) {
 1752                 if (cnp->cn_flags & MAKEENTRY)
 1753                         nfs_cache_enter(dvp, newvp, cnp);
 1754                 else
 1755                         cache_purge1(dvp, cnp, 0);
 1756                 *ap->a_vpp = newvp;
 1757         } else {
 1758                 if (newvp)
 1759                         vput(newvp);
 1760                 if (error == EEXIST)
 1761                         cache_purge1(dvp, cnp, 0);
 1762         }
 1763         PNBUF_PUT(cnp->cn_pnbuf);
 1764         VTONFS(dvp)->n_flag |= NMODIFIED;
 1765         if (!wccflag)
 1766                 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp));
 1767         VN_KNOTE(ap->a_dvp, NOTE_WRITE);
 1768         vput(dvp);
 1769         return (error);
 1770 }
 1771 
 1772 /*
 1773  * nfs file remove call
 1774  * To try and make nfs semantics closer to ufs semantics, a file that has
 1775  * other processes using the vnode is renamed instead of removed and then
 1776  * removed later on the last close.
 1777  * - If v_usecount > 1
 1778  *        If a rename is not already in the works
 1779  *           call nfs_sillyrename() to set it up
 1780  *     else
 1781  *        do the remove rpc
 1782  */
 1783 int
 1784 nfs_remove(v)
 1785         void *v;
 1786 {
 1787         struct vop_remove_args /* {
 1788                 struct vnodeop_desc *a_desc;
 1789                 struct vnode * a_dvp;
 1790                 struct vnode * a_vp;
 1791                 struct componentname * a_cnp;
 1792         } */ *ap = v;
 1793         struct vnode *vp = ap->a_vp;
 1794         struct vnode *dvp = ap->a_dvp;
 1795         struct componentname *cnp = ap->a_cnp;
 1796         struct nfsnode *np = VTONFS(vp);
 1797         int error = 0;
 1798         struct vattr vattr;
 1799 
 1800 #ifndef DIAGNOSTIC
 1801         if ((cnp->cn_flags & HASBUF) == 0)
 1802                 panic("nfs_remove: no name");
 1803         if (vp->v_usecount < 1)
 1804                 panic("nfs_remove: bad v_usecount");
 1805 #endif
 1806         if (vp->v_type == VDIR)
 1807                 error = EPERM;
 1808         else if (vp->v_usecount == 1 || (np->n_sillyrename &&
 1809             VOP_GETATTR(vp, &vattr, cnp->cn_cred) == 0 &&
 1810             vattr.va_nlink > 1)) {
 1811                 /*
 1812                  * Purge the name cache so that the chance of a lookup for
 1813                  * the name succeeding while the remove is in progress is
 1814                  * minimized. Without node locking it can still happen, such
 1815                  * that an I/O op returns ESTALE, but since you get this if
 1816                  * another host removes the file..
 1817                  */
 1818                 cache_purge(vp);
 1819                 /*
 1820                  * throw away biocache buffers, mainly to avoid
 1821                  * unnecessary delayed writes later.
 1822                  */
 1823                 error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, curlwp, 1);
 1824                 /* Do the rpc */
 1825                 if (error != EINTR)
 1826                         error = nfs_removerpc(dvp, cnp->cn_nameptr,
 1827                                 cnp->cn_namelen, cnp->cn_cred, curlwp);
 1828         } else if (!np->n_sillyrename)
 1829                 error = nfs_sillyrename(dvp, vp, cnp, false);
 1830         PNBUF_PUT(cnp->cn_pnbuf);
 1831         if (!error && nfs_getattrcache(vp, &vattr) == 0 &&
 1832             vattr.va_nlink == 1) {
 1833                 np->n_flag |= NREMOVED;
 1834         }
 1835         NFS_INVALIDATE_ATTRCACHE(np);
 1836         VN_KNOTE(vp, NOTE_DELETE);
 1837         VN_KNOTE(dvp, NOTE_WRITE);
 1838         if (dvp == vp)
 1839                 vrele(vp);
 1840         else
 1841                 vput(vp);
 1842         vput(dvp);
 1843         return (error);
 1844 }
 1845 
 1846 /*
 1847  * nfs file remove rpc called from nfs_inactive
 1848  */
 1849 int
 1850 nfs_removeit(sp)
 1851         struct sillyrename *sp;
 1852 {
 1853 
 1854         return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
 1855                 (struct lwp *)0));
 1856 }
 1857 
 1858 /*
 1859  * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
 1860  */
 1861 int
 1862 nfs_removerpc(dvp, name, namelen, cred, l)
 1863         struct vnode *dvp;
 1864         const char *name;
 1865         int namelen;
 1866         kauth_cred_t cred;
 1867         struct lwp *l;
 1868 {
 1869         u_int32_t *tl;
 1870         char *cp;
 1871 #ifndef NFS_V2_ONLY
 1872         int32_t t1;
 1873         char *cp2;
 1874 #endif
 1875         int32_t t2;
 1876         char *bpos, *dpos;
 1877         int error = 0, wccflag = NFSV3_WCCRATTR;
 1878         struct mbuf *mreq, *mrep, *md, *mb;
 1879         const int v3 = NFS_ISV3(dvp);
 1880         int rexmit = 0;
 1881         struct nfsnode *dnp = VTONFS(dvp);
 1882 
 1883         nfsstats.rpccnt[NFSPROC_REMOVE]++;
 1884         nfsm_reqhead(dnp, NFSPROC_REMOVE,
 1885                 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
 1886         nfsm_fhtom(dnp, v3);
 1887         nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
 1888         nfsm_request1(dnp, NFSPROC_REMOVE, l, cred, &rexmit);
 1889 #ifndef NFS_V2_ONLY
 1890         if (v3)
 1891                 nfsm_wcc_data(dvp, wccflag, 0, !error);
 1892 #endif
 1893         nfsm_reqdone;
 1894         VTONFS(dvp)->n_flag |= NMODIFIED;
 1895         if (!wccflag)
 1896                 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp));
 1897         /*
 1898          * Kludge City: If the first reply to the remove rpc is lost..
 1899          *   the reply to the retransmitted request will be ENOENT
 1900          *   since the file was in fact removed
 1901          *   Therefore, we cheat and return success.
 1902          */
 1903         if (rexmit && error == ENOENT)
 1904                 error = 0;
 1905         return (error);
 1906 }
 1907 
 1908 /*
 1909  * nfs file rename call
 1910  */
 1911 int
 1912 nfs_rename(v)
 1913         void *v;
 1914 {
 1915         struct vop_rename_args  /* {
 1916                 struct vnode *a_fdvp;
 1917                 struct vnode *a_fvp;
 1918                 struct componentname *a_fcnp;
 1919                 struct vnode *a_tdvp;
 1920                 struct vnode *a_tvp;
 1921                 struct componentname *a_tcnp;
 1922         } */ *ap = v;
 1923         struct vnode *fvp = ap->a_fvp;
 1924         struct vnode *tvp = ap->a_tvp;
 1925         struct vnode *fdvp = ap->a_fdvp;
 1926         struct vnode *tdvp = ap->a_tdvp;
 1927         struct componentname *tcnp = ap->a_tcnp;
 1928         struct componentname *fcnp = ap->a_fcnp;
 1929         int error;
 1930 
 1931 #ifndef DIAGNOSTIC
 1932         if ((tcnp->cn_flags & HASBUF) == 0 ||
 1933             (fcnp->cn_flags & HASBUF) == 0)
 1934                 panic("nfs_rename: no name");
 1935 #endif
 1936         /* Check for cross-device rename */
 1937         if ((fvp->v_mount != tdvp->v_mount) ||
 1938             (tvp && (fvp->v_mount != tvp->v_mount))) {
 1939                 error = EXDEV;
 1940                 goto out;
 1941         }
 1942 
 1943         /*
 1944          * If the tvp exists and is in use, sillyrename it before doing the
 1945          * rename of the new file over it.
 1946          *
 1947          * Have sillyrename use link instead of rename if possible,
 1948          * so that we don't lose the file if the rename fails, and so
 1949          * that there's no window when the "to" file doesn't exist.
 1950          */
 1951         if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
 1952             tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp, true)) {
 1953                 VN_KNOTE(tvp, NOTE_DELETE);
 1954                 vput(tvp);
 1955                 tvp = NULL;
 1956         }
 1957 
 1958         error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
 1959                 tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
 1960                 curlwp);
 1961 
 1962         VN_KNOTE(fdvp, NOTE_WRITE);
 1963         VN_KNOTE(tdvp, NOTE_WRITE);
 1964         if (error == 0 || error == EEXIST) {
 1965                 if (fvp->v_type == VDIR)
 1966                         cache_purge(fvp);
 1967                 else
 1968                         cache_purge1(fdvp, fcnp, 0);
 1969                 if (tvp != NULL && tvp->v_type == VDIR)
 1970                         cache_purge(tvp);
 1971                 else
 1972                         cache_purge1(tdvp, tcnp, 0);
 1973         }
 1974 out:
 1975         if (tdvp == tvp)
 1976                 vrele(tdvp);
 1977         else
 1978                 vput(tdvp);
 1979         if (tvp)
 1980                 vput(tvp);
 1981         vrele(fdvp);
 1982         vrele(fvp);
 1983         return (error);
 1984 }
 1985 
 1986 /*
 1987  * nfs file rename rpc called from nfs_remove() above
 1988  */
 1989 int
 1990 nfs_renameit(sdvp, scnp, sp)
 1991         struct vnode *sdvp;
 1992         struct componentname *scnp;
 1993         struct sillyrename *sp;
 1994 {
 1995         return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
 1996                 sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, curlwp));
 1997 }
 1998 
 1999 /*
 2000  * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
 2001  */
 2002 int
 2003 nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, l)
 2004         struct vnode *fdvp;
 2005         const char *fnameptr;
 2006         int fnamelen;
 2007         struct vnode *tdvp;
 2008         const char *tnameptr;
 2009         int tnamelen;
 2010         kauth_cred_t cred;
 2011         struct lwp *l;
 2012 {
 2013         u_int32_t *tl;
 2014         char *cp;
 2015 #ifndef NFS_V2_ONLY
 2016         int32_t t1;
 2017         char *cp2;
 2018 #endif
 2019         int32_t t2;
 2020         char *bpos, *dpos;
 2021         int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
 2022         struct mbuf *mreq, *mrep, *md, *mb;
 2023         const int v3 = NFS_ISV3(fdvp);
 2024         int rexmit = 0;
 2025         struct nfsnode *fdnp = VTONFS(fdvp);
 2026 
 2027         nfsstats.rpccnt[NFSPROC_RENAME]++;
 2028         nfsm_reqhead(fdnp, NFSPROC_RENAME,
 2029                 (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
 2030                 nfsm_rndup(tnamelen));
 2031         nfsm_fhtom(fdnp, v3);
 2032         nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
 2033         nfsm_fhtom(VTONFS(tdvp), v3);
 2034         nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
 2035         nfsm_request1(fdnp, NFSPROC_RENAME, l, cred, &rexmit);
 2036 #ifndef NFS_V2_ONLY
 2037         if (v3) {
 2038                 nfsm_wcc_data(fdvp, fwccflag, 0, !error);
 2039                 nfsm_wcc_data(tdvp, twccflag, 0, !error);
 2040         }
 2041 #endif
 2042         nfsm_reqdone;
 2043         VTONFS(fdvp)->n_flag |= NMODIFIED;
 2044         VTONFS(tdvp)->n_flag |= NMODIFIED;
 2045         if (!fwccflag)
 2046                 NFS_INVALIDATE_ATTRCACHE(VTONFS(fdvp));
 2047         if (!twccflag)
 2048                 NFS_INVALIDATE_ATTRCACHE(VTONFS(tdvp));
 2049         /*
 2050          * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
 2051          */
 2052         if (rexmit && error == ENOENT)
 2053                 error = 0;
 2054         return (error);
 2055 }
 2056 
 2057 /*
 2058  * NFS link RPC, called from nfs_link.
 2059  * Assumes dvp and vp locked, and leaves them that way.
 2060  */
 2061 
 2062 static int
 2063 nfs_linkrpc(struct vnode *dvp, struct vnode *vp, const char *name,
 2064     size_t namelen, kauth_cred_t cred, struct lwp *l)
 2065 {
 2066         u_int32_t *tl;
 2067         char *cp;
 2068 #ifndef NFS_V2_ONLY
 2069         int32_t t1;
 2070         char *cp2;
 2071 #endif
 2072         int32_t t2;
 2073         char *bpos, *dpos;
 2074         int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
 2075         struct mbuf *mreq, *mrep, *md, *mb;
 2076         const int v3 = NFS_ISV3(dvp);
 2077         int rexmit = 0;
 2078         struct nfsnode *np = VTONFS(vp);
 2079 
 2080         nfsstats.rpccnt[NFSPROC_LINK]++;
 2081         nfsm_reqhead(np, NFSPROC_LINK,
 2082             NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(namelen));
 2083         nfsm_fhtom(np, v3);
 2084         nfsm_fhtom(VTONFS(dvp), v3);
 2085         nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
 2086         nfsm_request1(np, NFSPROC_LINK, l, cred, &rexmit);
 2087 #ifndef NFS_V2_ONLY
 2088         if (v3) {
 2089                 nfsm_postop_attr(vp, attrflag, 0);
 2090                 nfsm_wcc_data(dvp, wccflag, 0, !error);
 2091         }
 2092 #endif
 2093         nfsm_reqdone;
 2094 
 2095         VTONFS(dvp)->n_flag |= NMODIFIED;
 2096         if (!attrflag)
 2097                 NFS_INVALIDATE_ATTRCACHE(VTONFS(vp));
 2098         if (!wccflag)
 2099                 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp));
 2100 
 2101         /*
 2102          * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
 2103          */
 2104         if (rexmit && error == EEXIST)
 2105                 error = 0;
 2106 
 2107         return error;
 2108 }
 2109 
 2110 /*
 2111  * nfs hard link create call
 2112  */
 2113 int
 2114 nfs_link(v)
 2115         void *v;
 2116 {
 2117         struct vop_link_args /* {
 2118                 struct vnode *a_dvp;
 2119                 struct vnode *a_vp;
 2120                 struct componentname *a_cnp;
 2121         } */ *ap = v;
 2122         struct vnode *vp = ap->a_vp;
 2123         struct vnode *dvp = ap->a_dvp;
 2124         struct componentname *cnp = ap->a_cnp;
 2125         int error = 0;
 2126 
 2127         if (dvp->v_mount != vp->v_mount) {
 2128                 VOP_ABORTOP(dvp, cnp);
 2129                 vput(dvp);
 2130                 return (EXDEV);
 2131         }
 2132         if (dvp != vp) {
 2133                 error = vn_lock(vp, LK_EXCLUSIVE);
 2134                 if (error != 0) {
 2135                         VOP_ABORTOP(dvp, cnp);
 2136                         vput(dvp);
 2137                         return error;
 2138                 }
 2139         }
 2140 
 2141         /*
 2142          * Push all writes to the server, so that the attribute cache
 2143          * doesn't get "out of sync" with the server.
 2144          * XXX There should be a better way!
 2145          */
 2146         VOP_FSYNC(vp, cnp->cn_cred, FSYNC_WAIT, 0, 0);
 2147 
 2148         error = nfs_linkrpc(dvp, vp, cnp->cn_nameptr, cnp->cn_namelen,
 2149             cnp->cn_cred, curlwp);
 2150 
 2151         if (error == 0)
 2152                 cache_purge1(dvp, cnp, 0);
 2153         PNBUF_PUT(cnp->cn_pnbuf);
 2154         if (dvp != vp)
 2155                 VOP_UNLOCK(vp, 0);
 2156         VN_KNOTE(vp, NOTE_LINK);
 2157         VN_KNOTE(dvp, NOTE_WRITE);
 2158         vput(dvp);
 2159         return (error);
 2160 }
 2161 
 2162 /*
 2163  * nfs symbolic link create call
 2164  */
 2165 int
 2166 nfs_symlink(v)
 2167         void *v;
 2168 {
 2169         struct vop_symlink_args /* {
 2170                 struct vnode *a_dvp;
 2171                 struct vnode **a_vpp;
 2172                 struct componentname *a_cnp;
 2173                 struct vattr *a_vap;
 2174                 char *a_target;
 2175         } */ *ap = v;
 2176         struct vnode *dvp = ap->a_dvp;
 2177         struct vattr *vap = ap->a_vap;
 2178         struct componentname *cnp = ap->a_cnp;
 2179         struct nfsv2_sattr *sp;
 2180         u_int32_t *tl;
 2181         char *cp;
 2182         int32_t t1, t2;
 2183         char *bpos, *dpos, *cp2;
 2184         int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
 2185         struct mbuf *mreq, *mrep, *md, *mb;
 2186         struct vnode *newvp = (struct vnode *)0;
 2187         const int v3 = NFS_ISV3(dvp);
 2188         int rexmit = 0;
 2189         struct nfsnode *dnp = VTONFS(dvp);
 2190 
 2191         *ap->a_vpp = NULL;
 2192         nfsstats.rpccnt[NFSPROC_SYMLINK]++;
 2193         slen = strlen(ap->a_target);
 2194         nfsm_reqhead(dnp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
 2195             nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
 2196         nfsm_fhtom(dnp, v3);
 2197         nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
 2198 #ifndef NFS_V2_ONlY
 2199         if (v3)
 2200                 nfsm_v3attrbuild(vap, false);
 2201 #endif
 2202         nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
 2203 #ifndef NFS_V2_ONlY
 2204         if (!v3) {
 2205                 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
 2206                 sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
 2207                 sp->sa_uid = nfs_xdrneg1;
 2208                 sp->sa_gid = nfs_xdrneg1;
 2209                 sp->sa_size = nfs_xdrneg1;
 2210                 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
 2211                 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
 2212         }
 2213 #endif
 2214         nfsm_request1(dnp, NFSPROC_SYMLINK, curlwp, cnp->cn_cred,
 2215             &rexmit);
 2216 #ifndef NFS_V2_ONlY
 2217         if (v3) {
 2218                 if (!error)
 2219                         nfsm_mtofh(dvp, newvp, v3, gotvp);
 2220                 nfsm_wcc_data(dvp, wccflag, 0, !error);
 2221         }
 2222 #endif
 2223         nfsm_reqdone;
 2224         /*
 2225          * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
 2226          */
 2227         if (rexmit && error == EEXIST)
 2228                 error = 0;
 2229         if (error == 0 || error == EEXIST)
 2230                 cache_purge1(dvp, cnp, 0);
 2231         if (error == 0 && newvp == NULL) {
 2232                 struct nfsnode *np = NULL;
 2233 
 2234                 error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
 2235                     cnp->cn_cred, curlwp, &np);
 2236                 if (error == 0)
 2237                         newvp = NFSTOV(np);
 2238         }
 2239         if (error) {
 2240                 if (newvp != NULL)
 2241                         vput(newvp);
 2242         } else {
 2243                 *ap->a_vpp = newvp;
 2244         }
 2245         PNBUF_PUT(cnp->cn_pnbuf);
 2246         VTONFS(dvp)->n_flag |= NMODIFIED;
 2247         if (!wccflag)
 2248                 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp));
 2249         VN_KNOTE(dvp, NOTE_WRITE);
 2250         vput(dvp);
 2251         return (error);
 2252 }
 2253 
 2254 /*
 2255  * nfs make dir call
 2256  */
 2257 int
 2258 nfs_mkdir(v)
 2259         void *v;
 2260 {
 2261         struct vop_mkdir_args /* {
 2262                 struct vnode *a_dvp;
 2263                 struct vnode **a_vpp;
 2264                 struct componentname *a_cnp;
 2265                 struct vattr *a_vap;
 2266         } */ *ap = v;
 2267         struct vnode *dvp = ap->a_dvp;
 2268         struct vattr *vap = ap->a_vap;
 2269         struct componentname *cnp = ap->a_cnp;
 2270         struct nfsv2_sattr *sp;
 2271         u_int32_t *tl;
 2272         char *cp;
 2273         int32_t t1, t2;
 2274         int len;
 2275         struct nfsnode *dnp = VTONFS(dvp), *np = (struct nfsnode *)0;
 2276         struct vnode *newvp = (struct vnode *)0;
 2277         char *bpos, *dpos, *cp2;
 2278         int error = 0, wccflag = NFSV3_WCCRATTR;
 2279         int gotvp = 0;
 2280         int rexmit = 0;
 2281         struct mbuf *mreq, *mrep, *md, *mb;
 2282         const int v3 = NFS_ISV3(dvp);
 2283 
 2284         len = cnp->cn_namelen;
 2285         nfsstats.rpccnt[NFSPROC_MKDIR]++;
 2286         nfsm_reqhead(dnp, NFSPROC_MKDIR,
 2287           NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
 2288         nfsm_fhtom(dnp, v3);
 2289         nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
 2290 #ifndef NFS_V2_ONLY
 2291         if (v3) {
 2292                 nfsm_v3attrbuild(vap, false);
 2293         } else
 2294 #endif
 2295         {
 2296                 nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
 2297                 sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
 2298                 sp->sa_uid = nfs_xdrneg1;
 2299                 sp->sa_gid = nfs_xdrneg1;
 2300                 sp->sa_size = nfs_xdrneg1;
 2301                 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
 2302                 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
 2303         }
 2304         nfsm_request1(dnp, NFSPROC_MKDIR, curlwp, cnp->cn_cred, &rexmit);
 2305         if (!error)
 2306                 nfsm_mtofh(dvp, newvp, v3, gotvp);
 2307         if (v3)
 2308                 nfsm_wcc_data(dvp, wccflag, 0, !error);
 2309         nfsm_reqdone;
 2310         VTONFS(dvp)->n_flag |= NMODIFIED;
 2311         if (!wccflag)
 2312                 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp));
 2313         /*
 2314          * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
 2315          * if we can succeed in looking up the directory.
 2316          */
 2317         if ((rexmit && error == EEXIST) || (!error && !gotvp)) {
 2318                 if (newvp) {
 2319                         vput(newvp);
 2320                         newvp = (struct vnode *)0;
 2321                 }
 2322                 error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
 2323                         curlwp, &np);
 2324                 if (!error) {
 2325                         newvp = NFSTOV(np);
 2326                         if (newvp->v_type != VDIR || newvp == dvp)
 2327                                 error = EEXIST;
 2328                 }
 2329         }
 2330         if (error) {
 2331                 if (newvp) {
 2332                         if (dvp != newvp)
 2333                                 vput(newvp);
 2334                         else
 2335                                 vrele(newvp);
 2336                 }
 2337         } else {
 2338                 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
 2339                 if (cnp->cn_flags & MAKEENTRY)
 2340                         nfs_cache_enter(dvp, newvp, cnp);
 2341                 *ap->a_vpp = newvp;
 2342         }
 2343         PNBUF_PUT(cnp->cn_pnbuf);
 2344         vput(dvp);
 2345         return (error);
 2346 }
 2347 
 2348 /*
 2349  * nfs remove directory call
 2350  */
 2351 int
 2352 nfs_rmdir(v)
 2353         void *v;
 2354 {
 2355         struct vop_rmdir_args /* {
 2356                 struct vnode *a_dvp;
 2357                 struct vnode *a_vp;
 2358                 struct componentname *a_cnp;
 2359         } */ *ap = v;
 2360         struct vnode *vp = ap->a_vp;
 2361         struct vnode *dvp = ap->a_dvp;
 2362         struct componentname *cnp = ap->a_cnp;
 2363         u_int32_t *tl;
 2364         char *cp;
 2365 #ifndef NFS_V2_ONLY
 2366         int32_t t1;
 2367         char *cp2;
 2368 #endif
 2369         int32_t t2;
 2370         char *bpos, *dpos;
 2371         int error = 0, wccflag = NFSV3_WCCRATTR;
 2372         int rexmit = 0;
 2373         struct mbuf *mreq, *mrep, *md, *mb;
 2374         const int v3 = NFS_ISV3(dvp);
 2375         struct nfsnode *dnp;
 2376 
 2377         if (dvp == vp) {
 2378                 vrele(dvp);
 2379                 vput(dvp);
 2380                 PNBUF_PUT(cnp->cn_pnbuf);
 2381                 return (EINVAL);
 2382         }
 2383         nfsstats.rpccnt[NFSPROC_RMDIR]++;
 2384         dnp = VTONFS(dvp);
 2385         nfsm_reqhead(dnp, NFSPROC_RMDIR,
 2386                 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
 2387         nfsm_fhtom(dnp, v3);
 2388         nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
 2389         nfsm_request1(dnp, NFSPROC_RMDIR, curlwp, cnp->cn_cred, &rexmit);
 2390 #ifndef NFS_V2_ONLY
 2391         if (v3)
 2392                 nfsm_wcc_data(dvp, wccflag, 0, !error);
 2393 #endif
 2394         nfsm_reqdone;
 2395         PNBUF_PUT(cnp->cn_pnbuf);
 2396         VTONFS(dvp)->n_flag |= NMODIFIED;
 2397         if (!wccflag)
 2398                 NFS_INVALIDATE_ATTRCACHE(VTONFS(dvp));
 2399         VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
 2400         VN_KNOTE(vp, NOTE_DELETE);
 2401         cache_purge(vp);
 2402         vput(vp);
 2403         vput(dvp);
 2404         /*
 2405          * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
 2406          */
 2407         if (rexmit && error == ENOENT)
 2408                 error = 0;
 2409         return (error);
 2410 }
 2411 
 2412 /*
 2413  * nfs readdir call
 2414  */
 2415 int
 2416 nfs_readdir(v)
 2417         void *v;
 2418 {
 2419         struct vop_readdir_args /* {
 2420                 struct vnode *a_vp;
 2421                 struct uio *a_uio;
 2422                 kauth_cred_t a_cred;
 2423                 int *a_eofflag;
 2424                 off_t **a_cookies;
 2425                 int *a_ncookies;
 2426         } */ *ap = v;
 2427         struct vnode *vp = ap->a_vp;
 2428         struct uio *uio = ap->a_uio;
 2429         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 2430         char *base = uio->uio_iov->iov_base;
 2431         int tresid, error;
 2432         size_t count, lost;
 2433         struct dirent *dp;
 2434         off_t *cookies = NULL;
 2435         int ncookies = 0, nc;
 2436 
 2437         if (vp->v_type != VDIR)
 2438                 return (EPERM);
 2439 
 2440         lost = uio->uio_resid & (NFS_DIRFRAGSIZ - 1);
 2441         count = uio->uio_resid - lost;
 2442         if (count <= 0)
 2443                 return (EINVAL);
 2444 
 2445         /*
 2446          * Call nfs_bioread() to do the real work.
 2447          */
 2448         tresid = uio->uio_resid = count;
 2449         error = nfs_bioread(vp, uio, 0, ap->a_cred,
 2450                     ap->a_cookies ? NFSBIO_CACHECOOKIES : 0);
 2451 
 2452         if (!error && ap->a_cookies) {
 2453                 ncookies = count / 16;
 2454                 cookies = malloc(sizeof (off_t) * ncookies, M_TEMP, M_WAITOK);
 2455                 *ap->a_cookies = cookies;
 2456         }
 2457 
 2458         if (!error && uio->uio_resid == tresid) {
 2459                 uio->uio_resid += lost;
 2460                 nfsstats.direofcache_misses++;
 2461                 if (ap->a_cookies)
 2462                         *ap->a_ncookies = 0;
 2463                 *ap->a_eofflag = 1;
 2464                 return (0);
 2465         }
 2466 
 2467         if (!error && ap->a_cookies) {
 2468                 /*
 2469                  * Only the NFS server and emulations use cookies, and they
 2470                  * load the directory block into system space, so we can
 2471                  * just look at it directly.
 2472                  */
 2473                 if (!VMSPACE_IS_KERNEL_P(uio->uio_vmspace) ||
 2474                     uio->uio_iovcnt != 1)
 2475                         panic("nfs_readdir: lost in space");
 2476                 for (nc = 0; ncookies-- &&
 2477                      base < (char *)uio->uio_iov->iov_base; nc++){
 2478                         dp = (struct dirent *) base;
 2479                         if (dp->d_reclen == 0)
 2480                                 break;
 2481                         if (nmp->nm_flag & NFSMNT_XLATECOOKIE)
 2482                                 *(cookies++) = (off_t)NFS_GETCOOKIE32(dp);
 2483                         else
 2484                                 *(cookies++) = NFS_GETCOOKIE(dp);
 2485                         base += dp->d_reclen;
 2486                 }
 2487                 uio->uio_resid +=
 2488                     ((char *)uio->uio_iov->iov_base - base);
 2489                 uio->uio_iov->iov_len +=
 2490                     ((char *)uio->uio_iov->iov_base - base);
 2491                 uio->uio_iov->iov_base = base;
 2492                 *ap->a_ncookies = nc;
 2493         }
 2494 
 2495         uio->uio_resid += lost;
 2496         *ap->a_eofflag = 0;
 2497         return (error);
 2498 }
 2499 
 2500 /*
 2501  * Readdir rpc call.
 2502  * Called from below the buffer cache by nfs_doio().
 2503  */
 2504 int
 2505 nfs_readdirrpc(vp, uiop, cred)
 2506         struct vnode *vp;
 2507         struct uio *uiop;
 2508         kauth_cred_t cred;
 2509 {
 2510         int len, left;
 2511         struct dirent *dp = NULL;
 2512         u_int32_t *tl;
 2513         char *cp;
 2514         int32_t t1, t2;
 2515         char *bpos, *dpos, *cp2;
 2516         struct mbuf *mreq, *mrep, *md, *mb;
 2517         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 2518         struct nfsnode *dnp = VTONFS(vp);
 2519         u_quad_t fileno;
 2520         int error = 0, more_dirs = 1, blksiz = 0, bigenough = 1;
 2521 #ifndef NFS_V2_ONLY
 2522         int attrflag;
 2523 #endif
 2524         int nrpcs = 0, reclen;
 2525         const int v3 = NFS_ISV3(vp);
 2526 
 2527 #ifdef DIAGNOSTIC
 2528         /*
 2529          * Should be called from buffer cache, so only amount of
 2530          * NFS_DIRBLKSIZ will be requested.
 2531          */
 2532         if (uiop->uio_iovcnt != 1 || uiop->uio_resid != NFS_DIRBLKSIZ)
 2533                 panic("nfs readdirrpc bad uio");
 2534 #endif
 2535 
 2536         /*
 2537          * Loop around doing readdir rpc's of size nm_readdirsize
 2538          * truncated to a multiple of NFS_DIRFRAGSIZ.
 2539          * The stopping criteria is EOF or buffer full.
 2540          */
 2541         while (more_dirs && bigenough) {
 2542                 /*
 2543                  * Heuristic: don't bother to do another RPC to further
 2544                  * fill up this block if there is not much room left. (< 50%
 2545                  * of the readdir RPC size). This wastes some buffer space
 2546                  * but can save up to 50% in RPC calls.
 2547                  */
 2548                 if (nrpcs > 0 && uiop->uio_resid < (nmp->nm_readdirsize / 2)) {
 2549                         bigenough = 0;
 2550                         break;
 2551                 }
 2552                 nfsstats.rpccnt[NFSPROC_READDIR]++;
 2553                 nfsm_reqhead(dnp, NFSPROC_READDIR, NFSX_FH(v3) +
 2554                         NFSX_READDIR(v3));
 2555                 nfsm_fhtom(dnp, v3);
 2556 #ifndef NFS_V2_ONLY
 2557                 if (v3) {
 2558                         nfsm_build(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 2559                         if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE) {
 2560                                 txdr_swapcookie3(uiop->uio_offset, tl);
 2561                         } else {
 2562                                 txdr_cookie3(uiop->uio_offset, tl);
 2563                         }
 2564                         tl += 2;
 2565                         *tl++ = dnp->n_cookieverf.nfsuquad[0];
 2566                         *tl++ = dnp->n_cookieverf.nfsuquad[1];
 2567                 } else
 2568 #endif
 2569                 {
 2570                         nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2571                         *tl++ = txdr_unsigned(uiop->uio_offset);
 2572                 }
 2573                 *tl = txdr_unsigned(nmp->nm_readdirsize);
 2574                 nfsm_request(dnp, NFSPROC_READDIR, curlwp, cred);
 2575                 nrpcs++;
 2576 #ifndef NFS_V2_ONLY
 2577                 if (v3) {
 2578                         nfsm_postop_attr(vp, attrflag, 0);
 2579                         if (!error) {
 2580                                 nfsm_dissect(tl, u_int32_t *,
 2581                                     2 * NFSX_UNSIGNED);
 2582                                 dnp->n_cookieverf.nfsuquad[0] = *tl++;
 2583                                 dnp->n_cookieverf.nfsuquad[1] = *tl;
 2584                         } else {
 2585                                 m_freem(mrep);
 2586                                 goto nfsmout;
 2587                         }
 2588                 }
 2589 #endif
 2590                 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
 2591                 more_dirs = fxdr_unsigned(int, *tl);
 2592 
 2593                 /* loop thru the dir entries, doctoring them to 4bsd form */
 2594                 while (more_dirs && bigenough) {
 2595 #ifndef NFS_V2_ONLY
 2596                         if (v3) {
 2597                                 nfsm_dissect(tl, u_int32_t *,
 2598                                     3 * NFSX_UNSIGNED);
 2599                                 fileno = fxdr_hyper(tl);
 2600                                 len = fxdr_unsigned(int, *(tl + 2));
 2601                         } else
 2602 #endif
 2603                         {
 2604                                 nfsm_dissect(tl, u_int32_t *,
 2605                                     2 * NFSX_UNSIGNED);
 2606                                 fileno = fxdr_unsigned(u_quad_t, *tl++);
 2607                                 len = fxdr_unsigned(int, *tl);
 2608                         }
 2609                         if (len <= 0 || len > NFS_MAXNAMLEN) {
 2610                                 error = EBADRPC;
 2611                                 m_freem(mrep);
 2612                                 goto nfsmout;
 2613                         }
 2614                         /* for cookie stashing */
 2615                         reclen = _DIRENT_RECLEN(dp, len) + 2 * sizeof(off_t);
 2616                         left = NFS_DIRFRAGSIZ - blksiz;
 2617                         if (reclen > left) {
 2618                                 memset(uiop->uio_iov->iov_base, 0, left);
 2619                                 dp->d_reclen += left;
 2620                                 UIO_ADVANCE(uiop, left);
 2621                                 blksiz = 0;
 2622                                 NFS_STASHCOOKIE(dp, uiop->uio_offset);
 2623                         }
 2624                         if (reclen > uiop->uio_resid)
 2625                                 bigenough = 0;
 2626                         if (bigenough) {
 2627                                 int tlen;
 2628 
 2629                                 dp = (struct dirent *)uiop->uio_iov->iov_base;
 2630                                 dp->d_fileno = fileno;
 2631                                 dp->d_namlen = len;
 2632                                 dp->d_reclen = reclen;
 2633                                 dp->d_type = DT_UNKNOWN;
 2634                                 blksiz += reclen;
 2635                                 if (blksiz == NFS_DIRFRAGSIZ)
 2636                                         blksiz = 0;
 2637                                 UIO_ADVANCE(uiop, DIRHDSIZ);
 2638                                 nfsm_mtouio(uiop, len);
 2639                                 tlen = reclen - (DIRHDSIZ + len);
 2640                                 (void)memset(uiop->uio_iov->iov_base, 0, tlen);
 2641                                 UIO_ADVANCE(uiop, tlen);
 2642                         } else
 2643                                 nfsm_adv(nfsm_rndup(len));
 2644 #ifndef NFS_V2_ONLY
 2645                         if (v3) {
 2646                                 nfsm_dissect(tl, u_int32_t *,
 2647                                     3 * NFSX_UNSIGNED);
 2648                         } else
 2649 #endif
 2650                         {
 2651                                 nfsm_dissect(tl, u_int32_t *,
 2652                                     2 * NFSX_UNSIGNED);
 2653                         }
 2654                         if (bigenough) {
 2655 #ifndef NFS_V2_ONLY
 2656                                 if (v3) {
 2657                                         if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE)
 2658                                                 uiop->uio_offset =
 2659                                                     fxdr_swapcookie3(tl);
 2660                                         else
 2661                                                 uiop->uio_offset =
 2662                                                     fxdr_cookie3(tl);
 2663                                 }
 2664                                 else
 2665 #endif
 2666                                 {
 2667                                         uiop->uio_offset =
 2668                                             fxdr_unsigned(off_t, *tl);
 2669                                 }
 2670                                 NFS_STASHCOOKIE(dp, uiop->uio_offset);
 2671                         }
 2672                         if (v3)
 2673                                 tl += 2;
 2674                         else
 2675                                 tl++;
 2676                         more_dirs = fxdr_unsigned(int, *tl);
 2677                 }
 2678                 /*
 2679                  * If at end of rpc data, get the eof boolean
 2680                  */
 2681                 if (!more_dirs) {
 2682                         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
 2683                         more_dirs = (fxdr_unsigned(int, *tl) == 0);
 2684 
 2685                         /*
 2686                          * kludge: if we got no entries, treat it as EOF.
 2687                          * some server sometimes send a reply without any
 2688                          * entries or EOF.
 2689                          * although it might mean the server has very long name,
 2690                          * we can't handle such entries anyway.
 2691                          */
 2692 
 2693                         if (uiop->uio_resid >= NFS_DIRBLKSIZ)
 2694                                 more_dirs = 0;
 2695                 }
 2696                 m_freem(mrep);
 2697         }
 2698         /*
 2699          * Fill last record, iff any, out to a multiple of NFS_DIRFRAGSIZ
 2700          * by increasing d_reclen for the last record.
 2701          */
 2702         if (blksiz > 0) {
 2703                 left = NFS_DIRFRAGSIZ - blksiz;
 2704                 memset(uiop->uio_iov->iov_base, 0, left);
 2705                 dp->d_reclen += left;
 2706                 NFS_STASHCOOKIE(dp, uiop->uio_offset);
 2707                 UIO_ADVANCE(uiop, left);
 2708         }
 2709 
 2710         /*
 2711          * We are now either at the end of the directory or have filled the
 2712          * block.
 2713          */
 2714         if (bigenough) {
 2715                 dnp->n_direofoffset = uiop->uio_offset;
 2716                 dnp->n_flag |= NEOFVALID;
 2717         }
 2718 nfsmout:
 2719         return (error);
 2720 }
 2721 
 2722 #ifndef NFS_V2_ONLY
 2723 /*
 2724  * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
 2725  */
 2726 int
 2727 nfs_readdirplusrpc(vp, uiop, cred)
 2728         struct vnode *vp;
 2729         struct uio *uiop;
 2730         kauth_cred_t cred;
 2731 {
 2732         int len, left;
 2733         struct dirent *dp = NULL;
 2734         u_int32_t *tl;
 2735         char *cp;
 2736         int32_t t1, t2;
 2737         struct vnode *newvp;
 2738         char *bpos, *dpos, *cp2;
 2739         struct mbuf *mreq, *mrep, *md, *mb;
 2740         struct nameidata nami, *ndp = &nami;
 2741         struct componentname *cnp = &ndp->ni_cnd;
 2742         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 2743         struct nfsnode *dnp = VTONFS(vp), *np;
 2744         nfsfh_t *fhp;
 2745         u_quad_t fileno;
 2746         int error = 0, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
 2747         int attrflag, fhsize, nrpcs = 0, reclen;
 2748         struct nfs_fattr fattr, *fp;
 2749 
 2750 #ifdef DIAGNOSTIC
 2751         if (uiop->uio_iovcnt != 1 || uiop->uio_resid != NFS_DIRBLKSIZ)
 2752                 panic("nfs readdirplusrpc bad uio");
 2753 #endif
 2754         ndp->ni_dvp = vp;
 2755         newvp = NULLVP;
 2756 
 2757         /*
 2758          * Loop around doing readdir rpc's of size nm_readdirsize
 2759          * truncated to a multiple of NFS_DIRFRAGSIZ.
 2760          * The stopping criteria is EOF or buffer full.
 2761          */
 2762         while (more_dirs && bigenough) {
 2763                 if (nrpcs > 0 && uiop->uio_resid < (nmp->nm_readdirsize / 2)) {
 2764                         bigenough = 0;
 2765                         break;
 2766                 }
 2767                 nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
 2768                 nfsm_reqhead(dnp, NFSPROC_READDIRPLUS,
 2769                         NFSX_FH(1) + 6 * NFSX_UNSIGNED);
 2770                 nfsm_fhtom(dnp, 1);
 2771                 nfsm_build(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
 2772                 if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE) {
 2773                         txdr_swapcookie3(uiop->uio_offset, tl);
 2774                 } else {
 2775                         txdr_cookie3(uiop->uio_offset, tl);
 2776                 }
 2777                 tl += 2;
 2778                 *tl++ = dnp->n_cookieverf.nfsuquad[0];
 2779                 *tl++ = dnp->n_cookieverf.nfsuquad[1];
 2780                 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
 2781                 *tl = txdr_unsigned(nmp->nm_rsize);
 2782                 nfsm_request(dnp, NFSPROC_READDIRPLUS, curlwp, cred);
 2783                 nfsm_postop_attr(vp, attrflag, 0);
 2784                 if (error) {
 2785                         m_freem(mrep);
 2786                         goto nfsmout;
 2787                 }
 2788                 nrpcs++;
 2789                 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 2790                 dnp->n_cookieverf.nfsuquad[0] = *tl++;
 2791                 dnp->n_cookieverf.nfsuquad[1] = *tl++;
 2792                 more_dirs = fxdr_unsigned(int, *tl);
 2793 
 2794                 /* loop thru the dir entries, doctoring them to 4bsd form */
 2795                 while (more_dirs && bigenough) {
 2796                         nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 2797                         fileno = fxdr_hyper(tl);
 2798                         len = fxdr_unsigned(int, *(tl + 2));
 2799                         if (len <= 0 || len > NFS_MAXNAMLEN) {
 2800                                 error = EBADRPC;
 2801                                 m_freem(mrep);
 2802                                 goto nfsmout;
 2803                         }
 2804                         /* for cookie stashing */
 2805                         reclen = _DIRENT_RECLEN(dp, len) + 2 * sizeof(off_t);
 2806                         left = NFS_DIRFRAGSIZ - blksiz;
 2807                         if (reclen > left) {
 2808                                 /*
 2809                                  * DIRFRAGSIZ is aligned, no need to align
 2810                                  * again here.
 2811                                  */
 2812                                 memset(uiop->uio_iov->iov_base, 0, left);
 2813                                 dp->d_reclen += left;
 2814                                 UIO_ADVANCE(uiop, left);
 2815                                 NFS_STASHCOOKIE(dp, uiop->uio_offset);
 2816                                 blksiz = 0;
 2817                         }
 2818                         if (reclen > uiop->uio_resid)
 2819                                 bigenough = 0;
 2820                         if (bigenough) {
 2821                                 int tlen;
 2822 
 2823                                 dp = (struct dirent *)uiop->uio_iov->iov_base;
 2824                                 dp->d_fileno = fileno;
 2825                                 dp->d_namlen = len;
 2826                                 dp->d_reclen = reclen;
 2827                                 dp->d_type = DT_UNKNOWN;
 2828                                 blksiz += reclen;
 2829                                 if (blksiz == NFS_DIRFRAGSIZ)
 2830                                         blksiz = 0;
 2831                                 UIO_ADVANCE(uiop, DIRHDSIZ);
 2832                                 nfsm_mtouio(uiop, len);
 2833                                 tlen = reclen - (DIRHDSIZ + len);
 2834                                 (void)memset(uiop->uio_iov->iov_base, 0, tlen);
 2835                                 UIO_ADVANCE(uiop, tlen);
 2836                                 cnp->cn_nameptr = dp->d_name;
 2837                                 cnp->cn_namelen = dp->d_namlen;
 2838                         } else
 2839                                 nfsm_adv(nfsm_rndup(len));
 2840                         nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 2841                         if (bigenough) {
 2842                                 if (nmp->nm_iflag & NFSMNT_SWAPCOOKIE)
 2843                                         uiop->uio_offset =
 2844                                                 fxdr_swapcookie3(tl);
 2845                                 else
 2846                                         uiop->uio_offset =
 2847                                                 fxdr_cookie3(tl);
 2848                                 NFS_STASHCOOKIE(dp, uiop->uio_offset);
 2849                         }
 2850                         tl += 2;
 2851 
 2852                         /*
 2853                          * Since the attributes are before the file handle
 2854                          * (sigh), we must skip over the attributes and then
 2855                          * come back and get them.
 2856                          */
 2857                         attrflag = fxdr_unsigned(int, *tl);
 2858                         if (attrflag) {
 2859                             nfsm_dissect(fp, struct nfs_fattr *, NFSX_V3FATTR);
 2860                             memcpy(&fattr, fp, NFSX_V3FATTR);
 2861                             nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
 2862                             doit = fxdr_unsigned(int, *tl);
 2863                             if (doit) {
 2864                                 nfsm_getfh(fhp, fhsize, 1);
 2865                                 if (NFS_CMPFH(dnp, fhp, fhsize)) {
 2866                                     VREF(vp);
 2867                                     newvp = vp;
 2868                                     np = dnp;
 2869                                 } else {
 2870                                     error = nfs_nget1(vp->v_mount, fhp,
 2871                                         fhsize, &np, LK_NOWAIT);
 2872                                     if (!error)
 2873                                         newvp = NFSTOV(np);
 2874                                 }
 2875                                 if (!error) {
 2876                                     const char *xcp;
 2877 
 2878                                     nfs_loadattrcache(&newvp, &fattr, 0, 0);
 2879                                     if (bigenough) {
 2880                                         dp->d_type =
 2881                                            IFTODT(VTTOIF(np->n_vattr->va_type));
 2882                                         if (cnp->cn_namelen <= NCHNAMLEN) {
 2883                                             ndp->ni_vp = newvp;
 2884                                             xcp = cnp->cn_nameptr +
 2885                                                 cnp->cn_namelen;
 2886                                             cnp->cn_hash =
 2887                                                namei_hash(cnp->cn_nameptr, &xcp);
 2888                                             nfs_cache_enter(ndp->ni_dvp,
 2889                                                 ndp->ni_vp, cnp);
 2890                                         }
 2891                                     }
 2892                                 }
 2893                                 error = 0;
 2894                            }
 2895                         } else {
 2896                             /* Just skip over the file handle */
 2897                             nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
 2898                             i = fxdr_unsigned(int, *tl);
 2899                             nfsm_adv(nfsm_rndup(i));
 2900                         }
 2901                         if (newvp != NULLVP) {
 2902                             if (newvp == vp)
 2903                                 vrele(newvp);
 2904                             else
 2905                                 vput(newvp);
 2906                             newvp = NULLVP;
 2907                         }
 2908                         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
 2909                         more_dirs = fxdr_unsigned(int, *tl);
 2910                 }
 2911                 /*
 2912                  * If at end of rpc data, get the eof boolean
 2913                  */
 2914                 if (!more_dirs) {
 2915                         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
 2916                         more_dirs = (fxdr_unsigned(int, *tl) == 0);
 2917 
 2918                         /*
 2919                          * kludge: see a comment in nfs_readdirrpc.
 2920                          */
 2921 
 2922                         if (uiop->uio_resid >= NFS_DIRBLKSIZ)
 2923                                 more_dirs = 0;
 2924                 }
 2925                 m_freem(mrep);
 2926         }
 2927         /*
 2928          * Fill last record, iff any, out to a multiple of NFS_DIRFRAGSIZ
 2929          * by increasing d_reclen for the last record.
 2930          */
 2931         if (blksiz > 0) {
 2932                 left = NFS_DIRFRAGSIZ - blksiz;
 2933                 memset(uiop->uio_iov->iov_base, 0, left);
 2934                 dp->d_reclen += left;
 2935                 NFS_STASHCOOKIE(dp, uiop->uio_offset);
 2936                 UIO_ADVANCE(uiop, left);
 2937         }
 2938 
 2939         /*
 2940          * We are now either at the end of the directory or have filled the
 2941          * block.
 2942          */
 2943         if (bigenough) {
 2944                 dnp->n_direofoffset = uiop->uio_offset;
 2945                 dnp->n_flag |= NEOFVALID;
 2946         }
 2947 nfsmout:
 2948         if (newvp != NULLVP) {
 2949                 if(newvp == vp)
 2950                     vrele(newvp);
 2951                 else
 2952                     vput(newvp);
 2953         }
 2954         return (error);
 2955 }
 2956 #endif
 2957 
 2958 /*
 2959  * Silly rename. To make the NFS filesystem that is stateless look a little
 2960  * more like the "ufs" a remove of an active vnode is translated to a rename
 2961  * to a funny looking filename that is removed by nfs_inactive on the
 2962  * nfsnode. There is the potential for another process on a different client
 2963  * to create the same funny name between the nfs_lookitup() fails and the
 2964  * nfs_rename() completes, but...
 2965  */
 2966 int
 2967 nfs_sillyrename(dvp, vp, cnp, dolink)
 2968         struct vnode *dvp, *vp;
 2969         struct componentname *cnp;
 2970         bool dolink;
 2971 {
 2972         struct sillyrename *sp;
 2973         struct nfsnode *np;
 2974         int error;
 2975         short pid;
 2976 
 2977         cache_purge(dvp);
 2978         np = VTONFS(vp);
 2979 #ifndef DIAGNOSTIC
 2980         if (vp->v_type == VDIR)
 2981                 panic("nfs: sillyrename dir");
 2982 #endif
 2983         sp = kmem_alloc(sizeof(*sp), KM_SLEEP);
 2984         sp->s_cred = kauth_cred_dup(cnp->cn_cred);
 2985         sp->s_dvp = dvp;
 2986         VREF(dvp);
 2987 
 2988         /* Fudge together a funny name */
 2989         pid = curlwp->l_proc->p_pid;
 2990         memcpy(sp->s_name, ".nfsAxxxx4.4", 13);
 2991         sp->s_namlen = 12;
 2992         sp->s_name[8] = hexdigits[pid & 0xf];
 2993         sp->s_name[7] = hexdigits[(pid >> 4) & 0xf];
 2994         sp->s_name[6] = hexdigits[(pid >> 8) & 0xf];
 2995         sp->s_name[5] = hexdigits[(pid >> 12) & 0xf];
 2996 
 2997         /* Try lookitups until we get one that isn't there */
 2998         while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
 2999                 curlwp, (struct nfsnode **)0) == 0) {
 3000                 sp->s_name[4]++;
 3001                 if (sp->s_name[4] > 'z') {
 3002                         error = EINVAL;
 3003                         goto bad;
 3004                 }
 3005         }
 3006         if (dolink) {
 3007                 error = nfs_linkrpc(dvp, vp, sp->s_name, sp->s_namlen,
 3008                     sp->s_cred, curlwp);
 3009                 /*
 3010                  * nfs_request maps NFSERR_NOTSUPP to ENOTSUP.
 3011                  */
 3012                 if (error == ENOTSUP) {
 3013                         error = nfs_renameit(dvp, cnp, sp);
 3014                 }
 3015         } else {
 3016                 error = nfs_renameit(dvp, cnp, sp);
 3017         }
 3018         if (error)
 3019                 goto bad;
 3020         error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
 3021                 curlwp, &np);
 3022         np->n_sillyrename = sp;
 3023         return (0);
 3024 bad:
 3025         vrele(sp->s_dvp);
 3026         kauth_cred_free(sp->s_cred);
 3027         kmem_free(sp, sizeof(*sp));
 3028         return (error);
 3029 }
 3030 
 3031 /*
 3032  * Look up a file name and optionally either update the file handle or
 3033  * allocate an nfsnode, depending on the value of npp.
 3034  * npp == NULL  --> just do the lookup
 3035  * *npp == NULL --> allocate a new nfsnode and make sure attributes are
 3036  *                      handled too
 3037  * *npp != NULL --> update the file handle in the vnode
 3038  */
 3039 int
 3040 nfs_lookitup(dvp, name, len, cred, l, npp)
 3041         struct vnode *dvp;
 3042         const char *name;
 3043         int len;
 3044         kauth_cred_t cred;
 3045         struct lwp *l;
 3046         struct nfsnode **npp;
 3047 {
 3048         u_int32_t *tl;
 3049         char *cp;
 3050         int32_t t1, t2;
 3051         struct vnode *newvp = (struct vnode *)0;
 3052         struct nfsnode *np, *dnp = VTONFS(dvp);
 3053         char *bpos, *dpos, *cp2;
 3054         int error = 0, fhlen;
 3055 #ifndef NFS_V2_ONLY
 3056         int attrflag;
 3057 #endif
 3058         struct mbuf *mreq, *mrep, *md, *mb;
 3059         nfsfh_t *nfhp;
 3060         const int v3 = NFS_ISV3(dvp);
 3061 
 3062         nfsstats.rpccnt[NFSPROC_LOOKUP]++;
 3063         nfsm_reqhead(dnp, NFSPROC_LOOKUP,
 3064                 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
 3065         nfsm_fhtom(dnp, v3);
 3066         nfsm_strtom(name, len, NFS_MAXNAMLEN);
 3067         nfsm_request(dnp, NFSPROC_LOOKUP, l, cred);
 3068         if (npp && !error) {
 3069                 nfsm_getfh(nfhp, fhlen, v3);
 3070                 if (*npp) {
 3071                     np = *npp;
 3072                     if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
 3073                         kmem_free(np->n_fhp, np->n_fhsize);
 3074                         np->n_fhp = &np->n_fh;
 3075                     }
 3076 #if NFS_SMALLFH < NFSX_V3FHMAX
 3077                     else if (np->n_fhsize <= NFS_SMALLFH && fhlen > NFS_SMALLFH)
 3078                         np->n_fhp = kmem_alloc(fhlen, KM_SLEEP);
 3079 #endif
 3080                     memcpy(np->n_fhp, nfhp, fhlen);
 3081                     np->n_fhsize = fhlen;
 3082                     newvp = NFSTOV(np);
 3083                 } else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
 3084                     VREF(dvp);
 3085                     newvp = dvp;
 3086                     np = dnp;
 3087                 } else {
 3088                     error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
 3089                     if (error) {
 3090                         m_freem(mrep);
 3091                         return (error);
 3092                     }
 3093                     newvp = NFSTOV(np);
 3094                 }
 3095 #ifndef NFS_V2_ONLY
 3096                 if (v3) {
 3097                         nfsm_postop_attr(newvp, attrflag, 0);
 3098                         if (!attrflag && *npp == NULL) {
 3099                                 m_freem(mrep);
 3100                                 vput(newvp);
 3101                                 return (ENOENT);
 3102                         }
 3103                 } else
 3104 #endif
 3105                         nfsm_loadattr(newvp, (struct vattr *)0, 0);
 3106         }
 3107         nfsm_reqdone;
 3108         if (npp && *npp == NULL) {
 3109                 if (error) {
 3110                         if (newvp)
 3111                                 vput(newvp);
 3112                 } else
 3113                         *npp = np;
 3114         }
 3115         return (error);
 3116 }
 3117 
 3118 #ifndef NFS_V2_ONLY
 3119 /*
 3120  * Nfs Version 3 commit rpc
 3121  */
 3122 int
 3123 nfs_commit(vp, offset, cnt, l)
 3124         struct vnode *vp;
 3125         off_t offset;
 3126         uint32_t cnt;
 3127         struct lwp *l;
 3128 {
 3129         char *cp;
 3130         u_int32_t *tl;
 3131         int32_t t1, t2;
 3132         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 3133         char *bpos, *dpos, *cp2;
 3134         int error = 0, wccflag = NFSV3_WCCRATTR;
 3135         struct mbuf *mreq, *mrep, *md, *mb;
 3136         struct nfsnode *np;
 3137 
 3138         KASSERT(NFS_ISV3(vp));
 3139 
 3140 #ifdef NFS_DEBUG_COMMIT
 3141         printf("commit %lu - %lu\n", (unsigned long)offset,
 3142             (unsigned long)(offset + cnt));
 3143 #endif
 3144 
 3145         mutex_enter(&nmp->nm_lock);
 3146         if ((nmp->nm_iflag & NFSMNT_HASWRITEVERF) == 0) {
 3147                 mutex_exit(&nmp->nm_lock);
 3148                 return (0);
 3149         }
 3150         mutex_exit(&nmp->nm_lock);
 3151         nfsstats.rpccnt[NFSPROC_COMMIT]++;
 3152         np = VTONFS(vp);
 3153         nfsm_reqhead(np, NFSPROC_COMMIT, NFSX_FH(1));
 3154         nfsm_fhtom(np, 1);
 3155         nfsm_build(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3156         txdr_hyper(offset, tl);
 3157         tl += 2;
 3158         *tl = txdr_unsigned(cnt);
 3159         nfsm_request(np, NFSPROC_COMMIT, l, np->n_wcred);
 3160         nfsm_wcc_data(vp, wccflag, NAC_NOTRUNC, false);
 3161         if (!error) {
 3162                 nfsm_dissect(tl, u_int32_t *, NFSX_V3WRITEVERF);
 3163                 mutex_enter(&nmp->nm_lock);
 3164                 if ((nmp->nm_iflag & NFSMNT_STALEWRITEVERF) ||
 3165                     memcmp(nmp->nm_writeverf, tl, NFSX_V3WRITEVERF)) {
 3166                         memcpy(nmp->nm_writeverf, tl, NFSX_V3WRITEVERF);
 3167                         error = NFSERR_STALEWRITEVERF;
 3168                         nmp->nm_iflag |= NFSMNT_STALEWRITEVERF;
 3169                 }
 3170                 mutex_exit(&nmp->nm_lock);
 3171         }
 3172         nfsm_reqdone;
 3173         return (error);
 3174 }
 3175 #endif
 3176 
 3177 /*
 3178  * Kludge City..
 3179  * - make nfs_bmap() essentially a no-op that does no translation
 3180  * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc
 3181  *   (Maybe I could use the process's page mapping, but I was concerned that
 3182  *    Kernel Write might not be enabled and also figured copyout() would do
 3183  *    a lot more work than memcpy() and also it currently happens in the
 3184  *    context of the swapper process (2).
 3185  */
 3186 int
 3187 nfs_bmap(v)
 3188         void *v;
 3189 {
 3190         struct vop_bmap_args /* {
 3191                 struct vnode *a_vp;
 3192                 daddr_t  a_bn;
 3193                 struct vnode **a_vpp;
 3194                 daddr_t *a_bnp;
 3195                 int *a_runp;
 3196         } */ *ap = v;
 3197         struct vnode *vp = ap->a_vp;
 3198         int bshift = vp->v_mount->mnt_fs_bshift - vp->v_mount->mnt_dev_bshift;
 3199 
 3200         if (ap->a_vpp != NULL)
 3201                 *ap->a_vpp = vp;
 3202         if (ap->a_bnp != NULL)
 3203                 *ap->a_bnp = ap->a_bn << bshift;
 3204         if (ap->a_runp != NULL)
 3205                 *ap->a_runp = 1024 * 1024; /* XXX */
 3206         return (0);
 3207 }
 3208 
 3209 /*
 3210  * Strategy routine.
 3211  * For async requests when nfsiod(s) are running, queue the request by
 3212  * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
 3213  * request.
 3214  */
 3215 int
 3216 nfs_strategy(v)
 3217         void *v;
 3218 {
 3219         struct vop_strategy_args *ap = v;
 3220         struct buf *bp = ap->a_bp;
 3221         int error = 0;
 3222 
 3223         if ((bp->b_flags & (B_PHYS|B_ASYNC)) == (B_PHYS|B_ASYNC))
 3224                 panic("nfs physio/async");
 3225 
 3226         /*
 3227          * If the op is asynchronous and an i/o daemon is waiting
 3228          * queue the request, wake it up and wait for completion
 3229          * otherwise just do it ourselves.
 3230          */
 3231         if ((bp->b_flags & B_ASYNC) == 0 || nfs_asyncio(bp))
 3232                 error = nfs_doio(bp);
 3233         return (error);
 3234 }
 3235 
 3236 /*
 3237  * fsync vnode op. Just call nfs_flush() with commit == 1.
 3238  */
 3239 /* ARGSUSED */
 3240 int
 3241 nfs_fsync(v)
 3242         void *v;
 3243 {
 3244         struct vop_fsync_args /* {
 3245                 struct vnodeop_desc *a_desc;
 3246                 struct vnode * a_vp;
 3247                 kauth_cred_t  a_cred;
 3248                 int  a_flags;
 3249                 off_t offlo;
 3250                 off_t offhi;
 3251                 struct lwp * a_l;
 3252         } */ *ap = v;
 3253 
 3254         struct vnode *vp = ap->a_vp;
 3255 
 3256         if (vp->v_type != VREG)
 3257                 return 0;
 3258 
 3259         return (nfs_flush(vp, ap->a_cred,
 3260             (ap->a_flags & FSYNC_WAIT) != 0 ? MNT_WAIT : 0, curlwp, 1));
 3261 }
 3262 
 3263 /*
 3264  * Flush all the data associated with a vnode.
 3265  */
 3266 int
 3267 nfs_flush(struct vnode *vp, kauth_cred_t cred, int waitfor, struct lwp *l,
 3268     int commit)
 3269 {
 3270         struct nfsnode *np = VTONFS(vp);
 3271         int error;
 3272         int flushflags = PGO_ALLPAGES|PGO_CLEANIT|PGO_SYNCIO;
 3273         UVMHIST_FUNC("nfs_flush"); UVMHIST_CALLED(ubchist);
 3274 
 3275         mutex_enter(&vp->v_interlock);
 3276         error = VOP_PUTPAGES(vp, 0, 0, flushflags);
 3277         if (np->n_flag & NWRITEERR) {
 3278                 error = np->n_error;
 3279                 np->n_flag &= ~NWRITEERR;
 3280         }
 3281         UVMHIST_LOG(ubchist, "returning %d", error,0,0,0);
 3282         return (error);
 3283 }
 3284 
 3285 /*
 3286  * Return POSIX pathconf information applicable to nfs.
 3287  *
 3288  * N.B. The NFS V2 protocol doesn't support this RPC.
 3289  */
 3290 /* ARGSUSED */
 3291 int
 3292 nfs_pathconf(v)
 3293         void *v;
 3294 {
 3295         struct vop_pathconf_args /* {
 3296                 struct vnode *a_vp;
 3297                 int a_name;
 3298                 register_t *a_retval;
 3299         } */ *ap = v;
 3300         struct nfsv3_pathconf *pcp;
 3301         struct vnode *vp = ap->a_vp;
 3302         struct mbuf *mreq, *mrep, *md, *mb;
 3303         int32_t t1, t2;
 3304         u_int32_t *tl;
 3305         char *bpos, *dpos, *cp, *cp2;
 3306         int error = 0, attrflag;
 3307 #ifndef NFS_V2_ONLY
 3308         struct nfsmount *nmp;
 3309         unsigned int l;
 3310         u_int64_t maxsize;
 3311 #endif
 3312         const int v3 = NFS_ISV3(vp);
 3313         struct nfsnode *np = VTONFS(vp);
 3314 
 3315         switch (ap->a_name) {
 3316                 /* Names that can be resolved locally. */
 3317         case _PC_PIPE_BUF:
 3318                 *ap->a_retval = PIPE_BUF;
 3319                 break;
 3320         case _PC_SYNC_IO:
 3321                 *ap->a_retval = 1;
 3322                 break;
 3323         /* Names that cannot be resolved locally; do an RPC, if possible. */
 3324         case _PC_LINK_MAX:
 3325         case _PC_NAME_MAX:
 3326         case _PC_CHOWN_RESTRICTED:
 3327         case _PC_NO_TRUNC:
 3328                 if (!v3) {
 3329                         error = EINVAL;
 3330                         break;
 3331                 }
 3332                 nfsstats.rpccnt[NFSPROC_PATHCONF]++;
 3333                 nfsm_reqhead(np, NFSPROC_PATHCONF, NFSX_FH(1));
 3334                 nfsm_fhtom(np, 1);
 3335                 nfsm_request(np, NFSPROC_PATHCONF,
 3336                     curlwp, curlwp->l_cred);    /* XXX */
 3337                 nfsm_postop_attr(vp, attrflag, 0);
 3338                 if (!error) {
 3339                         nfsm_dissect(pcp, struct nfsv3_pathconf *,
 3340                             NFSX_V3PATHCONF);
 3341                         switch (ap->a_name) {
 3342                         case _PC_LINK_MAX:
 3343                                 *ap->a_retval =
 3344                                     fxdr_unsigned(register_t, pcp->pc_linkmax);
 3345                                 break;
 3346                         case _PC_NAME_MAX:
 3347                                 *ap->a_retval =
 3348                                     fxdr_unsigned(register_t, pcp->pc_namemax);
 3349                                 break;
 3350                         case _PC_CHOWN_RESTRICTED:
 3351                                 *ap->a_retval =
 3352                                     (pcp->pc_chownrestricted == nfs_true);
 3353                                 break;
 3354                         case _PC_NO_TRUNC:
 3355                                 *ap->a_retval =
 3356                                     (pcp->pc_notrunc == nfs_true);
 3357                                 break;
 3358                         }
 3359                 }
 3360                 nfsm_reqdone;
 3361                 break;
 3362         case _PC_FILESIZEBITS:
 3363 #ifndef NFS_V2_ONLY
 3364                 if (v3) {
 3365                         nmp = VFSTONFS(vp->v_mount);
 3366                         if ((nmp->nm_iflag & NFSMNT_GOTFSINFO) == 0)
 3367                                 if ((error = nfs_fsinfo(nmp, vp,
 3368                                     curlwp->l_cred, curlwp)) != 0) /* XXX */
 3369                                         break;
 3370                         for (l = 0, maxsize = nmp->nm_maxfilesize;
 3371                             (maxsize >> l) > 0; l++)
 3372                                 ;
 3373                         *ap->a_retval = l + 1;
 3374                 } else
 3375 #endif
 3376                 {
 3377                         *ap->a_retval = 32;     /* NFS V2 limitation */
 3378                 }
 3379                 break;
 3380         default:
 3381                 error = EINVAL;
 3382                 break;
 3383         }
 3384 
 3385         return (error);
 3386 }
 3387 
 3388 /*
 3389  * NFS advisory byte-level locks.
 3390  */
 3391 int
 3392 nfs_advlock(v)
 3393         void *v;
 3394 {
 3395         struct vop_advlock_args /* {
 3396                 struct vnode *a_vp;
 3397                 void *a_id;
 3398                 int  a_op;
 3399                 struct flock *a_fl;
 3400                 int  a_flags;
 3401         } */ *ap = v;
 3402         struct nfsnode *np = VTONFS(ap->a_vp);
 3403 
 3404         return lf_advlock(ap, &np->n_lockf, np->n_size);
 3405 }
 3406 
 3407 /*
 3408  * Print out the contents of an nfsnode.
 3409  */
 3410 int
 3411 nfs_print(v)
 3412         void *v;
 3413 {
 3414         struct vop_print_args /* {
 3415                 struct vnode *a_vp;
 3416         } */ *ap = v;
 3417         struct vnode *vp = ap->a_vp;
 3418         struct nfsnode *np = VTONFS(vp);
 3419 
 3420         printf("tag VT_NFS, fileid %lld fsid 0x%lx",
 3421             (unsigned long long)np->n_vattr->va_fileid, np->n_vattr->va_fsid);
 3422         if (vp->v_type == VFIFO)
 3423                 fifo_printinfo(vp);
 3424         printf("\n");
 3425         return (0);
 3426 }
 3427 
 3428 /*
 3429  * nfs unlock wrapper.
 3430  */
 3431 int
 3432 nfs_unlock(void *v)
 3433 {
 3434         struct vop_unlock_args /* {
 3435                 struct vnode *a_vp;
 3436                 int a_flags;
 3437         } */ *ap = v;
 3438         struct vnode *vp = ap->a_vp;
 3439 
 3440         /*
 3441          * VOP_UNLOCK can be called by nfs_loadattrcache
 3442          * with v_data == 0.
 3443          */
 3444         if (VTONFS(vp)) {
 3445                 nfs_delayedtruncate(vp);
 3446         }
 3447 
 3448         return genfs_unlock(v);
 3449 }
 3450 
 3451 /*
 3452  * nfs special file access vnode op.
 3453  * Essentially just get vattr and then imitate iaccess() since the device is
 3454  * local to the client.
 3455  */
 3456 int
 3457 nfsspec_access(v)
 3458         void *v;
 3459 {
 3460         struct vop_access_args /* {
 3461                 struct vnode *a_vp;
 3462                 int  a_mode;
 3463                 kauth_cred_t a_cred;
 3464                 struct lwp *a_l;
 3465         } */ *ap = v;
 3466         struct vattr va;
 3467         struct vnode *vp = ap->a_vp;
 3468         int error;
 3469 
 3470         error = VOP_GETATTR(vp, &va, ap->a_cred);
 3471         if (error)
 3472                 return (error);
 3473 
 3474         /*
 3475          * Disallow write attempts on filesystems mounted read-only;
 3476          * unless the file is a socket, fifo, or a block or character
 3477          * device resident on the filesystem.
 3478          */
 3479         if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
 3480                 switch (vp->v_type) {
 3481                 case VREG:
 3482                 case VDIR:
 3483                 case VLNK:
 3484                         return (EROFS);
 3485                 default:
 3486                         break;
 3487                 }
 3488         }
 3489 
 3490         return (vaccess(va.va_type, va.va_mode,
 3491             va.va_uid, va.va_gid, ap->a_mode, ap->a_cred));
 3492 }
 3493 
 3494 /*
 3495  * Read wrapper for special devices.
 3496  */
 3497 int
 3498 nfsspec_read(v)
 3499         void *v;
 3500 {
 3501         struct vop_read_args /* {
 3502                 struct vnode *a_vp;
 3503                 struct uio *a_uio;
 3504                 int  a_ioflag;
 3505                 kauth_cred_t a_cred;
 3506         } */ *ap = v;
 3507         struct nfsnode *np = VTONFS(ap->a_vp);
 3508 
 3509         /*
 3510          * Set access flag.
 3511          */
 3512         np->n_flag |= NACC;
 3513         getnanotime(&np->n_atim);
 3514         return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
 3515 }
 3516 
 3517 /*
 3518  * Write wrapper for special devices.
 3519  */
 3520 int
 3521 nfsspec_write(v)
 3522         void *v;
 3523 {
 3524         struct vop_write_args /* {
 3525                 struct vnode *a_vp;
 3526                 struct uio *a_uio;
 3527                 int  a_ioflag;
 3528                 kauth_cred_t a_cred;
 3529         } */ *ap = v;
 3530         struct nfsnode *np = VTONFS(ap->a_vp);
 3531 
 3532         /*
 3533          * Set update flag.
 3534          */
 3535         np->n_flag |= NUPD;
 3536         getnanotime(&np->n_mtim);
 3537         return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
 3538 }
 3539 
 3540 /*
 3541  * Close wrapper for special devices.
 3542  *
 3543  * Update the times on the nfsnode then do device close.
 3544  */
 3545 int
 3546 nfsspec_close(v)
 3547         void *v;
 3548 {
 3549         struct vop_close_args /* {
 3550                 struct vnode *a_vp;
 3551                 int  a_fflag;
 3552                 kauth_cred_t a_cred;
 3553                 struct lwp *a_l;
 3554         } */ *ap = v;
 3555         struct vnode *vp = ap->a_vp;
 3556         struct nfsnode *np = VTONFS(vp);
 3557         struct vattr vattr;
 3558 
 3559         if (np->n_flag & (NACC | NUPD)) {
 3560                 np->n_flag |= NCHG;
 3561                 if (vp->v_usecount == 1 &&
 3562                     (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
 3563                         VATTR_NULL(&vattr);
 3564                         if (np->n_flag & NACC)
 3565                                 vattr.va_atime = np->n_atim;
 3566                         if (np->n_flag & NUPD)
 3567                                 vattr.va_mtime = np->n_mtim;
 3568                         (void)VOP_SETATTR(vp, &vattr, ap->a_cred);
 3569                 }
 3570         }
 3571         return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
 3572 }
 3573 
 3574 /*
 3575  * Read wrapper for fifos.
 3576  */
 3577 int
 3578 nfsfifo_read(v)
 3579         void *v;
 3580 {
 3581         struct vop_read_args /* {
 3582                 struct vnode *a_vp;
 3583                 struct uio *a_uio;
 3584                 int  a_ioflag;
 3585                 kauth_cred_t a_cred;
 3586         } */ *ap = v;
 3587         struct nfsnode *np = VTONFS(ap->a_vp);
 3588 
 3589         /*
 3590          * Set access flag.
 3591          */
 3592         np->n_flag |= NACC;
 3593         getnanotime(&np->n_atim);
 3594         return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
 3595 }
 3596 
 3597 /*
 3598  * Write wrapper for fifos.
 3599  */
 3600 int
 3601 nfsfifo_write(v)
 3602         void *v;
 3603 {
 3604         struct vop_write_args /* {
 3605                 struct vnode *a_vp;
 3606                 struct uio *a_uio;
 3607                 int  a_ioflag;
 3608                 kauth_cred_t a_cred;
 3609         } */ *ap = v;
 3610         struct nfsnode *np = VTONFS(ap->a_vp);
 3611 
 3612         /*
 3613          * Set update flag.
 3614          */
 3615         np->n_flag |= NUPD;
 3616         getnanotime(&np->n_mtim);
 3617         return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
 3618 }
 3619 
 3620 /*
 3621  * Close wrapper for fifos.
 3622  *
 3623  * Update the times on the nfsnode then do fifo close.
 3624  */
 3625 int
 3626 nfsfifo_close(v)
 3627         void *v;
 3628 {
 3629         struct vop_close_args /* {
 3630                 struct vnode *a_vp;
 3631                 int  a_fflag;
 3632                 kauth_cred_t a_cred;
 3633                 struct lwp *a_l;
 3634         } */ *ap = v;
 3635         struct vnode *vp = ap->a_vp;
 3636         struct nfsnode *np = VTONFS(vp);
 3637         struct vattr vattr;
 3638 
 3639         if (np->n_flag & (NACC | NUPD)) {
 3640                 struct timespec ts;
 3641 
 3642                 getnanotime(&ts);
 3643                 if (np->n_flag & NACC)
 3644                         np->n_atim = ts;
 3645                 if (np->n_flag & NUPD)
 3646                         np->n_mtim = ts;
 3647                 np->n_flag |= NCHG;
 3648                 if (vp->v_usecount == 1 &&
 3649                     (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
 3650                         VATTR_NULL(&vattr);
 3651                         if (np->n_flag & NACC)
 3652                                 vattr.va_atime = np->n_atim;
 3653                         if (np->n_flag & NUPD)
 3654                                 vattr.va_mtime = np->n_mtim;
 3655                         (void)VOP_SETATTR(vp, &vattr, ap->a_cred);
 3656                 }
 3657         }
 3658         return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
 3659 }

Cache object: 97a69d927cf5bb5a08c71a473352159a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.