root/nfs/nfs_vnops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfs_null
  2. nfs_access
  3. nfs_open
  4. nfs_close
  5. nfs_getattr
  6. nfs_setattr
  7. nfs_setattrrpc
  8. nfs_lookup
  9. nfs_read
  10. nfs_readlink
  11. nfs_readlinkrpc
  12. nfs_readrpc
  13. nfs_writerpc
  14. nfs_mknodrpc
  15. nfs_mknod
  16. nfs_create
  17. nfs_remove
  18. nfs_removeit
  19. nfs_removerpc
  20. nfs_rename
  21. nfs_renameit
  22. nfs_renamerpc
  23. nfs_link
  24. nfs_symlink
  25. nfs_mkdir
  26. nfs_rmdir
  27. nfs_readdir
  28. nfs_readdirrpc
  29. nfs_readdirplusrpc
  30. nfs_sillyrename
  31. nfs_lookitup
  32. nfs_commit
  33. nfs_bmap
  34. nfs_strategy
  35. nfs_fsync
  36. nfs_flush
  37. nfs_pathconf
  38. nfs_advlock
  39. nfs_print
  40. nfs_bwrite
  41. nfs_writebp
  42. nfsspec_access
  43. nfs_poll
  44. nfsspec_read
  45. nfsspec_write
  46. nfsspec_close
  47. nfsfifo_read
  48. nfsfifo_write
  49. nfsfifo_close
  50. nfsfifo_reclaim

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

/* [<][>][^][v][top][bottom][index][help] */