LCOV - code coverage report
Current view: top level - nfs - nfs_vnops.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1809 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 54 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13