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


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

FreeBSD/Linux Kernel Cross Reference
sys/nfs4client/nfs4_vnops.c

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

    1 /* $FreeBSD: src/sys/nfs4client/nfs4_vnops.c,v 1.6.2.1 2005/01/31 23:26:45 imp Exp $ */
    2 /* $Id: nfs_vnops.c,v 1.45 2003/11/05 14:59:02 rees Exp $ */
    3 
    4 /*-
    5  * copyright (c) 2003
    6  * the regents of the university of michigan
    7  * all rights reserved
    8  * 
    9  * permission is granted to use, copy, create derivative works and redistribute
   10  * this software and such derivative works for any purpose, so long as the name
   11  * of the university of michigan is not used in any advertising or publicity
   12  * pertaining to the use or distribution of this software without specific,
   13  * written prior authorization.  if the above copyright notice or any other
   14  * identification of the university of michigan is included in any copy of any
   15  * portion of this software, then the disclaimer below must also be included.
   16  * 
   17  * this software is provided as is, without representation from the university
   18  * of michigan as to its fitness for any purpose, and without warranty by the
   19  * university of michigan of any kind, either express or implied, including
   20  * without limitation the implied warranties of merchantability and fitness for
   21  * a particular purpose. the regents of the university of michigan shall not be
   22  * liable for any damages, including special, indirect, incidental, or
   23  * consequential damages, with respect to any claim arising out of or in
   24  * connection with the use of the software, even if it has been or is hereafter
   25  * advised of the possibility of such damages.
   26  */
   27 
   28 /*
   29  * Copyright (c) 1989, 1993
   30  *      The Regents of the University of California.  All rights reserved.
   31  *
   32  * This code is derived from software contributed to Berkeley by
   33  * Rick Macklem at The University of Guelph.
   34  *
   35  * Redistribution and use in source and binary forms, with or without
   36  * modification, are permitted provided that the following conditions
   37  * are met:
   38  * 1. Redistributions of source code must retain the above copyright
   39  *    notice, this list of conditions and the following disclaimer.
   40  * 2. Redistributions in binary form must reproduce the above copyright
   41  *    notice, this list of conditions and the following disclaimer in the
   42  *    documentation and/or other materials provided with the distribution.
   43  * 4. Neither the name of the University nor the names of its contributors
   44  *    may be used to endorse or promote products derived from this software
   45  *    without specific prior written permission.
   46  *
   47  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   50  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   51  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   52  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   53  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   55  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   57  * SUCH DAMAGE.
   58  *
   59  *      @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
   60  */
   61 
   62 #include <sys/cdefs.h>
   63 __FBSDID("$FreeBSD: src/sys/nfs4client/nfs4_vnops.c,v 1.6.2.1 2005/01/31 23:26:45 imp Exp $");
   64 
   65 /*
   66  * vnode op calls for Sun NFS version 2 and 3
   67  */
   68 
   69 #include "opt_inet.h"
   70 
   71 #include <sys/param.h>
   72 #include <sys/kernel.h>
   73 #include <sys/systm.h>
   74 #include <sys/resourcevar.h>
   75 #include <sys/proc.h>
   76 #include <sys/mount.h>
   77 #include <sys/bio.h>
   78 #include <sys/buf.h>
   79 #include <sys/malloc.h>
   80 #include <sys/mbuf.h>
   81 #include <sys/namei.h>
   82 #include <sys/socket.h>
   83 #include <sys/vnode.h>
   84 #include <sys/dirent.h>
   85 #include <sys/fcntl.h>
   86 #include <sys/lockf.h>
   87 #include <sys/stat.h>
   88 #include <sys/sysctl.h>
   89 #include <sys/lockmgr.h>
   90 
   91 #include <vm/vm.h>
   92 #include <vm/vm_extern.h>
   93 
   94 #include <fs/fifofs/fifo.h>
   95 
   96 #include <rpc/rpcclnt.h>
   97 
   98 #include <nfs/rpcv2.h>
   99 #include <nfs/nfsproto.h>
  100 #include <nfsclient/nfs.h>
  101 #include <nfs4client/nfs4.h>
  102 #include <nfsclient/nfsnode.h>
  103 #include <nfsclient/nfsmount.h>
  104 #include <nfsclient/nfs_lock.h>
  105 #include <nfs/xdr_subs.h>
  106 #include <nfsclient/nfsm_subs.h>
  107 
  108 #include <net/if.h>
  109 #include <netinet/in.h>
  110 #include <netinet/in_var.h>
  111 
  112 /* NFSv4 */
  113 #include <nfs4client/nfs4m_subs.h>
  114 #include <nfs4client/nfs4_vn.h>
  115 
  116 /* Defs */
  117 #define TRUE    1
  118 #define FALSE   0
  119 
  120 /*
  121  * Ifdef for FreeBSD-current merged buffer cache. It is unfortunate that these
  122  * calls are not in getblk() and brelse() so that they would not be necessary
  123  * here.
  124  */
  125 #ifndef B_VMIO
  126 #define vfs_busy_pages(bp, f)
  127 #endif
  128 
  129 static int      nfsspec_read(struct vop_read_args *);
  130 static int      nfsspec_write(struct vop_write_args *);
  131 static int      nfsfifo_read(struct vop_read_args *);
  132 static int      nfsfifo_write(struct vop_write_args *);
  133 static int      nfsspec_close(struct vop_close_args *);
  134 static int      nfsfifo_close(struct vop_close_args *);
  135 static int      nfs4_flush(struct vnode *, struct ucred *, int, struct thread *,
  136                     int);
  137 static int      nfs4_setattrrpc(struct vnode *, struct vattr *, struct ucred *,
  138                     struct thread *);
  139 static int      nfs4_closerpc(struct vnode *, struct ucred *, struct thread *, int);
  140 
  141 static  int     nfs4_lookup(struct vop_lookup_args *);
  142 static  int     nfs4_create(struct vop_create_args *);
  143 static  int     nfs4_mknod(struct vop_mknod_args *);
  144 static  int     nfs4_open(struct vop_open_args *);
  145 static  int     nfs4_close(struct vop_close_args *);
  146 static  int     nfs4_access(struct vop_access_args *);
  147 static  int     nfs4_getattr(struct vop_getattr_args *);
  148 static  int     nfs4_setattr(struct vop_setattr_args *);
  149 static  int     nfs4_read(struct vop_read_args *);
  150 static  int     nfs4_fsync(struct vop_fsync_args *);
  151 static  int     nfs4_remove(struct vop_remove_args *);
  152 static  int     nfs4_link(struct vop_link_args *);
  153 static  int     nfs4_rename(struct vop_rename_args *);
  154 static  int     nfs4_mkdir(struct vop_mkdir_args *);
  155 static  int     nfs4_rmdir(struct vop_rmdir_args *);
  156 static  int     nfs4_symlink(struct vop_symlink_args *);
  157 static  int     nfs4_readdir(struct vop_readdir_args *);
  158 static  int     nfs4_strategy(struct vop_strategy_args *);
  159 static  int     nfs4_lookitup(struct vnode *, const char *, int,
  160                     struct ucred *, struct thread *, struct nfsnode **);
  161 static  int     nfs4_sillyrename(struct vnode *, struct vnode *,
  162                     struct componentname *);
  163 static int      nfsspec_access(struct vop_access_args *);
  164 static int      nfs4_readlink(struct vop_readlink_args *);
  165 static int      nfs4_print(struct vop_print_args *);
  166 static int      nfs4_advlock(struct vop_advlock_args *);
  167 
  168 /*
  169  * Global vfs data structures for nfs
  170  */
  171 vop_t **nfs4_vnodeop_p;
  172 static struct vnodeopv_entry_desc nfs4_vnodeop_entries[] = {
  173         { &vop_default_desc,            (vop_t *) vop_defaultop },
  174         { &vop_access_desc,             (vop_t *) nfs4_access },
  175         { &vop_advlock_desc,            (vop_t *) nfs4_advlock },
  176         { &vop_close_desc,              (vop_t *) nfs4_close },
  177         { &vop_create_desc,             (vop_t *) nfs4_create },
  178         { &vop_fsync_desc,              (vop_t *) nfs4_fsync },
  179         { &vop_getattr_desc,            (vop_t *) nfs4_getattr },
  180         { &vop_getpages_desc,           (vop_t *) nfs_getpages },
  181         { &vop_putpages_desc,           (vop_t *) nfs_putpages },
  182         { &vop_inactive_desc,           (vop_t *) nfs_inactive },
  183         { &vop_lease_desc,              (vop_t *) vop_null },
  184         { &vop_link_desc,               (vop_t *) nfs4_link },
  185         { &vop_lookup_desc,             (vop_t *) nfs4_lookup },
  186         { &vop_mkdir_desc,              (vop_t *) nfs4_mkdir },
  187         { &vop_mknod_desc,              (vop_t *) nfs4_mknod },
  188         { &vop_open_desc,               (vop_t *) nfs4_open },
  189         { &vop_print_desc,              (vop_t *) nfs4_print },
  190         { &vop_read_desc,               (vop_t *) nfs4_read },
  191         { &vop_readdir_desc,            (vop_t *) nfs4_readdir },
  192         { &vop_readlink_desc,           (vop_t *) nfs4_readlink },
  193         { &vop_reclaim_desc,            (vop_t *) nfs_reclaim },
  194         { &vop_remove_desc,             (vop_t *) nfs4_remove },
  195         { &vop_rename_desc,             (vop_t *) nfs4_rename },
  196         { &vop_rmdir_desc,              (vop_t *) nfs4_rmdir },
  197         { &vop_setattr_desc,            (vop_t *) nfs4_setattr },
  198         { &vop_strategy_desc,           (vop_t *) nfs4_strategy },
  199         { &vop_symlink_desc,            (vop_t *) nfs4_symlink },
  200         { &vop_write_desc,              (vop_t *) nfs_write },
  201         { NULL, NULL }
  202 };
  203 static struct vnodeopv_desc nfs4_vnodeop_opv_desc =
  204         { &nfs4_vnodeop_p, nfs4_vnodeop_entries };
  205 VNODEOP_SET(nfs4_vnodeop_opv_desc);
  206 
  207 /*
  208  * Special device vnode ops
  209  */
  210 vop_t **spec_nfs4nodeop_p;
  211 static struct vnodeopv_entry_desc nfs4_specop_entries[] = {
  212         { &vop_default_desc,            (vop_t *) spec_vnoperate },
  213         { &vop_access_desc,             (vop_t *) nfsspec_access },
  214         { &vop_close_desc,              (vop_t *) nfsspec_close },
  215         { &vop_fsync_desc,              (vop_t *) nfs4_fsync },
  216         { &vop_getattr_desc,            (vop_t *) nfs4_getattr },
  217         { &vop_inactive_desc,           (vop_t *) nfs_inactive },
  218         { &vop_print_desc,              (vop_t *) nfs4_print },
  219         { &vop_read_desc,               (vop_t *) nfsspec_read },
  220         { &vop_reclaim_desc,            (vop_t *) nfs_reclaim },
  221         { &vop_setattr_desc,            (vop_t *) nfs4_setattr },
  222         { &vop_write_desc,              (vop_t *) nfsspec_write },
  223         { NULL, NULL }
  224 };
  225 static struct vnodeopv_desc spec_nfs4nodeop_opv_desc =
  226         { &spec_nfs4nodeop_p, nfs4_specop_entries };
  227 VNODEOP_SET(spec_nfs4nodeop_opv_desc);
  228 
  229 vop_t **fifo_nfs4nodeop_p;
  230 static struct vnodeopv_entry_desc nfs4_fifoop_entries[] = {
  231         { &vop_default_desc,            (vop_t *) fifo_vnoperate },
  232         { &vop_access_desc,             (vop_t *) nfsspec_access },
  233         { &vop_close_desc,              (vop_t *) nfsfifo_close },
  234         { &vop_fsync_desc,              (vop_t *) nfs4_fsync },
  235         { &vop_getattr_desc,            (vop_t *) nfs4_getattr },
  236         { &vop_inactive_desc,           (vop_t *) nfs_inactive },
  237         { &vop_print_desc,              (vop_t *) nfs4_print },
  238         { &vop_read_desc,               (vop_t *) nfsfifo_read },
  239         { &vop_reclaim_desc,            (vop_t *) nfs_reclaim },
  240         { &vop_setattr_desc,            (vop_t *) nfs4_setattr },
  241         { &vop_write_desc,              (vop_t *) nfsfifo_write },
  242         { NULL, NULL }
  243 };
  244 static struct vnodeopv_desc fifo_nfs4nodeop_opv_desc =
  245         { &fifo_nfs4nodeop_p, nfs4_fifoop_entries };
  246 VNODEOP_SET(fifo_nfs4nodeop_opv_desc);
  247 
  248 static int      nfs4_removerpc(struct vnode *dvp, const char *name, int namelen,
  249                               struct ucred *cred, struct thread *td);
  250 static int      nfs4_renamerpc(struct vnode *fdvp, const char *fnameptr,
  251                               int fnamelen, struct vnode *tdvp,
  252                               const char *tnameptr, int tnamelen,
  253                               struct ucred *cred, struct thread *td);
  254 static int      nfs4_renameit(struct vnode *sdvp, struct componentname *scnp,
  255                              struct sillyrename *sp);
  256 static int      nfs4_openrpc(struct vnode *, struct vnode **,
  257                             struct componentname *, int, struct vattr *);
  258 static int      nfs4_open_confirm(struct vnode *vp, struct nfs4_compound *cpp,
  259                                  struct nfs4_oparg_open *openap,
  260                                  struct nfs4_oparg_getfh *gfh,
  261                                  struct ucred *cred, struct thread *td);
  262 static int      nfs4_createrpc(struct vnode *, struct vnode **,
  263                               struct componentname *, nfstype,
  264                               struct vattr *, char *);
  265 
  266 /*
  267  * Global variables
  268  */
  269 struct nfs4_lowner nfs4_masterlowner;
  270 
  271 #define DIRHDSIZ        (sizeof (struct dirent) - (MAXNAMLEN + 1))
  272 
  273 SYSCTL_DECL(_vfs_nfs4);
  274 
  275 static int      nfsaccess_cache_timeout = NFS_MAXATTRTIMO;
  276 SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_cache_timeout, CTLFLAG_RW,
  277            &nfsaccess_cache_timeout, 0, "NFS ACCESS cache timeout");
  278 
  279 static int      nfsv3_commit_on_close = 0;
  280 SYSCTL_INT(_vfs_nfs4, OID_AUTO, nfsv3_commit_on_close, CTLFLAG_RW,
  281            &nfsv3_commit_on_close, 0, "write+commit on close, else only write");
  282 #if 0
  283 SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_cache_hits, CTLFLAG_RD,
  284            &nfsstats.accesscache_hits, 0, "NFS ACCESS cache hit count");
  285 
  286 SYSCTL_INT(_vfs_nfs4, OID_AUTO, access_cache_misses, CTLFLAG_RD,
  287            &nfsstats.accesscache_misses, 0, "NFS ACCESS cache miss count");
  288 #endif
  289 
  290 #define NFSV3ACCESS_ALL (NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY          \
  291                          | NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE     \
  292                          | NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP)
  293 static int
  294 nfs3_access_otw(struct vnode *vp, int wmode, struct thread *td,
  295     struct ucred *cred)
  296 {
  297         const int v3 = 1;
  298         u_int32_t *tl;
  299         int error = 0, attrflag;
  300 
  301         return (0);
  302 
  303         struct mbuf *mreq, *mrep = NULL, *md, *mb;
  304         caddr_t bpos, dpos;
  305         u_int32_t rmode;
  306         struct nfsnode *np = VTONFS(vp);
  307 
  308         nfsstats.rpccnt[NFSPROC_ACCESS]++;
  309         mreq = nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
  310         mb = mreq;
  311         bpos = mtod(mb, caddr_t);
  312         nfsm_fhtom(vp, v3);
  313         tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
  314         *tl = txdr_unsigned(wmode);
  315         nfsm_request(vp, NFSPROC_ACCESS, td, cred);
  316         nfsm_postop_attr(vp, attrflag);
  317         if (!error) {
  318                 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
  319                 rmode = fxdr_unsigned(u_int32_t, *tl);
  320                 np->n_mode = rmode;
  321                 np->n_modeuid = cred->cr_uid;
  322                 np->n_modestamp = time_second;
  323         }
  324         m_freem(mrep);
  325 nfsmout:
  326         return error;
  327 }
  328 
  329 /*
  330  * nfs access vnode op.
  331  * For nfs version 2, just return ok. File accesses may fail later.
  332  * For nfs version 3, use the access rpc to check accessibility. If file modes
  333  * are changed on the server, accesses might still fail later.
  334  */
  335 static int
  336 nfs4_access(struct vop_access_args *ap)
  337 {
  338         struct vnode *vp = ap->a_vp;
  339         int error = 0;
  340         u_int32_t mode, wmode;
  341         int v3 = NFS_ISV3(vp);  /* v3 \in v4 */
  342         struct nfsnode *np = VTONFS(vp);
  343         caddr_t bpos, dpos;
  344         struct mbuf *mreq, *mrep = NULL, *md, *mb;
  345         struct nfs4_compound cp;
  346         struct nfs4_oparg_access acc;
  347         struct thread *td = ap->a_td;
  348         struct ucred *cred = ap->a_cred;
  349 
  350         /*
  351          * Disallow write attempts on filesystems mounted read-only;
  352          * unless the file is a socket, fifo, or a block or character
  353          * device resident on the filesystem.
  354          */
  355         if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
  356                 switch (vp->v_type) {
  357                 case VREG:
  358                 case VDIR:
  359                 case VLNK:
  360                         return (EROFS);
  361                 default:
  362                         break;
  363                 }
  364         }
  365         /*
  366          * For nfs v3, check to see if we have done this recently, and if
  367          * so return our cached result instead of making an ACCESS call.
  368          * If not, do an access rpc, otherwise you are stuck emulating
  369          * ufs_access() locally using the vattr. This may not be correct,
  370          * since the server may apply other access criteria such as
  371          * client uid-->server uid mapping that we do not know about.
  372          */
  373         /* XXX Disable this for now; needs fixing of _access_otw() */
  374         if (0 && v3) {
  375                 if (ap->a_mode & VREAD)
  376                         mode = NFSV3ACCESS_READ;
  377                 else
  378                         mode = 0;
  379                 if (vp->v_type != VDIR) {
  380                         if (ap->a_mode & VWRITE)
  381                                 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
  382                         if (ap->a_mode & VEXEC)
  383                                 mode |= NFSV3ACCESS_EXECUTE;
  384                 } else {
  385                         if (ap->a_mode & VWRITE)
  386                                 mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
  387                                     NFSV3ACCESS_DELETE);
  388                         if (ap->a_mode & VEXEC)
  389                                 mode |= NFSV3ACCESS_LOOKUP;
  390                 }
  391                 /* XXX safety belt, only make blanket request if caching */
  392                 if (nfsaccess_cache_timeout > 0) {
  393                         wmode = NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY |
  394                             NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE |
  395                             NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP;
  396                 } else {
  397                         wmode = mode;
  398                 }
  399 
  400                 /*
  401                  * Does our cached result allow us to give a definite yes to
  402                  * this request?
  403                  */
  404                 if ((time_second < (np->n_modestamp + nfsaccess_cache_timeout)) &&
  405                     (ap->a_cred->cr_uid == np->n_modeuid) &&
  406                     ((np->n_mode & mode) == mode)) {
  407                         nfsstats.accesscache_hits++;
  408                 } else {
  409                         /*
  410                          * Either a no, or a don't know.  Go to the wire.
  411                          */
  412                         nfsstats.accesscache_misses++;
  413                         error = nfs3_access_otw(vp, wmode, ap->a_td,ap->a_cred);
  414                         if (!error) {
  415                                 if ((np->n_mode & mode) != mode) {
  416                                         error = EACCES;
  417                                 }
  418                         }
  419                 }
  420                 return (error);
  421         }
  422 
  423         /* XXX use generic access code here? */
  424         mode = ap->a_mode & VREAD ? NFSV4ACCESS_READ : 0;
  425         if (vp->v_type == VDIR) {
  426                 if (ap->a_mode & VWRITE)
  427                         mode |= NFSV4ACCESS_MODIFY | NFSV4ACCESS_EXTEND | NFSV4ACCESS_DELETE;
  428                 if (ap->a_mode & VEXEC)
  429                         mode |= NFSV4ACCESS_LOOKUP;
  430         } else {
  431                 if (ap->a_mode & VWRITE)
  432                         mode |= NFSV4ACCESS_MODIFY | NFSV4ACCESS_EXTEND;
  433                 if (ap->a_mode & VEXEC)
  434                         mode |= NFSV4ACCESS_EXECUTE;
  435         }
  436 
  437         nfs_v4initcompound(&cp);
  438         acc.mode = mode;
  439 
  440         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
  441         mb = mreq;
  442         bpos = mtod(mb, caddr_t);
  443 
  444         nfsm_v4build_compound(&cp, "nfs4_access()");
  445         nfsm_v4build_putfh(&cp, vp);
  446         nfsm_v4build_access(&cp, &acc);
  447         nfsm_v4build_finalize(&cp);
  448 
  449         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
  450         if (error != 0)
  451                 goto nfsmout;
  452 
  453         nfsm_v4dissect_compound(&cp);
  454         nfsm_v4dissect_putfh(&cp);
  455         nfsm_v4dissect_access(&cp, &acc);
  456 
  457         if ((acc.rmode & mode) != mode)
  458                 error = EACCES;
  459 
  460  nfsmout:
  461         error = nfs_v4postop(&cp, error);
  462 
  463         if (mrep != NULL)
  464                 m_freem(mrep);
  465 
  466         return (error);
  467 }
  468 
  469 static int
  470 nfs4_openrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
  471     int flags, struct vattr *vap)
  472 {
  473         struct vnode *vp = *vpp;
  474         struct nfs4_oparg_getattr getattr;
  475         struct nfs4_oparg_getfh getfh;
  476         struct nfs4_oparg_open opena;
  477         struct nfs4_compound cp;
  478         caddr_t bpos, dpos;
  479         int error = 0;
  480         struct mbuf *mreq, *mrep = NULL, *md, *mb;
  481         struct ucred *cred = cnp->cn_cred;
  482         struct thread *td = cnp->cn_thread;
  483         struct nfs4_fctx xfc, *fcp;
  484         struct nfsnode *np;
  485 
  486         if (vp == NULL) {
  487                 /* Create a new file */
  488                 np = NULL;
  489                 fcp = &xfc;
  490                 bzero(fcp, sizeof(*fcp));
  491         } else {
  492                 np = VTONFS(vp);
  493                 fcp = flags & FWRITE ? &np->n_wfc : &np->n_rfc;
  494         }
  495 
  496         /*
  497          * Since we are currently only one lockowner; we only open the
  498          * file once each for reading and writing.
  499          */
  500         if (fcp->refcnt++ != 0) {
  501                 *vpp = vp;
  502                 /*printf("not opening %s\n", np->n_name != NULL ? np->n_name : "");*/
  503                 return (0);
  504         }
  505 
  506         fcp->lop = &nfs4_masterlowner;
  507         fcp->np = np;
  508 
  509         nfs_v4initcompound(&cp);
  510         cp.nmp = VFSTONFS(dvp->v_mount);
  511 
  512         opena.ctype = NCLNULL;
  513         opena.flags = flags;
  514         opena.vap = vap;
  515         opena.fcp = fcp;                /* For lockowner */
  516         opena.cnp = cnp;
  517 
  518         getattr.bm = &nfsv4_getattrbm;
  519 
  520         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
  521         mb = mreq;
  522         bpos = mtod(mb, caddr_t);
  523 
  524         nfsm_v4build_compound(&cp, "nfs4_openrpc()");
  525         nfsm_v4build_putfh(&cp, dvp);
  526         nfsm_v4build_open(&cp, &opena);
  527         nfsm_v4build_getattr(&cp, &getattr);
  528         nfsm_v4build_getfh(&cp, &getfh);
  529         nfsm_v4build_finalize(&cp);
  530 
  531         nfsm_request(vp != NULL ? vp : dvp, NFSV4PROC_COMPOUND, td, cred);
  532         if (error != 0)
  533                 goto nfsmout;
  534 
  535         nfsm_v4dissect_compound(&cp);
  536         nfsm_v4dissect_putfh(&cp);
  537         nfsm_v4dissect_open(&cp, &opena);
  538         nfsm_v4dissect_getattr(&cp, &getattr);
  539         nfsm_v4dissect_getfh(&cp, &getfh);
  540 
  541         error = nfs_v4postop(&cp, error);
  542 
  543         if (opena.rflags & NFSV4OPENRES_CONFIRM) {
  544                 error = nfs4_open_confirm(vp ? vp : dvp, &cp, &opena, &getfh, cred, td);
  545                 if (error != 0)
  546                         goto nfsmout;
  547         }
  548 
  549         if (vp == NULL) {
  550                 /* New file */
  551                 error = nfs_nget(dvp->v_mount, &getfh.fh_val,
  552                     getfh.fh_len, &np);
  553                 if (error != 0)
  554                         goto nfsmout;
  555 
  556                 vp = NFSTOV(np);
  557                 np->n_dvp = dvp;
  558                 np->n_namelen = cnp->cn_namelen; /* XXX memory leaks on these; track! */
  559                 if (np->n_name != NULL)
  560                         FREE(np->n_name, M_NFSREQ);
  561                 MALLOC(np->n_name, u_char *, np->n_namelen + 1, M_NFSREQ, M_WAITOK);
  562                 bcopy(cnp->cn_nameptr, np->n_name, np->n_namelen);
  563                 np->n_name[np->n_namelen] = '\0';
  564                 if (flags & FWRITE)
  565                         np->n_wfc = *fcp;
  566                 else
  567                         np->n_rfc = *fcp;
  568 
  569                 /*printf("opened new file %s\n", np->n_name);*/
  570 
  571                 nfs4_vnop_loadattrcache(vp, &getattr.fa, NULL);
  572                 *vpp = vp;
  573         } else {
  574                 /*printf("openend \"old\" %s\n", np->n_name != NULL ? np->n_name : "");*/
  575 
  576                 if (flags & O_TRUNC && np->n_size != 0) {
  577                         struct vattr va;
  578 
  579                         VATTR_NULL(&va);
  580                         va.va_size = 0;
  581                         error = nfs4_setattrrpc(vp, &va,
  582                             cnp->cn_cred, cnp->cn_thread);
  583                 }
  584                 np->n_attrstamp = 0;
  585         }
  586 
  587  nfsmout:
  588         if (mrep != NULL)
  589                 m_freem(mrep);
  590 
  591         return (error);
  592 }
  593 
  594 static int
  595 nfs4_open_confirm(struct vnode *vp, struct nfs4_compound *cpp,
  596     struct nfs4_oparg_open *openap, struct nfs4_oparg_getfh *gfh,
  597     struct ucred *cred, struct thread *td)
  598 {
  599         caddr_t bpos, dpos;
  600         int error = 0;
  601         struct mbuf *mreq, *mrep = NULL, *md, *mb;
  602 
  603         nfs_v4initcompound(cpp);
  604         cpp->nmp = VFSTONFS(vp->v_mount);
  605 
  606         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
  607         mb = mreq;
  608         bpos = mtod(mb, caddr_t);
  609 
  610         nfsm_v4build_compound(cpp, "nfs4_open_confirm()");
  611         nfsm_v4build_putfh_nv(cpp, gfh);
  612         nfsm_v4build_open_confirm(cpp, openap);
  613         nfsm_v4build_finalize(cpp);
  614 
  615         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
  616         if (error != 0)
  617                 goto nfsmout;
  618 
  619         nfsm_v4dissect_compound(cpp);
  620         nfsm_v4dissect_putfh(cpp);
  621         nfsm_v4dissect_open_confirm(cpp, openap);
  622 
  623  nfsmout:
  624         error = nfs_v4postop(cpp, error);
  625 
  626         if (mrep != NULL)
  627                 m_freem(mrep);
  628 
  629         return (error);
  630 }
  631 
  632 
  633 /*
  634  * nfs open vnode op
  635  * Check to see if the type is ok
  636  * and that deletion is not in progress.
  637  * For paged in text files, you will need to flush the page cache
  638  * if consistency is lost.
  639  */
  640 /* ARGSUSED */
  641 static int
  642 nfs4_open(struct vop_open_args *ap)
  643 {
  644         struct vnode *vp = ap->a_vp;
  645         struct nfsnode *np = VTONFS(vp);
  646         enum vtype vtype = vp->v_type;
  647         int mode = ap->a_mode;
  648         struct componentname cn;
  649 
  650         if (vtype != VREG) {
  651                 if (vtype != VDIR && vtype != VLNK) {
  652 #ifdef DIAGNOSTIC
  653                         printf("open eacces vtyp=%d\n", vp->v_type);
  654 #endif
  655                         return (EACCES);
  656                 } else
  657                         return (0);
  658         }
  659 
  660         if (np->n_flag & NCREATED) {
  661                 np->n_flag &= ~NCREATED;
  662                 return (0);
  663         }
  664 
  665         cn.cn_nameptr = np->n_name;
  666         cn.cn_namelen = np->n_namelen;
  667         cn.cn_cred = ap->a_cred;
  668         cn.cn_thread = ap->a_td;
  669 
  670         return (nfs4_openrpc(np->n_dvp, &vp, &cn, mode, NULL));
  671 }
  672 
  673 static int
  674 nfs4_closerpc(struct vnode *vp, struct ucred *cred, struct thread *td, int flags)
  675 {
  676         caddr_t bpos, dpos;
  677         int error = 0;
  678         struct mbuf *mreq, *mrep = NULL, *md, *mb;
  679         struct nfs4_fctx *fcp;
  680         struct nfs4_compound cp;
  681         struct nfsnode *np = VTONFS(vp);
  682 
  683         fcp = flags & FWRITE ? &np->n_wfc : &np->n_rfc;
  684 
  685         nfs_v4initcompound(&cp);
  686 
  687         if (--fcp->refcnt != 0)
  688                 return (0);
  689 
  690         /*printf("closing %s\n", np->n_name != NULL ? np->n_name : "");*/
  691 
  692         cp.fcp = fcp;
  693 
  694         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
  695         mb = mreq;
  696         bpos = mtod(mb, caddr_t);
  697 
  698         nfsm_v4build_compound(&cp, "nfs4_closerpc()");
  699         nfsm_v4build_putfh(&cp, vp);
  700         nfsm_v4build_close(&cp, fcp);
  701         nfsm_v4build_finalize(&cp);
  702 
  703         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
  704         if (error != 0)
  705                 goto nfsmout;
  706 
  707         nfsm_v4dissect_compound(&cp);
  708         nfsm_v4dissect_putfh(&cp);
  709         nfsm_v4dissect_close(&cp, fcp);
  710 
  711  nfsmout:
  712         error = nfs_v4postop(&cp, error);
  713 
  714         if (mrep != NULL)
  715                 m_freem(mrep);
  716 
  717         return (error);
  718 }
  719 
  720 /*
  721  * nfs close vnode op
  722  * play it safe for now (see comments in v2/v3 nfs_close regarding dirty buffers)
  723  */
  724 /* ARGSUSED */
  725 static int
  726 nfs4_close(struct vop_close_args *ap)
  727 {
  728         struct vnode *vp = ap->a_vp;
  729         struct nfsnode *np = VTONFS(vp);
  730         int error = 0;
  731 
  732         if (vp->v_type != VREG)
  733                 return (0);
  734 
  735         if (np->n_flag & NMODIFIED) {
  736                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_td);
  737                 error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1);
  738                 VOP_UNLOCK(vp, 0, ap->a_td);
  739                 np->n_attrstamp = 0;
  740         }
  741 
  742         error = nfs4_closerpc(vp, ap->a_cred, ap->a_td, ap->a_fflag);
  743 
  744         if (!error && np->n_flag & NWRITEERR) {
  745                 np->n_flag &= ~NWRITEERR;
  746                 error = np->n_error;
  747         }
  748         return (error);
  749 }
  750 
  751 /*
  752  * nfs getattr call from vfs.
  753  */
  754 static int
  755 nfs4_getattr(struct vop_getattr_args *ap)
  756 {
  757         struct vnode *vp = ap->a_vp;
  758         struct nfsnode *np = VTONFS(vp);
  759         caddr_t bpos, dpos;
  760         int error = 0;
  761         struct mbuf *mreq, *mrep = NULL, *md, *mb;
  762         struct nfs4_oparg_getattr ga;
  763         struct nfs4_compound cp;
  764 
  765         /*
  766          * Update local times for special files.
  767          */
  768         if (np->n_flag & (NACC | NUPD))
  769                 np->n_flag |= NCHG;
  770         /*
  771          * First look in the cache.
  772          */
  773         if (nfs_getattrcache(vp, ap->a_vap) == 0)
  774                 return (0);
  775 
  776         nfsstats.rpccnt[NFSPROC_GETATTR]++;
  777 
  778         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, NFSX_FH(1));
  779         mb = mreq;
  780         bpos = mtod(mb, caddr_t);
  781 
  782         ga.bm = &nfsv4_getattrbm;
  783         nfs_v4initcompound(&cp);
  784 
  785         nfsm_v4build_compound(&cp, "nfs4_getattr()");
  786         nfsm_v4build_putfh(&cp, vp);
  787         nfsm_v4build_getattr(&cp, &ga);
  788         nfsm_v4build_finalize(&cp);
  789 
  790         nfsm_request(vp, NFSV4PROC_COMPOUND, ap->a_td, ap->a_cred);
  791         if (error != 0)
  792                 goto nfsmout;
  793 
  794         nfsm_v4dissect_compound(&cp);
  795         nfsm_v4dissect_putfh(&cp);
  796         nfsm_v4dissect_getattr(&cp, &ga);
  797 
  798         nfs4_vnop_loadattrcache(vp, &ga.fa, ap->a_vap);
  799 
  800 nfsmout:
  801         error = nfs_v4postop(&cp, error);
  802 
  803         if (mrep != NULL)
  804                 m_freem(mrep);
  805         return (error);
  806 }
  807 
  808 /*
  809  * nfs setattr call.
  810  */
  811 static int
  812 nfs4_setattr(struct vop_setattr_args *ap)
  813 {
  814         struct vnode *vp = ap->a_vp;
  815         struct nfsnode *np = VTONFS(vp);
  816         struct vattr *vap = ap->a_vap;
  817         int error = 0;
  818         u_quad_t tsize;
  819 
  820 #ifndef nolint
  821         tsize = (u_quad_t)0;
  822 #endif
  823 
  824         /*
  825          * Setting of flags is not supported.
  826          */
  827         if (vap->va_flags != VNOVAL)
  828                 return (EOPNOTSUPP);
  829 
  830         /*
  831          * Disallow write attempts if the filesystem is mounted read-only.
  832          */
  833         if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
  834             vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
  835             vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
  836             (vp->v_mount->mnt_flag & MNT_RDONLY))
  837                 return (EROFS);
  838         if (vap->va_size != VNOVAL) {
  839                 switch (vp->v_type) {
  840                 case VDIR:
  841                         return (EISDIR);
  842                 case VCHR:
  843                 case VBLK:
  844                 case VSOCK:
  845                 case VFIFO:
  846                         if (vap->va_mtime.tv_sec == VNOVAL &&
  847                             vap->va_atime.tv_sec == VNOVAL &&
  848                             vap->va_mode == (mode_t)VNOVAL &&
  849                             vap->va_uid == (uid_t)VNOVAL &&
  850                             vap->va_gid == (gid_t)VNOVAL)
  851                                 return (0);
  852                         vap->va_size = VNOVAL;
  853                         break;
  854                 default:
  855                         /*
  856                          * Disallow write attempts if the filesystem is
  857                          * mounted read-only.
  858                          */
  859                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  860                                 return (EROFS);
  861 
  862                         /*
  863                          *  We run vnode_pager_setsize() early (why?),
  864                          * we must set np->n_size now to avoid vinvalbuf
  865                          * V_SAVE races that might setsize a lower
  866                          * value.
  867                          */
  868 
  869                         tsize = np->n_size;
  870                         error = nfs_meta_setsize(vp, ap->a_cred, 
  871                                                 ap->a_td, vap->va_size);
  872 
  873                         if (np->n_flag & NMODIFIED) {
  874                             if (vap->va_size == 0)
  875                                 error = nfs_vinvalbuf(vp, 0,
  876                                         ap->a_cred, ap->a_td, 1);
  877                             else
  878                                 error = nfs_vinvalbuf(vp, V_SAVE,
  879                                         ap->a_cred, ap->a_td, 1);
  880                             if (error) {
  881                                 vnode_pager_setsize(vp, np->n_size);
  882                                 return (error);
  883                             }
  884                         }
  885                         /*
  886                          * np->n_size has already been set to vap->va_size
  887                          * in nfs_meta_setsize(). We must set it again since
  888                          * nfs_loadattrcache() could be called through
  889                          * nfs_meta_setsize() and could modify np->n_size.
  890                          */
  891                         np->n_vattr.va_size = np->n_size = vap->va_size;
  892                 };
  893         } else if ((vap->va_mtime.tv_sec != VNOVAL ||
  894                 vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
  895                 vp->v_type == VREG &&
  896                 (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
  897                  ap->a_td, 1)) == EINTR)
  898                 return (error);
  899 
  900         if (vap->va_size != VNOVAL && np->n_wfc.refcnt == 0) {
  901                 /* Have to open the file before we can truncate it */
  902                 struct componentname cn;
  903 
  904                 cn.cn_nameptr = np->n_name;
  905                 cn.cn_namelen = np->n_namelen;
  906                 cn.cn_cred = ap->a_cred;
  907                 cn.cn_thread = ap->a_td;
  908                 error = nfs4_openrpc(np->n_dvp, &vp, &cn, FWRITE, NULL);
  909                 if (error)
  910                         return error;
  911                 np->n_flag |= NTRUNCATE;
  912         }
  913 
  914         error = nfs4_setattrrpc(vp, vap, ap->a_cred, ap->a_td);
  915         if (error && vap->va_size != VNOVAL) {
  916                 np->n_size = np->n_vattr.va_size = tsize;
  917                 vnode_pager_setsize(vp, np->n_size);
  918         }
  919         return (error);
  920 }
  921 
  922 /*
  923  * Do an nfs setattr rpc.
  924  */
  925 static int
  926 nfs4_setattrrpc(struct vnode *vp, struct vattr *vap, struct ucred *cred,
  927     struct thread *td)
  928 {
  929         caddr_t bpos, dpos;
  930         int error = 0;
  931         struct mbuf *mreq, *mrep = NULL, *md, *mb;
  932         struct nfs4_compound cp;
  933         struct nfs4_oparg_getattr ga;
  934         struct nfsnode *np = VTONFS(vp);
  935         struct nfs4_fctx *fcp;
  936 
  937         nfsstats.rpccnt[NFSPROC_SETATTR]++;
  938         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
  939         mb = mreq;
  940         bpos = mtod(mb, caddr_t);
  941 
  942         ga.bm = &nfsv4_getattrbm;
  943         fcp = (vap->va_size != VNOVAL) ? &np->n_wfc : NULL;
  944         nfs_v4initcompound(&cp);
  945 
  946         nfsm_v4build_compound(&cp, "nfs4_setattrrpc");
  947         nfsm_v4build_putfh(&cp, vp);
  948         nfsm_v4build_setattr(&cp, vap, fcp);
  949         nfsm_v4build_getattr(&cp, &ga);
  950         nfsm_v4build_finalize(&cp);
  951 
  952         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
  953         if (error != 0)
  954                 goto nfsmout;
  955 
  956         nfsm_v4dissect_compound(&cp);
  957         nfsm_v4dissect_putfh(&cp);
  958         nfsm_v4dissect_setattr(&cp);
  959         nfsm_v4dissect_getattr(&cp, &ga);
  960 
  961         nfs4_vnop_loadattrcache(vp, &ga.fa, NULL);
  962 
  963         /* TODO: do the settatr and close in a single compound rpc */
  964         if (np->n_flag & NTRUNCATE) {
  965                 error = nfs4_closerpc(vp, cred, td, FWRITE);
  966                 np->n_flag &= ~NTRUNCATE;
  967         }
  968 
  969 nfsmout:
  970         error = nfs_v4postop(&cp, error);
  971 
  972         if (mrep != NULL)
  973                 m_freem(mrep);
  974         
  975         return (error);
  976 }
  977 
  978 /*
  979  * nfs lookup call, one step at a time...
  980  * First look in cache
  981  * If not found, unlock the directory nfsnode and do the rpc
  982  */
  983 static int
  984 nfs4_lookup(struct vop_lookup_args *ap)
  985 {
  986         struct componentname *cnp = ap->a_cnp;
  987         struct vnode *dvp = ap->a_dvp;
  988         struct vnode **vpp = ap->a_vpp;
  989         int isdot, flags = cnp->cn_flags;
  990         struct vnode *newvp;
  991         struct nfsmount *nmp;
  992         caddr_t bpos, dpos;
  993         struct mbuf *mreq, *mrep = NULL, *md, *mb;
  994         long len;
  995         nfsfh_t *fhp;
  996         struct nfsnode *np;
  997         int lockparent, wantparent, error = 0, fhsize;
  998         struct thread *td = cnp->cn_thread;
  999         struct nfs4_compound cp;
 1000         struct nfs4_oparg_getattr ga, dga;
 1001         struct nfs4_oparg_lookup l;
 1002         struct nfs4_oparg_getfh gfh;
 1003 
 1004         *vpp = NULLVP;
 1005         cnp->cn_flags &= ~PDIRUNLOCK;
 1006         if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
 1007             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
 1008                 return (EROFS);
 1009         if (dvp->v_type != VDIR)
 1010                 return (ENOTDIR);
 1011         lockparent = flags & LOCKPARENT;
 1012         wantparent = flags & (LOCKPARENT|WANTPARENT);
 1013         nmp = VFSTONFS(dvp->v_mount);
 1014         np = VTONFS(dvp);
 1015 
 1016         isdot = cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.';
 1017 
 1018         if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
 1019                 struct vattr vattr;
 1020                 int vpid;
 1021 
 1022                 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) {
 1023                         *vpp = NULLVP;
 1024                         return (error);
 1025                 }
 1026 
 1027                 vhold(*vpp);
 1028                 newvp = *vpp;
 1029                 vpid = newvp->v_id;
 1030                 /*
 1031                  * See the comment starting `Step through' in ufs/ufs_lookup.c
 1032                  * for an explanation of the locking protocol
 1033                  */
 1034                 if (dvp == newvp) {
 1035                         VREF(newvp);
 1036                         error = 0;
 1037                 } else if (flags & ISDOTDOT) {
 1038                         VOP_UNLOCK(dvp, 0, td);
 1039                         cnp->cn_flags |= PDIRUNLOCK;
 1040                         error = vget(newvp, LK_EXCLUSIVE, td);
 1041                         if (!error && lockparent && (flags & ISLASTCN)) {
 1042                                 error = vn_lock(dvp, LK_EXCLUSIVE, td);
 1043                                 if (error == 0)
 1044                                         cnp->cn_flags &= ~PDIRUNLOCK;
 1045                         }
 1046                 } else {
 1047                         error = vget(newvp, LK_EXCLUSIVE, td);
 1048                         if (!lockparent || error || !(flags & ISLASTCN)) {
 1049                                 VOP_UNLOCK(dvp, 0, td);
 1050                                 cnp->cn_flags |= PDIRUNLOCK;
 1051                         }
 1052                 }
 1053                 if (!error) {
 1054                         if (vpid == newvp->v_id) {
 1055                            if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, td)
 1056                             && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
 1057                                 nfsstats.lookupcache_hits++;
 1058                                 if (cnp->cn_nameiop != LOOKUP &&
 1059                                     (flags & ISLASTCN))
 1060                                         cnp->cn_flags |= SAVENAME;
 1061                                 vdrop(newvp);
 1062                                 return (0);
 1063                            }
 1064                            cache_purge(newvp);
 1065                         }
 1066                         vput(newvp);
 1067                         if (lockparent && dvp != newvp && (flags & ISLASTCN))
 1068                                 VOP_UNLOCK(dvp, 0, td);
 1069                 }
 1070                 vdrop(newvp);
 1071                 error = vn_lock(dvp, LK_EXCLUSIVE, td);
 1072                 *vpp = NULLVP;
 1073                 if (error) {
 1074                         cnp->cn_flags |= PDIRUNLOCK;
 1075                         return (error);
 1076                 }
 1077                 cnp->cn_flags &= ~PDIRUNLOCK;
 1078         }
 1079 
 1080         error = 0;
 1081         newvp = NULLVP;
 1082         nfsstats.lookupcache_misses++;
 1083         nfsstats.rpccnt[NFSPROC_LOOKUP]++;
 1084 
 1085         len = cnp->cn_namelen;
 1086         mreq = nfsm_reqhead(NULL, NFSV4PROC_COMPOUND, 0);
 1087         mb = mreq;
 1088         bpos = mtod(mb, caddr_t);
 1089 
 1090         ga.bm = &nfsv4_getattrbm;
 1091         dga.bm = &nfsv4_getattrbm;
 1092         nfs_v4initcompound(&cp);
 1093 
 1094         nfsm_v4build_compound(&cp, "nfs4_lookup()");
 1095         nfsm_v4build_putfh(&cp, dvp);
 1096         nfsm_v4build_getattr(&cp, &dga);
 1097         if (flags & ISDOTDOT)
 1098                 nfsm_v4build_lookupp(&cp);
 1099         else if (!isdot) {
 1100                 l.name = cnp->cn_nameptr;
 1101                 l.namelen = len;
 1102                 nfsm_v4build_lookup(&cp, &l);
 1103         }
 1104         nfsm_v4build_getattr(&cp, &ga);
 1105         nfsm_v4build_getfh(&cp, &gfh);
 1106         nfsm_v4build_finalize(&cp);
 1107 
 1108         nfsm_request(dvp, NFSV4PROC_COMPOUND, cnp->cn_thread, cnp->cn_cred);
 1109         if (error != 0)
 1110                 goto nfsmout;
 1111 
 1112         nfsm_v4dissect_compound(&cp);
 1113         nfsm_v4dissect_putfh(&cp);
 1114         nfsm_v4dissect_getattr(&cp, &dga);
 1115         if (flags & ISDOTDOT)
 1116                 nfsm_v4dissect_lookupp(&cp);
 1117         else if (!isdot)
 1118                 nfsm_v4dissect_lookup(&cp);
 1119         nfsm_v4dissect_getattr(&cp, &ga);
 1120         nfsm_v4dissect_getfh(&cp, &gfh);
 1121 
 1122         nfs4_vnop_loadattrcache(dvp, &dga.fa, NULL);
 1123         fhp = &gfh.fh_val;
 1124         fhsize = gfh.fh_len;
 1125 
 1126         /*
 1127          * Handle RENAME case...
 1128          */
 1129         if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
 1130                 if (NFS_CMPFH(np, fhp, fhsize))
 1131                         return (EISDIR);
 1132 
 1133                 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
 1134                 if (error)
 1135                         return (error);
 1136 
 1137                 newvp = NFSTOV(np);
 1138 
 1139                 nfs4_vnop_loadattrcache(newvp, &ga.fa, NULL);
 1140 
 1141                 *vpp = newvp;
 1142                 cnp->cn_flags |= SAVENAME;
 1143                 if (!lockparent) {
 1144                         VOP_UNLOCK(dvp, 0, td);
 1145                         cnp->cn_flags |= PDIRUNLOCK;
 1146                 }
 1147                 return (0);
 1148         }
 1149 
 1150         if (flags & ISDOTDOT) {
 1151                 VOP_UNLOCK(dvp, 0, td);
 1152 
 1153                 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
 1154                 if (error) {
 1155                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
 1156                         return (error);
 1157                 }
 1158                 newvp = NFSTOV(np);
 1159 
 1160                 nfs4_vnop_loadattrcache(newvp, &ga.fa, NULL);
 1161 
 1162                 if (lockparent && (flags & ISLASTCN)) {
 1163                         error = vn_lock(dvp, LK_EXCLUSIVE, td);
 1164                         if (error) {
 1165                                 cnp->cn_flags |= PDIRUNLOCK;
 1166                                 vput(newvp);
 1167                                 return (error);
 1168                         }
 1169                 } else
 1170                         cnp->cn_flags |= PDIRUNLOCK;
 1171         } else if (NFS_CMPFH(np, fhp, fhsize)) {
 1172                 VREF(dvp);
 1173                 newvp = dvp;
 1174         } else {
 1175                 error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
 1176                 if (error)
 1177                         return (error);
 1178 
 1179                 if (!lockparent || !(flags & ISLASTCN)) {
 1180                         cnp->cn_flags |= PDIRUNLOCK;
 1181                         VOP_UNLOCK(dvp, 0, td);
 1182                 }
 1183                 newvp = NFSTOV(np);
 1184 
 1185                 /* Fill in np used by open. */
 1186                 np->n_dvp = dvp;
 1187                 np->n_namelen = cnp->cn_namelen;
 1188                 if (np->n_name != NULL)
 1189                         FREE(np->n_name, M_NFSREQ);
 1190                 MALLOC(np->n_name, u_char *, np->n_namelen + 1, M_NFSREQ, M_WAITOK);
 1191                 bcopy(cnp->cn_nameptr, np->n_name, np->n_namelen);
 1192                 np->n_name[np->n_namelen] = '\0';
 1193 
 1194                 nfs4_vnop_loadattrcache(newvp, &ga.fa, NULL);
 1195         }
 1196 
 1197         if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
 1198                 cnp->cn_flags |= SAVENAME;
 1199         if ((cnp->cn_flags & MAKEENTRY) &&
 1200             (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
 1201                 np->n_ctime = np->n_vattr.va_ctime.tv_sec;
 1202                 cache_enter(dvp, newvp, cnp);
 1203         }
 1204         *vpp = newvp;
 1205         m_freem(mrep);
 1206 nfsmout:
 1207         error = nfs_v4postop(&cp, error);
 1208 
 1209         if (error) {
 1210                 if (newvp != NULLVP) {
 1211                         vrele(newvp);
 1212                         *vpp = NULLVP;
 1213                 }
 1214                 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
 1215                     (flags & ISLASTCN) && error == ENOENT) {
 1216                         if (!lockparent) {
 1217                                 VOP_UNLOCK(dvp, 0, td);
 1218                                 cnp->cn_flags |= PDIRUNLOCK;
 1219                         }
 1220                         if (dvp->v_mount->mnt_flag & MNT_RDONLY)
 1221                                 error = EROFS;
 1222                         else
 1223                                 error = EJUSTRETURN;
 1224                 }
 1225                 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
 1226                         cnp->cn_flags |= SAVENAME;
 1227         }
 1228 
 1229         return (error);
 1230 }
 1231 
 1232 /*
 1233  * nfs read call.
 1234  * Just call nfs_bioread() to do the work.
 1235  */
 1236 static int
 1237 nfs4_read(struct vop_read_args *ap)
 1238 {
 1239         struct vnode *vp = ap->a_vp;
 1240 
 1241         switch (vp->v_type) {
 1242         case VREG:
 1243                 return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
 1244         case VDIR:
 1245                 return (EISDIR);
 1246         default:
 1247                 return (EOPNOTSUPP);
 1248         }
 1249 }
 1250 
 1251 /*
 1252  * nfs readlink call
 1253  */
 1254 static int
 1255 nfs4_readlink(struct vop_readlink_args *ap)
 1256 {
 1257         struct vnode *vp = ap->a_vp;
 1258 
 1259         if (vp->v_type != VLNK)
 1260                 return (EINVAL);
 1261         return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
 1262 }
 1263 
 1264 /*
 1265  * Do a readlink rpc.
 1266  * Called by nfs_doio() from below the buffer cache.
 1267  */
 1268 int
 1269 nfs4_readlinkrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred)
 1270 {
 1271         caddr_t bpos, dpos;
 1272         int error = 0;
 1273         struct mbuf *mreq, *mrep = NULL, *md, *mb;
 1274         struct nfs4_compound cp;
 1275 
 1276         nfsstats.rpccnt[NFSPROC_READLINK]++;
 1277 
 1278         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
 1279         mb = mreq;
 1280         bpos = mtod(mb, caddr_t);
 1281 
 1282         nfs_v4initcompound(&cp);
 1283 
 1284         nfsm_v4build_compound(&cp, "nfs4_readlinkrpc()");
 1285         nfsm_v4build_putfh(&cp, vp);
 1286         nfsm_v4build_readlink(&cp);
 1287         nfsm_v4build_finalize(&cp);
 1288 
 1289         nfsm_request(vp, NFSV4PROC_COMPOUND, uiop->uio_td, cred);
 1290         if (error != 0)
 1291                 goto nfsmout;
 1292 
 1293         nfsm_v4dissect_compound(&cp);
 1294         nfsm_v4dissect_putfh(&cp);
 1295         nfsm_v4dissect_readlink(&cp, uiop);
 1296 
 1297 nfsmout:
 1298         error = nfs_v4postop(&cp, error);
 1299 
 1300         if (m_freem != NULL)
 1301                 m_freem(mrep);
 1302         return (error);
 1303 }
 1304 
 1305 /*
 1306  * nfs read rpc call
 1307  * Ditto above
 1308  */
 1309 int
 1310 nfs4_readrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred)
 1311 {
 1312         caddr_t bpos, dpos;
 1313         struct mbuf *mreq, *mrep = NULL, *md, *mb;
 1314         struct nfsmount *nmp;
 1315         int error = 0, len, tsiz;
 1316         struct nfs4_compound cp;
 1317         struct nfs4_oparg_read read;
 1318         struct nfsnode *np = VTONFS(vp);
 1319 
 1320         nmp = VFSTONFS(vp->v_mount);
 1321         tsiz = uiop->uio_resid;
 1322         if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize)
 1323                 return (EFBIG);
 1324 
 1325         if (tsiz == 0)
 1326                 return (0);
 1327 
 1328         read.uiop = uiop;
 1329         read.fcp = np->n_rfc.refcnt > 0 ? &np->n_rfc : &np->n_wfc;
 1330 
 1331         while (tsiz > 0) {
 1332                 nfsstats.rpccnt[NFSPROC_READ]++;
 1333                 len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
 1334 
 1335                 read.off = uiop->uio_offset;
 1336                 read.maxcnt = len;
 1337                 nfs_v4initcompound(&cp);
 1338 
 1339                 mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
 1340                 mb = mreq;
 1341                 bpos = mtod(mb, caddr_t);
 1342 
 1343                 nfsm_v4build_compound(&cp, "nfs4_readrpc()");
 1344                 nfsm_v4build_putfh(&cp, vp);
 1345                 nfsm_v4build_read(&cp, &read);
 1346                 nfsm_v4build_finalize(&cp);
 1347 
 1348                 nfsm_request(vp, NFSV4PROC_COMPOUND, uiop->uio_td, cred);
 1349                 if (error != 0) {
 1350                         error = nfs_v4postop(&cp, error);
 1351                         goto nfsmout;
 1352                 }
 1353 
 1354                 nfsm_v4dissect_compound(&cp);
 1355                 nfsm_v4dissect_putfh(&cp);
 1356                 nfsm_v4dissect_read(&cp, &read);
 1357 
 1358                 if (read.eof || read.retlen == 0)
 1359                         tsiz = 0;
 1360                 else
 1361                         tsiz -= read.retlen;
 1362 
 1363                 error = nfs_v4postop(&cp, error);
 1364 
 1365                 m_freem(mrep);
 1366                 mrep = NULL;
 1367         }
 1368 nfsmout:
 1369         if (mrep != NULL)
 1370                 m_freem(mrep);
 1371         
 1372         return (error);
 1373 }
 1374 
 1375 /*
 1376  * nfs write call
 1377  */
 1378 int
 1379 nfs4_writerpc(struct vnode *vp, struct uio *uiop, struct ucred *cred,
 1380     int *iomode, int *must_commit)
 1381 {
 1382         int32_t backup;
 1383         caddr_t bpos, dpos;
 1384         struct mbuf *mreq, *mrep = NULL, *md, *mb;
 1385         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 1386         int error = 0, len, tsiz, wccflag = 1, rlen;
 1387         struct nfs4_compound cp;
 1388         struct nfs4_oparg_write write;
 1389         nfsv4stablehow commit, committed = NSHFILESYNC;
 1390         caddr_t verf;
 1391         struct nfsnode *np = VTONFS(vp);
 1392 
 1393 #ifndef DIAGNOSTIC
 1394         if (uiop->uio_iovcnt != 1)
 1395                 panic("nfs: writerpc iovcnt > 1");
 1396 #endif
 1397         *must_commit = 0;
 1398         tsiz = uiop->uio_resid;
 1399         if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize)
 1400                 return (EFBIG);
 1401 
 1402         if (tsiz == 0)
 1403                 return (0);
 1404 
 1405         write.stable = (nfsv4stablehow)*iomode;
 1406         write.uiop = uiop;
 1407         write.fcp = &np->n_wfc;
 1408 
 1409         while (tsiz > 0) {
 1410                 nfsstats.rpccnt[NFSPROC_WRITE]++;
 1411                 len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
 1412 
 1413                 write.off = uiop->uio_offset;
 1414                 write.cnt = len;
 1415                 nfs_v4initcompound(&cp);
 1416 
 1417                 mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
 1418                 mb = mreq;
 1419                 bpos = mtod(mb, caddr_t);
 1420 
 1421                 nfsm_v4build_compound(&cp, "nfs4_writerpc()");
 1422                 nfsm_v4build_putfh(&cp, vp);
 1423                 nfsm_v4build_write(&cp, &write);
 1424                 nfsm_v4build_finalize(&cp);
 1425 
 1426                 nfsm_request(vp, NFSV4PROC_COMPOUND, uiop->uio_td, cred);
 1427                 if (error != 0) {
 1428                         error = nfs_v4postop(&cp, error);
 1429                         goto nfsmout;
 1430                 }
 1431 
 1432                 nfsm_v4dissect_compound(&cp);
 1433                 nfsm_v4dissect_putfh(&cp);
 1434                 nfsm_v4dissect_write(&cp, &write);
 1435 
 1436                 rlen = write.retlen;
 1437                 if (rlen == 0) {
 1438                         error = NFSERR_IO;
 1439                         break;
 1440                 } else if (rlen < len) {
 1441                         backup = len - rlen;
 1442                         uiop->uio_iov->iov_base =
 1443                             (char *)uiop->uio_iov->iov_base -  backup;
 1444                         uiop->uio_iov->iov_len += backup;
 1445                         uiop->uio_offset -= backup;
 1446                         uiop->uio_resid += backup;
 1447                         len = rlen;
 1448                 }
 1449 
 1450                 commit = write.committed;
 1451 
 1452                 if (committed == NSHFILESYNC ||
 1453                     (committed = NSHDATASYNC && commit == NSHUNSTABLE))
 1454                         committed = commit;
 1455 
 1456                 verf = (caddr_t)write.wverf;
 1457 
 1458                 if ((nmp->nm_flag & NFSSTA_HASWRITEVERF) == 0) {
 1459                         bcopy(verf, nmp->nm_verf, NFSX_V4VERF);
 1460                         nmp->nm_flag |= NFSMNT_HASWRITEVERF;
 1461                 } else if (bcmp(verf, nmp->nm_verf, NFSX_V4VERF)) {
 1462                         *must_commit = 1;
 1463                         bcopy(verf, nmp->nm_verf, NFSX_V4VERF);
 1464                 }
 1465 
 1466                 /* XXX wccflag */
 1467                 if (wccflag)
 1468                         VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
 1469 
 1470                 error = nfs_v4postop(&cp, error);
 1471 
 1472                 m_freem(mrep);
 1473                 mrep = NULL;
 1474                 if (error)
 1475                         break;
 1476                 tsiz -= len;
 1477         }
 1478 nfsmout:
 1479         if (mrep != NULL)
 1480                 m_freem(mrep);
 1481         *iomode = committed;
 1482         if (error)
 1483                 uiop->uio_resid = tsiz;
 1484         return (error);
 1485 }
 1486 
 1487 /* ARGSUSED */
 1488 static int
 1489 nfs4_mknod(struct vop_mknod_args *ap)
 1490 {
 1491         struct vattr *vap = ap->a_vap;
 1492         struct vnode *newvp = NULL;
 1493         int error;
 1494 
 1495         error = nfs4_createrpc(ap->a_dvp, &newvp,
 1496             ap->a_cnp, (nfstype)vap->va_type, vap, NULL);
 1497 
 1498         /* XXX - is this actually referenced here? */
 1499         if (error == 0) {
 1500                 *ap->a_vpp = newvp;
 1501                 vrele(newvp);
 1502         }
 1503 
 1504         return (error);
 1505 }
 1506 
 1507 static int
 1508 nfs4_createrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
 1509     nfstype ftype, struct vattr *vap, char *linktarget)
 1510 {
 1511         struct nfsnode *dnp = VTONFS(dvp);
 1512         struct nfsnode *np = NULL;
 1513         struct vnode *newvp = NULL;
 1514         struct nfs4_compound cp;
 1515         struct nfs4_oparg_create c;
 1516         struct nfs4_oparg_getattr ga;
 1517         struct nfs4_oparg_getfh gfh;
 1518         caddr_t bpos, dpos;
 1519         struct mbuf *mreq, *mrep = NULL, *md, *mb;
 1520         int error = 0;
 1521 
 1522         nfsstats.rpccnt[NFSPROC_CREATE]++;
 1523 
 1524         mreq = nfsm_reqhead(dvp, NFSV4PROC_COMPOUND, 0);
 1525         mb = mreq;
 1526         bpos = mtod(mb, caddr_t);
 1527 
 1528         bzero(&c, sizeof(c));
 1529         bzero(&ga, sizeof(ga));
 1530 
 1531         c.type = ftype;
 1532         c.vap = vap;
 1533         c.linktext = linktarget;
 1534         c.name = cnp->cn_nameptr;
 1535         c.namelen = cnp->cn_namelen;
 1536 
 1537         ga.bm = &nfsv4_getattrbm;
 1538         nfs_v4initcompound(&cp);
 1539 
 1540         nfsm_v4build_compound(&cp, "nfs4_createrpc()");
 1541         nfsm_v4build_putfh(&cp, dvp);
 1542         nfsm_v4build_create(&cp, &c);
 1543         nfsm_v4build_getattr(&cp, &ga);
 1544         nfsm_v4build_getfh(&cp, &gfh);  
 1545         nfsm_v4build_finalize(&cp); 
 1546 
 1547         nfsm_request(dvp, NFSV4PROC_COMPOUND, cnp->cn_thread, cnp->cn_cred);
 1548         if (error != 0)
 1549                 goto nfsmout;
 1550 
 1551         nfsm_v4dissect_compound(&cp);
 1552         nfsm_v4dissect_putfh(&cp);
 1553         nfsm_v4dissect_create(&cp, &c);
 1554         nfsm_v4dissect_getattr(&cp, &ga);
 1555         nfsm_v4dissect_getfh(&cp, &gfh);        
 1556         
 1557         error = nfs_nget(dvp->v_mount, &gfh.fh_val, gfh.fh_len, &np);
 1558         if (error != 0)
 1559                 goto nfsmout;
 1560 
 1561         newvp = NFSTOV(np);
 1562         nfs4_vnop_loadattrcache(newvp, &ga.fa, NULL);
 1563 
 1564         if (cnp->cn_flags & MAKEENTRY)
 1565                 cache_enter(dvp, newvp, cnp);
 1566 
 1567         dnp->n_flag |= NMODIFIED;
 1568         dnp->n_attrstamp = 0;
 1569 
 1570  nfsmout:
 1571         error = nfs_v4postop(&cp, error);
 1572 
 1573         if (mrep != NULL)
 1574                 m_freem(mrep);
 1575 
 1576         /* XXX */
 1577         /*FREE(cnp->cn_pnbuf, M_NAMEI);*/
 1578         if (error != 0 && newvp != NULL)
 1579                 vrele(newvp);
 1580         else if (error == 0)
 1581                 *vpp = newvp;
 1582 
 1583         return (error);
 1584 }
 1585 
 1586 static int
 1587 nfs4_renamerpc(struct vnode *fdvp, const char *fnameptr, int fnamelen,
 1588     struct vnode *tdvp, const char *tnameptr, int tnamelen,
 1589     struct ucred *cred, struct thread *td)
 1590 {
 1591 
 1592         struct nfsnode *fnp = VTONFS(fdvp), *tnp = VTONFS(tdvp);
 1593         caddr_t bpos, dpos;
 1594         struct mbuf *mreq, *mrep = NULL, *md, *mb;
 1595         struct nfs4_compound cp;
 1596         struct nfs4_oparg_rename r;
 1597         int error = 0;
 1598 
 1599         nfsstats.rpccnt[NFSPROC_RENAME]++;
 1600 
 1601         r.fname = fnameptr;
 1602         r.fnamelen = fnamelen;
 1603         r.tname = tnameptr;
 1604         r.tnamelen = tnamelen;
 1605         nfs_v4initcompound(&cp);
 1606 
 1607         mreq = nfsm_reqhead(fdvp, NFSV4PROC_COMPOUND, 0);
 1608         mb = mreq;
 1609         bpos = mtod(mb, caddr_t);
 1610 
 1611         nfsm_v4build_compound(&cp, "nfs4_renamerpc()");
 1612         nfsm_v4build_putfh(&cp, fdvp);
 1613         nfsm_v4build_savefh(&cp);
 1614         nfsm_v4build_putfh(&cp, tdvp);
 1615         nfsm_v4build_rename(&cp, &r);
 1616         nfsm_v4build_finalize(&cp);
 1617 
 1618         nfsm_request(fdvp, NFSV4PROC_COMPOUND, td, cred);
 1619         if (error != 0)
 1620                 goto nfsmout;
 1621 
 1622         nfsm_v4dissect_compound(&cp);
 1623         nfsm_v4dissect_putfh(&cp);
 1624         nfsm_v4dissect_savefh(&cp);
 1625         nfsm_v4dissect_putfh(&cp);
 1626         nfsm_v4dissect_rename(&cp);
 1627 
 1628         /* XXX should this always be performed?  */
 1629         fnp->n_flag |= NMODIFIED;
 1630         tnp->n_flag |= NMODIFIED;
 1631         fnp->n_attrstamp = tnp->n_attrstamp = 0;
 1632 
 1633  nfsmout:
 1634         error = nfs_v4postop(&cp, error);
 1635 
 1636         if (mrep != NULL)
 1637                 m_freem(mrep);
 1638 
 1639         return (error);
 1640 }
 1641 
 1642 /*
 1643  * nfs file create call
 1644  */
 1645 static int
 1646 nfs4_create(struct vop_create_args *ap)
 1647 {
 1648         struct vnode *dvp = ap->a_dvp;
 1649         struct vattr *vap = ap->a_vap;
 1650         struct nfsnode *dnp = VTONFS(dvp);
 1651         struct componentname *cnp = ap->a_cnp;
 1652         struct vnode *newvp = NULL;
 1653         int error = 0, fmode = (O_CREAT | FREAD | FWRITE);
 1654         struct vattr vattr;
 1655 
 1656         if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread)) != 0)
 1657                 return (error);
 1658 
 1659         if (vap->va_vaflags & VA_EXCLUSIVE)
 1660                 fmode |= O_EXCL;
 1661 
 1662         error = nfs4_openrpc(dvp, &newvp, cnp, fmode, vap);
 1663         if (error != 0)
 1664                 goto out;
 1665 
 1666         VTONFS(newvp)->n_flag |= NCREATED;
 1667 
 1668         if (cnp->cn_flags & MAKEENTRY)
 1669                 cache_enter(dvp, newvp, cnp);
 1670 
 1671         *ap->a_vpp = newvp;
 1672 
 1673         dnp->n_flag |= NMODIFIED;
 1674         dnp->n_attrstamp = 0;   /* XXX; wccflag */
 1675 
 1676  out:
 1677         return (error);
 1678 }
 1679 
 1680 /*
 1681  * nfs file remove call
 1682  * To try and make nfs semantics closer to ufs semantics, a file that has
 1683  * other processes using the vnode is renamed instead of removed and then
 1684  * removed later on the last close.
 1685  * - If v_usecount > 1
 1686  *        If a rename is not already in the works
 1687  *           call nfs4_sillyrename() to set it up
 1688  *     else
 1689  *        do the remove rpc
 1690  */
 1691 static int
 1692 nfs4_remove(struct vop_remove_args *ap)
 1693 {
 1694         struct vnode *vp = ap->a_vp;
 1695         struct vnode *dvp = ap->a_dvp;
 1696         struct componentname *cnp = ap->a_cnp;
 1697         struct nfsnode *np = VTONFS(vp);
 1698         int error = 0;
 1699         struct vattr vattr;
 1700 
 1701 #ifndef DIAGNOSTIC
 1702         if ((cnp->cn_flags & HASBUF) == 0)
 1703                 panic("nfs4_remove: no name");
 1704         if (vrefcnt(vp) < 1)
 1705                 panic("nfs4_remove: bad v_usecount");
 1706 #endif
 1707         if (vp->v_type == VDIR)
 1708                 error = EPERM;
 1709         else if (vrefcnt(vp) == 1 || (np->n_sillyrename &&
 1710             VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_thread) == 0 &&
 1711             vattr.va_nlink > 1)) {
 1712                 /*
 1713                  * Purge the name cache so that the chance of a lookup for
 1714                  * the name succeeding while the remove is in progress is
 1715                  * minimized. Without node locking it can still happen, such
 1716                  * that an I/O op returns ESTALE, but since you get this if
 1717                  * another host removes the file..
 1718                  */
 1719                 cache_purge(vp);
 1720                 /*
 1721                  * throw away biocache buffers, mainly to avoid
 1722                  * unnecessary delayed writes later.
 1723                  */
 1724                 error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_thread, 1);
 1725                 /* Do the rpc */
 1726                 if (error != EINTR)
 1727                         error = nfs4_removerpc(dvp, cnp->cn_nameptr,
 1728                                 cnp->cn_namelen, cnp->cn_cred, cnp->cn_thread);
 1729                 /*
 1730                  * Kludge City: If the first reply to the remove rpc is lost..
 1731                  *   the reply to the retransmitted request will be ENOENT
 1732                  *   since the file was in fact removed
 1733                  *   Therefore, we cheat and return success.
 1734                  */
 1735                 if (error == ENOENT)
 1736                         error = 0;
 1737         } else if (!np->n_sillyrename)
 1738                 error = nfs4_sillyrename(dvp, vp, cnp);
 1739         np->n_attrstamp = 0;
 1740         return (error);
 1741 }
 1742 
 1743 /*
 1744  * nfs file remove rpc called from nfs_inactive
 1745  */
 1746 int
 1747 nfs4_removeit(struct sillyrename *sp)
 1748 {
 1749         /*
 1750          * Make sure that the directory vnode is still valid.
 1751          * XXX we should lock sp->s_dvp here.
 1752          */
 1753         if (sp->s_dvp->v_type == VBAD)
 1754                 return (0);
 1755         return (nfs4_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
 1756                 NULL));
 1757 }
 1758 
 1759 /*
 1760  * Nfs remove rpc, called from nfs4_remove() and nfs4_removeit().
 1761  */
 1762 static int
 1763 nfs4_removerpc(struct vnode *dvp, const char *name, int namelen,
 1764     struct ucred *cred, struct thread *td)
 1765 {
 1766         caddr_t bpos, dpos;
 1767         int error = 0;
 1768         struct mbuf *mreq, *mrep = NULL, *md, *mb;
 1769         struct nfs4_compound cp;
 1770 
 1771         nfsstats.rpccnt[NFSPROC_REMOVE]++;
 1772 
 1773         mreq = nfsm_reqhead(dvp, NFSV4PROC_COMPOUND, 0);
 1774         mb = mreq;
 1775         bpos = mtod(mb, caddr_t);
 1776 
 1777         nfs_v4initcompound(&cp);
 1778 
 1779         nfsm_v4build_compound(&cp, "nfs4_removerpc()");
 1780         nfsm_v4build_putfh(&cp, dvp);
 1781         nfsm_v4build_remove(&cp, name, namelen);
 1782         nfsm_v4build_finalize(&cp);
 1783 
 1784         nfsm_request(dvp, NFSV4PROC_COMPOUND, td, cred);
 1785         if (error != 0)
 1786                 goto nfsmout;
 1787 
 1788         nfsm_v4dissect_compound(&cp);
 1789         nfsm_v4dissect_putfh(&cp);
 1790         nfsm_v4dissect_remove(&cp);
 1791 
 1792  nfsmout:
 1793         error = nfs_v4postop(&cp, error);
 1794 
 1795         if (mrep != NULL)
 1796                 m_freem(mrep);
 1797 
 1798         VTONFS(dvp)->n_flag |= NMODIFIED;
 1799         VTONFS(dvp)->n_attrstamp = 0; /* XXX wccflag */
 1800 
 1801         return (error);
 1802 }
 1803 
 1804 /*
 1805  * nfs file rename call
 1806  */
 1807 static int
 1808 nfs4_rename(struct vop_rename_args *ap)
 1809 {
 1810         struct vnode *fvp = ap->a_fvp;
 1811         struct vnode *tvp = ap->a_tvp;
 1812         struct vnode *fdvp = ap->a_fdvp;
 1813         struct vnode *tdvp = ap->a_tdvp;
 1814         struct componentname *tcnp = ap->a_tcnp;
 1815         struct componentname *fcnp = ap->a_fcnp;
 1816         int error;
 1817 
 1818  #ifndef DIAGNOSTIC
 1819         if ((tcnp->cn_flags & HASBUF) == 0 ||
 1820             (fcnp->cn_flags & HASBUF) == 0)
 1821                 panic("nfs4_rename: no name");
 1822 #endif
 1823         /* Check for cross-device rename */
 1824         if ((fvp->v_mount != tdvp->v_mount) ||
 1825             (tvp && (fvp->v_mount != tvp->v_mount))) {
 1826                 error = EXDEV;
 1827                 goto out;
 1828         }
 1829 
 1830         if (fvp == tvp) {
 1831                 printf("nfs4_rename: fvp == tvp (can't happen)\n");
 1832                 error = 0;
 1833                 goto out;
 1834         }
 1835         if ((error = vn_lock(fvp, LK_EXCLUSIVE, fcnp->cn_thread)) != 0)
 1836                 goto out;
 1837 
 1838         /*
 1839          * We have to flush B_DELWRI data prior to renaming
 1840          * the file.  If we don't, the delayed-write buffers
 1841          * can be flushed out later after the file has gone stale
 1842          * under NFSV3.  NFSV2 does not have this problem because
 1843          * ( as far as I can tell ) it flushes dirty buffers more
 1844          * often.
 1845          */
 1846         VOP_FSYNC(fvp, fcnp->cn_cred, MNT_WAIT, fcnp->cn_thread);
 1847         VOP_UNLOCK(fvp, 0, fcnp->cn_thread);
 1848         if (tvp)
 1849             VOP_FSYNC(tvp, tcnp->cn_cred, MNT_WAIT, tcnp->cn_thread);
 1850 
 1851         /*
 1852          * If the tvp exists and is in use, sillyrename it before doing the
 1853          * rename of the new file over it.
 1854          * XXX Can't sillyrename a directory.
 1855          */
 1856         if (tvp && vrefcnt(tvp) > 1 && !VTONFS(tvp)->n_sillyrename &&
 1857                 tvp->v_type != VDIR && !nfs4_sillyrename(tdvp, tvp, tcnp)) {
 1858                 vput(tvp);
 1859                 tvp = NULL;
 1860         }
 1861 
 1862         error = nfs4_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
 1863                 tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
 1864                 tcnp->cn_thread);
 1865 
 1866         if (fvp->v_type == VDIR) {
 1867                 if (tvp != NULL && tvp->v_type == VDIR)
 1868                         cache_purge(tdvp);
 1869                 cache_purge(fdvp);
 1870         }
 1871 
 1872 out:
 1873         if (tdvp == tvp)
 1874                 vrele(tdvp);
 1875         else
 1876                 vput(tdvp);
 1877         if (tvp)
 1878                 vput(tvp);
 1879         vrele(fdvp);
 1880         vrele(fvp);
 1881         /*
 1882          * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
 1883          */
 1884         if (error == ENOENT)
 1885                 error = 0;
 1886         return (error);
 1887 }
 1888 
 1889 /*
 1890  * nfs file rename rpc called from nfs4_remove() above
 1891  */
 1892 static int
 1893 nfs4_renameit(struct vnode *sdvp, struct componentname *scnp,
 1894     struct sillyrename *sp)
 1895 {
 1896         return (nfs4_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen, sdvp,
 1897             sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_thread));
 1898 }
 1899 
 1900 /*
 1901  * nfs hard link create call
 1902  */
 1903 static int
 1904 nfs4_link(struct vop_link_args *ap)
 1905 {
 1906         struct vnode *vp = ap->a_vp;
 1907         struct vnode *tdvp = ap->a_tdvp;
 1908         struct componentname *cnp = ap->a_cnp;
 1909         caddr_t bpos, dpos;
 1910         int error = 0;
 1911         struct mbuf *mreq, *mrep = NULL, *md, *mb;
 1912         struct nfs4_compound cp;
 1913         struct nfs4_oparg_link l;
 1914 
 1915         if (vp->v_mount != tdvp->v_mount) {
 1916                 return (EXDEV);
 1917         }
 1918 
 1919         /*
 1920          * Push all writes to the server, so that the attribute cache
 1921          * doesn't get "out of sync" with the server.
 1922          * XXX There should be a better way!
 1923          */
 1924         VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_thread);
 1925 
 1926         nfsstats.rpccnt[NFSPROC_LINK]++;
 1927 
 1928         l.name = cnp->cn_nameptr;
 1929         l.namelen = cnp->cn_namelen;
 1930         nfs_v4initcompound(&cp);
 1931 
 1932         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
 1933         mb = mreq;
 1934         bpos = mtod(mb, caddr_t);
 1935 
 1936         nfsm_v4build_compound(&cp, "nfs4_link()");
 1937         nfsm_v4build_putfh(&cp, vp);
 1938         nfsm_v4build_savefh(&cp);
 1939         nfsm_v4build_putfh(&cp, tdvp);
 1940         nfsm_v4build_link(&cp, &l);
 1941         nfsm_v4build_finalize(&cp);
 1942 
 1943         nfsm_request(vp, NFSV4PROC_COMPOUND, cnp->cn_thread, cnp->cn_cred);
 1944         if (error != 0)
 1945                 goto nfsmout;
 1946 
 1947         nfsm_v4dissect_compound(&cp);
 1948         nfsm_v4dissect_putfh(&cp);
 1949         nfsm_v4dissect_savefh(&cp);
 1950         nfsm_v4dissect_putfh(&cp);
 1951         nfsm_v4dissect_link(&cp);
 1952 
 1953         VTONFS(tdvp)->n_flag |= NMODIFIED;
 1954         VTONFS(vp)->n_attrstamp = 0;
 1955         VTONFS(tdvp)->n_attrstamp = 0;
 1956 
 1957 nfsmout:
 1958         error = nfs_v4postop(&cp, error);
 1959 
 1960         if (mrep != NULL)
 1961                 m_freem(mrep);
 1962 
 1963         return (error);
 1964 }
 1965 
 1966 /*
 1967  * nfs symbolic link create call
 1968  */
 1969 static int
 1970 nfs4_symlink(struct vop_symlink_args *ap)
 1971 {
 1972         struct vnode *dvp = ap->a_dvp;
 1973         int error = 0;
 1974         struct vnode *newvp = NULL;
 1975 
 1976         nfsstats.rpccnt[NFSPROC_SYMLINK]++;
 1977 
 1978         error = nfs4_createrpc(ap->a_dvp, &newvp, ap->a_cnp, NFLNK,
 1979             ap->a_vap, ap->a_target);
 1980 
 1981         if (error != 0 && newvp != NULL)
 1982                 vput(newvp);
 1983         else if (error == 0)
 1984                  *ap->a_vpp = newvp;
 1985 
 1986         VTONFS(dvp)->n_flag |= NMODIFIED;
 1987         VTONFS(dvp)->n_attrstamp = 0; /* XXX wccflags */
 1988 
 1989         return (error);
 1990 }
 1991 
 1992 /*
 1993  * nfs make dir call
 1994  */
 1995 static int
 1996 nfs4_mkdir(struct vop_mkdir_args *ap)
 1997 {
 1998         return (nfs4_createrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, NFDIR,
 1999                     ap->a_vap, NULL));
 2000 }
 2001 
 2002 /*
 2003  * nfs remove directory call
 2004  */
 2005 static int
 2006 nfs4_rmdir(struct vop_rmdir_args *ap)
 2007 {
 2008         struct vnode *vp = ap->a_vp;
 2009         struct vnode *dvp = ap->a_dvp;
 2010         struct nfsnode *dnp = VTONFS(dvp);
 2011         struct componentname *cnp = ap->a_cnp;
 2012         int error = 0;
 2013 
 2014         if (dvp == vp)
 2015                 return (EINVAL);
 2016 
 2017         error = (nfs4_removerpc(dvp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_cred,
 2018                                NULL));
 2019         if (error)
 2020                 return (error);
 2021 
 2022         dnp->n_flag |= NMODIFIED;
 2023         dnp->n_attrstamp = 0;
 2024         cache_purge(dvp);
 2025         cache_purge(vp);
 2026 
 2027         return (error);
 2028 }
 2029 
 2030 /*
 2031  * nfs readdir call
 2032  */
 2033 static int
 2034 nfs4_readdir(struct vop_readdir_args *ap)
 2035 {
 2036         struct vnode *vp = ap->a_vp;
 2037         struct nfsnode *np = VTONFS(vp);
 2038         struct uio *uio = ap->a_uio;
 2039         int tresid, error;
 2040         struct vattr vattr;
 2041 
 2042         if (vp->v_type != VDIR)
 2043                 return (EPERM);
 2044         /*
 2045          * First, check for hit on the EOF offset cache
 2046          */
 2047         if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
 2048             (np->n_flag & NMODIFIED) == 0) {
 2049                 if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_td) == 0 &&
 2050                         np->n_mtime == vattr.va_mtime.tv_sec) {
 2051                         nfsstats.direofcache_hits++;
 2052                         return (0);
 2053                 }
 2054         }
 2055 
 2056         /*
 2057          * Call nfs_bioread() to do the real work.
 2058          */
 2059         tresid = uio->uio_resid;
 2060         error = nfs_bioread(vp, uio, 0, ap->a_cred);
 2061 
 2062         if (!error && uio->uio_resid == tresid)
 2063                 nfsstats.direofcache_misses++;
 2064         return (error);
 2065 }
 2066 
 2067 static u_char fty_to_dty[] = {
 2068         DT_UNKNOWN,             /* NFNON */
 2069         DT_REG,                 /* NFREG */
 2070         DT_DIR,                 /* NFDIR */
 2071         DT_BLK,                 /* NFBLK */
 2072         DT_CHR,                 /* NFCHR */
 2073         DT_LNK,                 /* NFLNK */
 2074         DT_SOCK,                /* NFSOCK */
 2075         DT_FIFO,                /* NFFIFO */
 2076         DT_UNKNOWN,             /* NFATTRDIT */
 2077         DT_UNKNOWN,             /* NFNAMEDATTR */
 2078         DT_UNKNOWN,             /* NFBAD */
 2079 };
 2080 
 2081 /*
 2082  * Readdir rpc call.
 2083  * Called from below the buffer cache by nfs_doio().
 2084  */
 2085 int
 2086 nfs4_readdirrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred)
 2087 {
 2088         int len, left;
 2089         struct dirent *dp = NULL;
 2090         u_int32_t *tl;
 2091         caddr_t p;
 2092         uint64_t *cookiep;
 2093         caddr_t bpos, dpos;
 2094         struct mbuf *mreq, *mrep = NULL, *md, *mb;
 2095         uint64_t cookie;
 2096         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 2097         struct nfsnode *dnp = VTONFS(vp);
 2098         int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
 2099         struct nfs4_compound cp;
 2100         struct nfs4_oparg_readdir readdir;
 2101         struct nfsv4_fattr fattr;
 2102         u_int fty;
 2103 
 2104 #ifndef DIAGNOSTIC
 2105         if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
 2106                 (uiop->uio_resid & (DIRBLKSIZ - 1)))
 2107                 panic("nfs readdirrpc bad uio");
 2108 #endif
 2109 
 2110         /*
 2111          * If there is no cookie, assume directory was stale.
 2112          */
 2113         cookiep = nfs4_getcookie(dnp, uiop->uio_offset, 0);
 2114         if (cookiep)
 2115                 cookie = *cookiep;
 2116         else
 2117                 return (NFSERR_BAD_COOKIE);
 2118 
 2119         /* Generate fake entries for "." and ".." */
 2120         while (cookie < 2 && bigenough) {
 2121                 cookie++;
 2122                 len = 4 + DIRHDSIZ;
 2123 
 2124                 if (len > uiop->uio_resid) {
 2125                         bigenough = 0;
 2126                         break;
 2127                 }
 2128                 dp = (struct dirent *)uiop->uio_iov->iov_base;
 2129 
 2130                 dp->d_namlen = cookie;
 2131                 dp->d_reclen = len;
 2132                 dp->d_type = DT_DIR;
 2133                 if (cookie == 1)
 2134                         dp->d_fileno = dnp->n_vattr.va_fileid; /* XXX has problems with pynfs virtualhandles */
 2135                 else
 2136                         dp->d_fileno = dnp->n_dvp != NULL ?
 2137                             VTONFS(dnp->n_dvp)->n_vattr.va_fileid : cookie;
 2138 
 2139                 p = dp->d_name;
 2140                 *p++ = '.';
 2141                 if (cookie == 2)
 2142                         *p++ = '.';
 2143                 *p = '\0';
 2144 
 2145                 blksiz += len;
 2146                 if (blksiz == DIRBLKSIZ)
 2147                         blksiz = 0;
 2148                 uiop->uio_offset += len;
 2149                 uiop->uio_resid -= len;
 2150                 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + len;
 2151                 uiop->uio_iov->iov_len -= len;
 2152         }
 2153 
 2154         if (cookie == 2)
 2155                 cookie = 0;
 2156 
 2157         /* This is sort of ugly, to prevent v4postop() from acting weird */
 2158         bzero(&cp, sizeof(cp));
 2159 
 2160         /*
 2161          * Loop around doing readdir rpc's of size nm_readdirsize
 2162          * truncated to a multiple of DIRBLKSIZ.
 2163          * The stopping criteria is EOF or buffer full.
 2164          */
 2165         /*
 2166          * XXX this is sort of ugly for nfsv4; we don't maintain the
 2167          * strict abstraction, but do the decoding inline.  that's ok.
 2168          */
 2169         while (more_dirs && bigenough) {
 2170                 nfsstats.rpccnt[NFSPROC_READDIR]++;
 2171 
 2172                 mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
 2173                 mb = mreq;
 2174                 bpos = mtod(mb, caddr_t);
 2175 
 2176                 readdir.cnt = nmp->nm_readdirsize;
 2177                 readdir.cookie = cookie;
 2178                 readdir.bm = &nfsv4_readdirbm;
 2179                 if (cookie == 0)
 2180                         bzero(&readdir.verf, sizeof(readdir.verf));
 2181                 else
 2182                         bcopy(&dnp->n_cookieverf, &readdir.verf,
 2183                             sizeof(readdir.verf));
 2184 
 2185                 nfs_v4initcompound(&cp);
 2186 
 2187                 nfsm_v4build_compound(&cp, "nfs4_readdirrpc()");
 2188                 nfsm_v4build_putfh(&cp, vp);
 2189                 nfsm_v4build_readdir(&cp, &readdir);
 2190                 nfsm_v4build_finalize(&cp);
 2191 
 2192                 nfsm_request(vp, NFSV4PROC_COMPOUND, uiop->uio_td, cred);
 2193                 if (error != 0)
 2194                         goto nfsmout;
 2195 
 2196                 nfsm_v4dissect_compound(&cp);
 2197                 nfsm_v4dissect_putfh(&cp);
 2198 
 2199                 /*
 2200                  * XXX - Readdir gets handled inline like in
 2201                  * NFSv{2,3}.  This is a nasty inconsistency and
 2202                  * should be fixed.
 2203                  */
 2204 
 2205                 tl = nfsm_dissect(uint32_t *, 5 * NFSX_UNSIGNED);
 2206                 if (fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_READDIR) {
 2207                         error = EBADRPC;
 2208                         goto nfsmout;
 2209                 }
 2210                 if (fxdr_unsigned(uint32_t, *tl++) != 0) {
 2211                         error = EBADRPC;
 2212                         goto nfsmout;
 2213                 }
 2214 
 2215                 bcopy(tl, &dnp->n_cookieverf, NFSX_V4VERF);
 2216                 tl += 2;
 2217                 more_dirs = fxdr_unsigned(int, *tl++);
 2218 
 2219                 /* loop thru the dir entries, doctoring them to 4bsd form */
 2220                 while (more_dirs && bigenough) {
 2221                         tl = nfsm_dissect(uint32_t *, 3 * NFSX_UNSIGNED);
 2222                         cookie = fxdr_hyper(tl);
 2223                         tl += 2;
 2224                         /* XXX cookie sanity check */
 2225                         len = fxdr_unsigned(int, *tl++);
 2226                         if (len <= 0 || len > NFS_MAXNAMLEN) {
 2227                                 error = EBADRPC;
 2228                                 goto nfsmout;
 2229                         }
 2230                         tlen = nfsm_rndup(len);
 2231                         if (tlen == len)
 2232                                 tlen += 4;      /* To ensure null termination */
 2233                         left = DIRBLKSIZ - blksiz;
 2234                         if ((tlen + DIRHDSIZ) > left) {
 2235                                 dp->d_reclen += left;
 2236                                 uiop->uio_iov->iov_base =
 2237                                     (char *)uiop->uio_iov->iov_base + left;
 2238                                 uiop->uio_iov->iov_len -= left;
 2239                                 uiop->uio_offset += left;
 2240                                 uiop->uio_resid -= left;
 2241                                 blksiz = 0;
 2242                         }
 2243                         if ((tlen + DIRHDSIZ) > uiop->uio_resid)
 2244                                 bigenough = 0;
 2245                         if (bigenough) {
 2246                                 dp = (struct dirent *)uiop->uio_iov->iov_base;
 2247 
 2248                                 dp->d_namlen = len;
 2249                                 dp->d_reclen = tlen + DIRHDSIZ;
 2250 
 2251                                 blksiz += dp->d_reclen;
 2252                                 if (blksiz == DIRBLKSIZ)
 2253                                         blksiz = 0;
 2254                                 uiop->uio_offset += DIRHDSIZ;
 2255                                 uiop->uio_resid -= DIRHDSIZ;
 2256                                 uiop->uio_iov->iov_base =
 2257                                     (char *)uiop->uio_iov->iov_base + DIRHDSIZ;
 2258                                 uiop->uio_iov->iov_len -= DIRHDSIZ;
 2259 
 2260                                 /* Copy name */
 2261                                 nfsm_mtouio(uiop, len);
 2262                                 p = uiop->uio_iov->iov_base;
 2263                                 tlen -= len;
 2264                                 *p = '\0';      /* null terminate */
 2265                                 /* printf("nfs4_readdirrpc: name: \"%s\" cookie %d\n",
 2266                                    p - len, (int) cookie);*/
 2267                                 uiop->uio_iov->iov_base =
 2268                                     (char *)uiop->uio_iov->iov_base + tlen;
 2269                                 uiop->uio_iov->iov_len -= tlen;
 2270                                 uiop->uio_offset += tlen;
 2271                                 uiop->uio_resid -= tlen;
 2272 
 2273                                 /* Copy attributes */
 2274                                 nfsm_v4dissect_attrs(&fattr);
 2275 
 2276                                 dp->d_fileno = nfs_v4fileid4_to_fileid(
 2277                                         fattr.fa4_valid & FA4V_FILEID &&
 2278                                             fattr.fa4_fileid ?
 2279                                             fattr.fa4_fileid : cookie);
 2280 
 2281                                 fty = (u_int)fattr.fa4_type;
 2282                                 dp->d_type = fattr.fa4_valid & FA4V_TYPE &&
 2283                                     (fty < sizeof(fty_to_dty)) ?
 2284                                     fty_to_dty[fty] : DT_UNKNOWN;
 2285                         } else
 2286                                 nfsm_adv(nfsm_rndup(len));
 2287 
 2288                         tl = nfsm_dissect(uint32_t *, NFSX_UNSIGNED);
 2289                         more_dirs = fxdr_unsigned(int, *tl++);
 2290                 }
 2291                 /*
 2292                  * If at end of rpc data, get the eof boolean
 2293                  */
 2294                 if (!more_dirs) {
 2295                         tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
 2296                         more_dirs = (fxdr_unsigned(int, *tl) == 0);
 2297                 }
 2298 
 2299                 error = nfs_v4postop(&cp, error);
 2300 
 2301                 m_freem(mrep);
 2302                 mrep = NULL;
 2303         }
 2304         /*
 2305          * Fill last record, iff any, out to a multiple of DIRBLKSIZ
 2306          * by increasing d_reclen for the last record.
 2307          */
 2308         if (blksiz > 0) {
 2309                 left = DIRBLKSIZ - blksiz;
 2310                 dp->d_reclen += left;
 2311                 uiop->uio_iov->iov_base =
 2312                     (char *)uiop->uio_iov->iov_base + left;
 2313                 uiop->uio_iov->iov_len -= left;
 2314                 uiop->uio_offset += left;
 2315                 uiop->uio_resid -= left;
 2316         }
 2317 
 2318         /*
 2319          * We are now either at the end of the directory or have filled the
 2320          * block.
 2321          */
 2322         if (bigenough)
 2323                 dnp->n_direofoffset = uiop->uio_offset;
 2324         else {
 2325                 if (uiop->uio_resid > 0)
 2326                         printf("EEK! readdirrpc resid > 0\n");
 2327                 cookiep = nfs4_getcookie(dnp, uiop->uio_offset, 1);
 2328                 *cookiep = cookie;
 2329         }
 2330 nfsmout:
 2331         if (mrep != NULL)
 2332                 m_freem(mrep);
 2333         return (error);
 2334 }
 2335 
 2336 /*
 2337  * Silly rename. To make the NFS filesystem that is stateless look a little
 2338  * more like the "ufs" a remove of an active vnode is translated to a rename
 2339  * to a funny looking filename that is removed by nfs_inactive on the
 2340  * nfsnode. There is the potential for another process on a different client
 2341  * to create the same funny name between the nfs_lookitup() fails and the
 2342  * nfs_rename() completes, but...
 2343  */
 2344 static int
 2345 nfs4_sillyrename(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
 2346 {
 2347         struct sillyrename *sp;
 2348         struct nfsnode *np;
 2349         int error;
 2350         short pid;
 2351 
 2352         cache_purge(dvp);
 2353         np = VTONFS(vp);
 2354 #ifndef DIAGNOSTIC
 2355         if (vp->v_type == VDIR)
 2356                 panic("nfs: sillyrename dir");
 2357 #endif
 2358         MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
 2359                 M_NFSREQ, M_WAITOK);
 2360         sp->s_cred = crhold(cnp->cn_cred);
 2361         sp->s_dvp = dvp;
 2362         sp->s_removeit = nfs4_removeit;
 2363         VREF(dvp);
 2364 
 2365         /* Fudge together a funny name */
 2366         pid = cnp->cn_thread->td_proc->p_pid;
 2367         sp->s_namlen = sprintf(sp->s_name, ".nfsA%04x4.4", pid);
 2368 
 2369         /* Try lookitups until we get one that isn't there */
 2370         while (nfs4_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
 2371                 cnp->cn_thread, NULL) == 0) {
 2372                 sp->s_name[4]++;
 2373                 if (sp->s_name[4] > 'z') {
 2374                         error = EINVAL;
 2375                         goto bad;
 2376                 }
 2377         }
 2378         error = nfs4_renameit(dvp, cnp, sp);
 2379         if (error)
 2380                 goto bad;
 2381         error = nfs4_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
 2382                 cnp->cn_thread, &np);
 2383         np->n_sillyrename = sp;
 2384         return (0);
 2385 bad:
 2386         vrele(sp->s_dvp);
 2387         crfree(sp->s_cred);
 2388         free((caddr_t)sp, M_NFSREQ);
 2389         return (error);
 2390 }
 2391 
 2392 /*
 2393  * Look up a file name and optionally either update the file handle or
 2394  * allocate an nfsnode, depending on the value of npp.
 2395  * npp == NULL  --> just do the lookup
 2396  * *npp == NULL --> allocate a new nfsnode and make sure attributes are
 2397  *                      handled too
 2398  * *npp != NULL --> update the file handle in the vnode
 2399  */
 2400 static int
 2401 nfs4_lookitup(struct vnode *dvp, const char *name, int len, struct ucred *cred,
 2402     struct thread *td, struct nfsnode **npp)
 2403 {
 2404         struct vnode *newvp = NULL;
 2405         struct nfsnode *np, *dnp = VTONFS(dvp);
 2406         caddr_t bpos, dpos;
 2407         int error = 0, fhlen;
 2408         struct mbuf *mreq, *mrep = NULL, *md, *mb;
 2409         nfsfh_t *nfhp;
 2410         struct nfs4_compound cp;
 2411         struct nfs4_oparg_lookup l;
 2412         struct nfs4_oparg_getfh gfh;
 2413         struct nfs4_oparg_getattr ga;
 2414 
 2415         nfsstats.rpccnt[NFSPROC_RENAME]++;
 2416 
 2417         mreq = nfsm_reqhead(dvp, NFSV4PROC_COMPOUND, 0);
 2418         mb = mreq;
 2419         bpos = mtod(mb, caddr_t);
 2420 
 2421         l.name = name;
 2422         l.namelen = len;
 2423 
 2424         nfs_v4initcompound(&cp);
 2425 
 2426         ga.bm = &nfsv4_getattrbm;
 2427 
 2428         nfsm_v4build_compound(&cp, "nfs4_renamerpc()");
 2429         nfsm_v4build_putfh(&cp, dvp);
 2430         nfsm_v4build_lookup(&cp, &l);
 2431         nfsm_v4build_getfh(&cp, &gfh);
 2432         nfsm_v4build_getattr(&cp, &ga);
 2433 
 2434         nfsm_request(dvp, NFSV4PROC_COMPOUND, td, cred);
 2435         if (error != 0)
 2436                 goto nfsmout;
 2437 
 2438         nfsm_v4dissect_compound(&cp);
 2439         nfsm_v4dissect_putfh(&cp);
 2440         nfsm_v4dissect_lookup(&cp);
 2441         nfsm_v4dissect_getfh(&cp, &gfh);
 2442         nfsm_v4dissect_getattr(&cp, &ga);
 2443 
 2444         if (npp != NULL && error == 0) {
 2445                 nfhp = &gfh.fh_val;
 2446                 fhlen = gfh.fh_len;
 2447 
 2448                 if (*npp != NULL) {
 2449                         np = *npp;
 2450                         if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
 2451                                 free((caddr_t)np->n_fhp, M_NFSBIGFH);
 2452                                 np->n_fhp = &np->n_fh;
 2453                         } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
 2454                                 np->n_fhp =(nfsfh_t *)malloc(fhlen, M_NFSBIGFH, M_WAITOK);
 2455                         bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
 2456                         np->n_fhsize = fhlen;
 2457                         newvp = NFSTOV(np);
 2458                 } else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
 2459                         VREF(dvp);
 2460                         newvp = dvp;
 2461                 } else {
 2462                         error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
 2463                         if (error) {
 2464                                 m_freem(mrep);
 2465                                 return (error);
 2466                         }
 2467                         newvp = NFSTOV(np);
 2468                 }
 2469 
 2470                 if (newvp != dvp) {
 2471                         np->n_dvp = dvp;
 2472                         np->n_namelen = len;
 2473                         if (np->n_name != NULL)
 2474                                 FREE(np->n_name, M_NFSREQ);
 2475                         MALLOC(np->n_name, u_char *,
 2476                             np->n_namelen + 1, M_NFSREQ, M_WAITOK);
 2477                         memcpy(np->n_name, name, len);
 2478                         np->n_name[len] = '\0';
 2479                 }
 2480                 nfs4_vnop_loadattrcache(newvp, &ga.fa, NULL);
 2481         }
 2482 
 2483 nfsmout:
 2484         error = nfs_v4postop(&cp, error);
 2485 
 2486         if (mrep != NULL)
 2487                 m_freem(mrep);
 2488         if (npp && *npp == NULL) {
 2489                 if (error) {
 2490                         if (newvp) {
 2491                                 if (newvp == dvp)
 2492                                         vrele(newvp);
 2493                                 else
 2494                                         vput(newvp);
 2495                         }
 2496                 } else
 2497                         *npp = np;
 2498         }
 2499 
 2500 
 2501         return (error);
 2502 }
 2503 
 2504 /*
 2505  * Nfs Version 3 commit rpc
 2506  */
 2507 int
 2508 nfs4_commit(struct vnode *vp, u_quad_t offset, int cnt, struct ucred *cred,
 2509     struct thread *td)
 2510 {
 2511         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 2512         caddr_t bpos, dpos;
 2513         int error = 0;
 2514         struct mbuf *mreq, *mrep = NULL, *md, *mb;
 2515         struct nfs4_compound cp;
 2516         struct nfs4_oparg_commit commit;
 2517 
 2518         if ((nmp->nm_state & NFSSTA_HASWRITEVERF) == 0)
 2519                 return (0);
 2520         nfsstats.rpccnt[NFSPROC_COMMIT]++;
 2521 
 2522         mreq = nfsm_reqhead(vp, NFSV4PROC_COMPOUND, 0);
 2523         mb = mreq;
 2524         bpos = mtod(mb, caddr_t);
 2525 
 2526         commit.start = offset;
 2527         commit.len = cnt;
 2528 
 2529         nfs_v4initcompound(&cp);
 2530 
 2531         nfsm_v4build_compound(&cp, "nfs4_commit()");
 2532         nfsm_v4build_putfh(&cp, vp);
 2533         nfsm_v4build_commit(&cp, &commit);
 2534         nfsm_v4build_finalize(&cp);
 2535 
 2536         nfsm_request(vp, NFSV4PROC_COMPOUND, td, cred);
 2537         if (error != 0)
 2538                 goto nfsmout;
 2539 
 2540         nfsm_v4dissect_compound(&cp);
 2541         nfsm_v4dissect_putfh(&cp);
 2542         nfsm_v4dissect_commit(&cp, &commit);
 2543         
 2544         /* XXX */
 2545         /* nfsm_wcc_data(vp, wccflag);*/
 2546         if (bcmp(nmp->nm_verf, commit.verf, NFSX_V4VERF)) {
 2547                 bcopy(commit.verf, nmp->nm_verf, NFSX_V4VERF);
 2548                 error = NFSERR_STALEWRITEVERF;
 2549         }
 2550 
 2551 nfsmout:
 2552         error = nfs_v4postop(&cp, error);
 2553 
 2554         if (mrep == NULL)
 2555                 m_freem(mrep);
 2556         return (error);
 2557 }
 2558 
 2559 /*
 2560  * Strategy routine.
 2561  * For async requests when nfsiod(s) are running, queue the request by
 2562  * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
 2563  * request.
 2564  */
 2565 static int
 2566 nfs4_strategy(struct vop_strategy_args *ap)
 2567 {
 2568         struct buf *bp = ap->a_bp;
 2569         struct ucred *cr;
 2570         struct thread *td;
 2571         int error = 0;
 2572 
 2573         KASSERT(ap->a_vp == ap->a_bp->b_vp, ("%s(%p != %p)",
 2574             __func__, ap->a_vp, ap->a_bp->b_vp));
 2575         KASSERT(!(bp->b_flags & B_DONE), ("nfs4_strategy: buffer %p unexpectedly marked B_DONE", bp));
 2576         KASSERT(BUF_REFCNT(bp) > 0, ("nfs4_strategy: buffer %p not locked", bp));
 2577 
 2578         if (bp->b_flags & B_ASYNC)
 2579                 td = NULL;
 2580         else
 2581                 td = curthread; /* XXX */
 2582 
 2583         if (bp->b_iocmd == BIO_READ)
 2584                 cr = bp->b_rcred;
 2585         else
 2586                 cr = bp->b_wcred;
 2587 
 2588         /*
 2589          * If the op is asynchronous and an i/o daemon is waiting
 2590          * queue the request, wake it up and wait for completion
 2591          * otherwise just do it ourselves.
 2592          */
 2593         if ((bp->b_flags & B_ASYNC) == 0 ||
 2594                 nfs_asyncio(bp, NOCRED, td))
 2595                 error = nfs_doio(bp, cr, td);
 2596         return (error);
 2597 }
 2598 
 2599 /*
 2600  * fsync vnode op. Just call nfs4_flush() with commit == 1.
 2601  */
 2602 /* ARGSUSED */
 2603 static int
 2604 nfs4_fsync(struct vop_fsync_args *ap)
 2605 {
 2606         return (nfs4_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));
 2607 }
 2608 
 2609 /*
 2610  * Flush all the blocks associated with a vnode.
 2611  *      Walk through the buffer pool and push any dirty pages
 2612  *      associated with the vnode.
 2613  */
 2614 static int
 2615 nfs4_flush(struct vnode *vp, struct ucred *cred, int waitfor, struct thread *td,
 2616     int commit)
 2617 {
 2618         struct nfsnode *np = VTONFS(vp);
 2619         struct buf *bp;
 2620         int i;
 2621         struct buf *nbp;
 2622         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 2623         int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
 2624         int passone = 1;
 2625         u_quad_t off, endoff, toff;
 2626         struct ucred* wcred = NULL;
 2627         struct buf **bvec = NULL;
 2628 #ifndef NFS_COMMITBVECSIZ
 2629 #define NFS_COMMITBVECSIZ       20
 2630 #endif
 2631         struct buf *bvec_on_stack[NFS_COMMITBVECSIZ];
 2632         int bvecsize = 0, bveccount;
 2633 
 2634         if (nmp->nm_flag & NFSMNT_INT)
 2635                 slpflag = PCATCH;
 2636         if (!commit)
 2637                 passone = 0;
 2638         /*
 2639          * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
 2640          * server, but nas not been committed to stable storage on the server
 2641          * yet. On the first pass, the byte range is worked out and the commit
 2642          * rpc is done. On the second pass, nfs_writebp() is called to do the
 2643          * job.
 2644          */
 2645 again:
 2646         off = (u_quad_t)-1;
 2647         endoff = 0;
 2648         bvecpos = 0;
 2649         if (NFS_ISV3(vp) && commit) {
 2650                 s = splbio();
 2651                 if (bvec != NULL && bvec != bvec_on_stack)
 2652                         free(bvec, M_TEMP);
 2653                 /*
 2654                  * Count up how many buffers waiting for a commit.
 2655                  */
 2656                 bveccount = 0;
 2657                 VI_LOCK(vp);
 2658                 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
 2659                         nbp = TAILQ_NEXT(bp, b_vnbufs);
 2660                         if (BUF_REFCNT(bp) == 0 &&
 2661                             (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
 2662                                 == (B_DELWRI | B_NEEDCOMMIT))
 2663                                 bveccount++;
 2664                 }
 2665                 /*
 2666                  * Allocate space to remember the list of bufs to commit.  It is
 2667                  * important to use M_NOWAIT here to avoid a race with nfs4_write.
 2668                  * If we can't get memory (for whatever reason), we will end up
 2669                  * committing the buffers one-by-one in the loop below.
 2670                  */
 2671                 if (bveccount > NFS_COMMITBVECSIZ) {
 2672                         /*
 2673                          * Release the vnode interlock to avoid a lock
 2674                          * order reversal.
 2675                          */
 2676                         VI_UNLOCK(vp);
 2677                         bvec = (struct buf **)
 2678                                 malloc(bveccount * sizeof(struct buf *),
 2679                                        M_TEMP, M_NOWAIT);
 2680                         VI_LOCK(vp);
 2681                         if (bvec == NULL) {
 2682                                 bvec = bvec_on_stack;
 2683                                 bvecsize = NFS_COMMITBVECSIZ;
 2684                         } else
 2685                                 bvecsize = bveccount;
 2686                 } else {
 2687                         bvec = bvec_on_stack;
 2688                         bvecsize = NFS_COMMITBVECSIZ;
 2689                 }
 2690                 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
 2691                         if (bvecpos >= bvecsize)
 2692                                 break;
 2693                         if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
 2694                                 nbp = TAILQ_NEXT(bp, b_vnbufs);
 2695                                 continue;
 2696                         }
 2697                         if ((bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) !=
 2698                             (B_DELWRI | B_NEEDCOMMIT)) {
 2699                                 BUF_UNLOCK(bp);
 2700                                 nbp = TAILQ_NEXT(bp, b_vnbufs);
 2701                                 continue;
 2702                         }
 2703                         VI_UNLOCK(vp);
 2704                         bremfree(bp);
 2705                         /*
 2706                          * Work out if all buffers are using the same cred
 2707                          * so we can deal with them all with one commit.
 2708                          *
 2709                          * NOTE: we are not clearing B_DONE here, so we have
 2710                          * to do it later on in this routine if we intend to
 2711                          * initiate I/O on the bp.
 2712                          *
 2713                          * Note: to avoid loopback deadlocks, we do not
 2714                          * assign b_runningbufspace.
 2715                          */
 2716                         if (wcred == NULL)
 2717                                 wcred = bp->b_wcred;
 2718                         else if (wcred != bp->b_wcred)
 2719                                 wcred = NOCRED;
 2720                         bp->b_flags |= B_WRITEINPROG;
 2721                         vfs_busy_pages(bp, 1);
 2722 
 2723                         VI_LOCK(vp);
 2724                         /*
 2725                          * bp is protected by being locked, but nbp is not
 2726                          * and vfs_busy_pages() may sleep.  We have to
 2727                          * recalculate nbp.
 2728                          */
 2729                         nbp = TAILQ_NEXT(bp, b_vnbufs);
 2730 
 2731                         /*
 2732                          * A list of these buffers is kept so that the
 2733                          * second loop knows which buffers have actually
 2734                          * been committed. This is necessary, since there
 2735                          * may be a race between the commit rpc and new
 2736                          * uncommitted writes on the file.
 2737                          */
 2738                         bvec[bvecpos++] = bp;
 2739                         toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
 2740                                 bp->b_dirtyoff;
 2741                         if (toff < off)
 2742                                 off = toff;
 2743                         toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
 2744                         if (toff > endoff)
 2745                                 endoff = toff;
 2746                 }
 2747                 splx(s);
 2748                 VI_UNLOCK(vp);
 2749         }
 2750         if (bvecpos > 0) {
 2751                 /*
 2752                  * Commit data on the server, as required.
 2753                  * If all bufs are using the same wcred, then use that with
 2754                  * one call for all of them, otherwise commit each one
 2755                  * separately.
 2756                  */
 2757                 if (wcred != NOCRED)
 2758                         retv = nfs4_commit(vp, off, (int)(endoff - off),
 2759                                           wcred, td);
 2760                 else {
 2761                         retv = 0;
 2762                         for (i = 0; i < bvecpos; i++) {
 2763                                 off_t off, size;
 2764                                 bp = bvec[i];
 2765                                 off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
 2766                                         bp->b_dirtyoff;
 2767                                 size = (u_quad_t)(bp->b_dirtyend
 2768                                                   - bp->b_dirtyoff);
 2769                                 retv = nfs4_commit(vp, off, (int)size,
 2770                                                   bp->b_wcred, td);
 2771                                 if (retv) break;
 2772                         }
 2773                 }
 2774 
 2775                 if (retv == NFSERR_STALEWRITEVERF)
 2776                         nfs_clearcommit(vp->v_mount);
 2777 
 2778                 /*
 2779                  * Now, either mark the blocks I/O done or mark the
 2780                  * blocks dirty, depending on whether the commit
 2781                  * succeeded.
 2782                  */
 2783                 for (i = 0; i < bvecpos; i++) {
 2784                         bp = bvec[i];
 2785                         bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG | B_CLUSTEROK);
 2786                         if (retv) {
 2787                                 /*
 2788                                  * Error, leave B_DELWRI intact
 2789                                  */
 2790                                 vfs_unbusy_pages(bp);
 2791                                 brelse(bp);
 2792                         } else {
 2793                                 /*
 2794                                  * Success, remove B_DELWRI ( bundirty() ).
 2795                                  *
 2796                                  * b_dirtyoff/b_dirtyend seem to be NFS
 2797                                  * specific.  We should probably move that
 2798                                  * into bundirty(). XXX
 2799                                  */
 2800                                 s = splbio();
 2801                                 VI_LOCK(vp);
 2802                                 vp->v_numoutput++;
 2803                                 VI_UNLOCK(vp);
 2804                                 bp->b_flags |= B_ASYNC;
 2805                                 bundirty(bp);
 2806                                 bp->b_flags &= ~B_DONE;
 2807                                 bp->b_ioflags &= ~BIO_ERROR;
 2808                                 bp->b_dirtyoff = bp->b_dirtyend = 0;
 2809                                 splx(s);
 2810                                 bufdone(bp);
 2811                         }
 2812                 }
 2813         }
 2814 
 2815         /*
 2816          * Start/do any write(s) that are required.
 2817          */
 2818 loop:
 2819         s = splbio();
 2820         VI_LOCK(vp);
 2821         for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
 2822                 nbp = TAILQ_NEXT(bp, b_vnbufs);
 2823                 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
 2824                         if (waitfor != MNT_WAIT || passone)
 2825                                 continue;
 2826 
 2827                         error = BUF_TIMELOCK(bp,
 2828                             LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
 2829                             VI_MTX(vp), "nfsfsync", slpflag, slptimeo);
 2830                         splx(s);
 2831                         if (error == 0)
 2832                                 panic("nfs4_fsync: inconsistent lock");
 2833                         if (error == ENOLCK)
 2834                                 goto loop;
 2835                         if (nfs4_sigintr(nmp, NULL, td)) {
 2836                                 error = EINTR;
 2837                                 goto done;
 2838                         }
 2839                         if (slpflag == PCATCH) {
 2840                                 slpflag = 0;
 2841                                 slptimeo = 2 * hz;
 2842                         }
 2843                         goto loop;
 2844                 }
 2845                 if ((bp->b_flags & B_DELWRI) == 0)
 2846                         panic("nfs4_fsync: not dirty");
 2847                 if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT)) {
 2848                         BUF_UNLOCK(bp);
 2849                         continue;
 2850                 }
 2851                 VI_UNLOCK(vp);
 2852                 bremfree(bp);
 2853                 if (passone || !commit)
 2854                     bp->b_flags |= B_ASYNC;
 2855                 else
 2856                     bp->b_flags |= B_ASYNC | B_WRITEINPROG;
 2857                 splx(s);
 2858                 bwrite(bp);
 2859                 goto loop;
 2860         }
 2861         splx(s);
 2862         if (passone) {
 2863                 passone = 0;
 2864                 VI_UNLOCK(vp);
 2865                 goto again;
 2866         }
 2867         if (waitfor == MNT_WAIT) {
 2868                 while (vp->v_numoutput) {
 2869                         vp->v_iflag |= VI_BWAIT;
 2870                         error = msleep((caddr_t)&vp->v_numoutput, VI_MTX(vp),
 2871                                 slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
 2872                         if (error) {
 2873                             VI_UNLOCK(vp);
 2874                             if (nfs4_sigintr(nmp, NULL, td)) {
 2875                                 error = EINTR;
 2876                                 goto done;
 2877                             }
 2878                             if (slpflag == PCATCH) {
 2879                                 slpflag = 0;
 2880                                 slptimeo = 2 * hz;
 2881                             }
 2882                             VI_LOCK(vp);
 2883                         }
 2884                 }
 2885                 if (!TAILQ_EMPTY(&vp->v_dirtyblkhd) && commit) {
 2886                         VI_UNLOCK(vp);
 2887                         goto loop;
 2888                 }
 2889         }
 2890         VI_UNLOCK(vp);
 2891         if (np->n_flag & NWRITEERR) {
 2892                 error = np->n_error;
 2893                 np->n_flag &= ~NWRITEERR;
 2894         }
 2895 done:
 2896         if (bvec != NULL && bvec != bvec_on_stack)
 2897                 free(bvec, M_TEMP);
 2898         return (error);
 2899 }
 2900 
 2901 /*
 2902  * NFS advisory byte-level locks.
 2903  */
 2904 static int
 2905 nfs4_advlock(struct vop_advlock_args *ap)
 2906 {
 2907         return (EPERM);
 2908 
 2909         if ((VFSTONFS(ap->a_vp->v_mount)->nm_flag & NFSMNT_NOLOCKD) != 0) {
 2910                 struct nfsnode *np = VTONFS(ap->a_vp);
 2911 
 2912                 return (lf_advlock(ap, &(np->n_lockf), np->n_size));
 2913         }
 2914         return (nfs_dolock(ap));
 2915 }
 2916 
 2917 /*
 2918  * Print out the contents of an nfsnode.
 2919  */
 2920 static int
 2921 nfs4_print(struct vop_print_args *ap)
 2922 {
 2923         struct vnode *vp = ap->a_vp;
 2924         struct nfsnode *np = VTONFS(vp);
 2925 
 2926         printf("\tfileid %ld fsid 0x%x",
 2927            np->n_vattr.va_fileid, np->n_vattr.va_fsid);
 2928         if (vp->v_type == VFIFO)
 2929                 fifo_printinfo(vp);
 2930         printf("\n");
 2931         return (0);
 2932 }
 2933 
 2934 /*
 2935  * This is the "real" nfs::bwrite(struct buf*).
 2936  * B_WRITEINPROG isn't set unless the force flag is one and it
 2937  * handles the B_NEEDCOMMIT flag.
 2938  * We set B_CACHE if this is a VMIO buffer.
 2939  */
 2940 int
 2941 nfs4_writebp(struct buf *bp, int force, struct thread *td)
 2942 {
 2943         int s;
 2944         int oldflags = bp->b_flags;
 2945 #if 0
 2946         int retv = 1;
 2947         off_t off;
 2948 #endif
 2949 
 2950         if (BUF_REFCNT(bp) == 0)
 2951                 panic("bwrite: buffer is not locked???");
 2952 
 2953         if (bp->b_flags & B_INVAL) {
 2954                 brelse(bp);
 2955                 return(0);
 2956         }
 2957 
 2958         bp->b_flags |= B_CACHE;
 2959 
 2960         /*
 2961          * Undirty the bp.  We will redirty it later if the I/O fails.
 2962          */
 2963 
 2964         s = splbio();
 2965         bundirty(bp);
 2966         bp->b_flags &= ~B_DONE;
 2967         bp->b_ioflags &= ~BIO_ERROR;
 2968         bp->b_iocmd = BIO_WRITE;
 2969 
 2970         VI_LOCK(bp->b_vp);
 2971         bp->b_vp->v_numoutput++;
 2972         VI_UNLOCK(bp->b_vp);
 2973         curthread->td_proc->p_stats->p_ru.ru_oublock++;
 2974         splx(s);
 2975 
 2976         /*
 2977          * Note: to avoid loopback deadlocks, we do not
 2978          * assign b_runningbufspace.
 2979          */
 2980         vfs_busy_pages(bp, 1);
 2981 
 2982         if (force)
 2983                 bp->b_flags |= B_WRITEINPROG;
 2984         BUF_KERNPROC(bp);
 2985         bp->b_iooffset = dbtob(bp->b_blkno);
 2986         VOP_STRATEGY(bp->b_vp, bp);
 2987 
 2988         if( (oldflags & B_ASYNC) == 0) {
 2989                 int rtval = bufwait(bp);
 2990 
 2991                 if (oldflags & B_DELWRI) {
 2992                         s = splbio();
 2993                         reassignbuf(bp);
 2994                         splx(s);
 2995                 }
 2996 
 2997                 brelse(bp);
 2998                 return (rtval);
 2999         }
 3000 
 3001         return (0);
 3002 }
 3003 
 3004 /*
 3005  * nfs special file access vnode op.
 3006  * Essentially just get vattr and then imitate iaccess() since the device is
 3007  * local to the client.
 3008  */
 3009 static int
 3010 nfsspec_access(struct vop_access_args *ap)
 3011 {
 3012         struct vattr *vap;
 3013         struct ucred *cred = ap->a_cred;
 3014         struct vnode *vp = ap->a_vp;
 3015         mode_t mode = ap->a_mode;
 3016         struct vattr vattr;
 3017         int error;
 3018 
 3019         /*
 3020          * Disallow write attempts on filesystems mounted read-only;
 3021          * unless the file is a socket, fifo, or a block or character
 3022          * device resident on the filesystem.
 3023          */
 3024         if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
 3025                 switch (vp->v_type) {
 3026                 case VREG:
 3027                 case VDIR:
 3028                 case VLNK:
 3029                         return (EROFS);
 3030                 default:
 3031                         break;
 3032                 }
 3033         }
 3034         vap = &vattr;
 3035         error = VOP_GETATTR(vp, vap, cred, ap->a_td);
 3036         if (error)
 3037                 return (error);
 3038         return (vaccess(vp->v_type, vap->va_mode, vap->va_uid, vap->va_gid,
 3039             mode, cred, NULL));
 3040 }
 3041 
 3042 /*
 3043  * Read wrapper for special devices.
 3044  */
 3045 static int
 3046 nfsspec_read(struct vop_read_args *ap)
 3047 {
 3048         struct nfsnode *np = VTONFS(ap->a_vp);
 3049 
 3050         /*
 3051          * Set access flag.
 3052          */
 3053         np->n_flag |= NACC;
 3054         getnanotime(&np->n_atim);
 3055         return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
 3056 }
 3057 
 3058 /*
 3059  * Write wrapper for special devices.
 3060  */
 3061 static int
 3062 nfsspec_write(struct vop_write_args *ap)
 3063 {
 3064         struct nfsnode *np = VTONFS(ap->a_vp);
 3065 
 3066         /*
 3067          * Set update flag.
 3068          */
 3069         np->n_flag |= NUPD;
 3070         getnanotime(&np->n_mtim);
 3071         return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
 3072 }
 3073 
 3074 /*
 3075  * Close wrapper for special devices.
 3076  *
 3077  * Update the times on the nfsnode then do device close.
 3078  */
 3079 static int
 3080 nfsspec_close(struct vop_close_args *ap)
 3081 {
 3082         struct vnode *vp = ap->a_vp;
 3083         struct nfsnode *np = VTONFS(vp);
 3084         struct vattr vattr;
 3085 
 3086         if (np->n_flag & (NACC | NUPD)) {
 3087                 np->n_flag |= NCHG;
 3088                 if (vrefcnt(vp) == 1 &&
 3089                     (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
 3090                         VATTR_NULL(&vattr);
 3091                         if (np->n_flag & NACC)
 3092                                 vattr.va_atime = np->n_atim;
 3093                         if (np->n_flag & NUPD)
 3094                                 vattr.va_mtime = np->n_mtim;
 3095                         (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_td);
 3096                 }
 3097         }
 3098         return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
 3099 }
 3100 
 3101 /*
 3102  * Read wrapper for fifos.
 3103  */
 3104 static int
 3105 nfsfifo_read(struct vop_read_args *ap)
 3106 {
 3107         struct nfsnode *np = VTONFS(ap->a_vp);
 3108 
 3109         /*
 3110          * Set access flag.
 3111          */
 3112         np->n_flag |= NACC;
 3113         getnanotime(&np->n_atim);
 3114         return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
 3115 }
 3116 
 3117 /*
 3118  * Write wrapper for fifos.
 3119  */
 3120 static int
 3121 nfsfifo_write(struct vop_write_args *ap)
 3122 {
 3123         struct nfsnode *np = VTONFS(ap->a_vp);
 3124 
 3125         /*
 3126          * Set update flag.
 3127          */
 3128         np->n_flag |= NUPD;
 3129         getnanotime(&np->n_mtim);
 3130         return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
 3131 }
 3132 
 3133 /*
 3134  * Close wrapper for fifos.
 3135  *
 3136  * Update the times on the nfsnode then do fifo close.
 3137  */
 3138 static int
 3139 nfsfifo_close(struct vop_close_args *ap)
 3140 {
 3141         struct vnode *vp = ap->a_vp;
 3142         struct nfsnode *np = VTONFS(vp);
 3143         struct vattr vattr;
 3144         struct timespec ts;
 3145 
 3146         if (np->n_flag & (NACC | NUPD)) {
 3147                 getnanotime(&ts);
 3148                 if (np->n_flag & NACC)
 3149                         np->n_atim = ts;
 3150                 if (np->n_flag & NUPD)
 3151                         np->n_mtim = ts;
 3152                 np->n_flag |= NCHG;
 3153                 if (vrefcnt(vp) == 1 &&
 3154                     (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
 3155                         VATTR_NULL(&vattr);
 3156                         if (np->n_flag & NACC)
 3157                                 vattr.va_atime = np->n_atim;
 3158                         if (np->n_flag & NUPD)
 3159                                 vattr.va_mtime = np->n_mtim;
 3160                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_td);
 3161                         (void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_td);
 3162                         VOP_UNLOCK(vp, 0, ap->a_td);
 3163                 }
 3164         }
 3165         return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
 3166 }
 3167 

Cache object: 0fba5034a2706b14b407da5623dfdf1f


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


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