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


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

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

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

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

Cache object: 3159edf77dbd4a5608f8115c99e5e6c1


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