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

Cache object: 56679604123a88dc272b4b34c016c99d


[ 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.