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

Cache object: 2b0c2df30add1f639948b828a9f4fffe


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