root/nfs/nfs_subs.c

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

DEFINITIONS

This source file includes following definitions.
  1. nfsm_reqh
  2. nfsm_rpchead
  3. nfsm_mbuftouio
  4. nfsm_uiotombuf
  5. nfsm_disct
  6. nfs_adv
  7. nfsm_strtmbuf
  8. nfs_init
  9. nfs_vfs_init
  10. nfs_loadattrcache
  11. nfs_attrtimeo
  12. nfs_getattrcache
  13. nfs_namei
  14. nfsm_adj
  15. nfsm_srvwcc
  16. nfsm_srvpostopattr
  17. nfsm_srvfattr
  18. nfsrv_fhtovp
  19. netaddr_match
  20. nfs_clearcommit
  21. nfs_merge_commit_ranges
  22. nfs_in_committed_range
  23. nfs_in_tobecommitted_range
  24. nfs_add_committed_range
  25. nfs_del_committed_range
  26. nfs_add_tobecommitted_range
  27. nfs_del_tobecommitted_range
  28. nfsrv_errmap
  29. nfsrvw_sort
  30. nfsrv_setcred

    1 /*      $OpenBSD: nfs_subs.c,v 1.61 2007/04/19 14:46:44 thib Exp $      */
    2 /*      $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 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_subs.c  8.8 (Berkeley) 5/22/95
   36  */
   37 
   38 
   39 /*
   40  * These functions support the macros and help fiddle mbuf chains for
   41  * the nfs op functions. They do things like create the rpc header and
   42  * copy data between mbuf chains and uio lists.
   43  */
   44 #include <sys/param.h>
   45 #include <sys/proc.h>
   46 #include <sys/systm.h>
   47 #include <sys/kernel.h>
   48 #include <sys/mount.h>
   49 #include <sys/vnode.h>
   50 #include <sys/namei.h>
   51 #include <sys/mbuf.h>
   52 #include <sys/socket.h>
   53 #include <sys/socketvar.h>
   54 #include <sys/stat.h>
   55 #include <sys/malloc.h>
   56 #include <sys/pool.h>
   57 #include <sys/time.h>
   58 
   59 #include <uvm/uvm_extern.h>
   60 
   61 #include <nfs/rpcv2.h>
   62 #include <nfs/nfsproto.h>
   63 #include <nfs/nfsnode.h>
   64 #include <nfs/nfs.h>
   65 #include <nfs/xdr_subs.h>
   66 #include <nfs/nfsm_subs.h>
   67 #include <nfs/nfsmount.h>
   68 #include <nfs/nfsrtt.h>
   69 #include <nfs/nfs_var.h>
   70 
   71 #include <miscfs/specfs/specdev.h>
   72 
   73 #include <netinet/in.h>
   74 
   75 #include <dev/rndvar.h>
   76 
   77 #ifdef __GNUC__
   78 #define INLINE __inline
   79 #else
   80 #define INLINE
   81 #endif
   82 
   83 int     nfs_attrtimeo(struct nfsnode *np);
   84 
   85 /*
   86  * Data items converted to xdr at startup, since they are constant
   87  * This is kinda hokey, but may save a little time doing byte swaps
   88  */
   89 u_int32_t nfs_xdrneg1;
   90 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
   91         rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
   92         rpc_auth_kerb;
   93 u_int32_t nfs_prog, nfs_true, nfs_false;
   94 
   95 /* And other global data */
   96 static u_int32_t nfs_xid = 0;
   97 static u_int32_t nfs_xid_touched = 0;
   98 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
   99                       NFCHR, NFNON };
  100 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
  101                       NFFIFO, NFNON };
  102 enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
  103 enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
  104 int nfs_ticks;
  105 struct nfsstats nfsstats;
  106 
  107 /*
  108  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
  109  */
  110 int nfsv3_procid[NFS_NPROCS] = {
  111         NFSPROC_NULL,
  112         NFSPROC_GETATTR,
  113         NFSPROC_SETATTR,
  114         NFSPROC_NOOP,
  115         NFSPROC_LOOKUP,
  116         NFSPROC_READLINK,
  117         NFSPROC_READ,
  118         NFSPROC_NOOP,
  119         NFSPROC_WRITE,
  120         NFSPROC_CREATE,
  121         NFSPROC_REMOVE,
  122         NFSPROC_RENAME,
  123         NFSPROC_LINK,
  124         NFSPROC_SYMLINK,
  125         NFSPROC_MKDIR,
  126         NFSPROC_RMDIR,
  127         NFSPROC_READDIR,
  128         NFSPROC_FSSTAT,
  129         NFSPROC_NOOP,
  130         NFSPROC_NOOP,
  131         NFSPROC_NOOP,
  132         NFSPROC_NOOP,
  133         NFSPROC_NOOP,
  134         NFSPROC_NOOP,
  135         NFSPROC_NOOP,
  136         NFSPROC_NOOP
  137 };
  138 
  139 /*
  140  * and the reverse mapping from generic to Version 2 procedure numbers
  141  */
  142 int nfsv2_procid[NFS_NPROCS] = {
  143         NFSV2PROC_NULL,
  144         NFSV2PROC_GETATTR,
  145         NFSV2PROC_SETATTR,
  146         NFSV2PROC_LOOKUP,
  147         NFSV2PROC_NOOP,
  148         NFSV2PROC_READLINK,
  149         NFSV2PROC_READ,
  150         NFSV2PROC_WRITE,
  151         NFSV2PROC_CREATE,
  152         NFSV2PROC_MKDIR,
  153         NFSV2PROC_SYMLINK,
  154         NFSV2PROC_CREATE,
  155         NFSV2PROC_REMOVE,
  156         NFSV2PROC_RMDIR,
  157         NFSV2PROC_RENAME,
  158         NFSV2PROC_LINK,
  159         NFSV2PROC_READDIR,
  160         NFSV2PROC_NOOP,
  161         NFSV2PROC_STATFS,
  162         NFSV2PROC_NOOP,
  163         NFSV2PROC_NOOP,
  164         NFSV2PROC_NOOP,
  165         NFSV2PROC_NOOP,
  166         NFSV2PROC_NOOP,
  167         NFSV2PROC_NOOP,
  168         NFSV2PROC_NOOP,
  169 };
  170 
  171 /*
  172  * Maps errno values to nfs error numbers.
  173  * Use NFSERR_IO as the catch all for ones not specifically defined in
  174  * RFC 1094.
  175  */
  176 static u_char nfsrv_v2errmap[ELAST] = {
  177   NFSERR_PERM,  NFSERR_NOENT,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  178   NFSERR_NXIO,  NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  179   NFSERR_IO,    NFSERR_IO,      NFSERR_ACCES,   NFSERR_IO,      NFSERR_IO,
  180   NFSERR_IO,    NFSERR_EXIST,   NFSERR_IO,      NFSERR_NODEV,   NFSERR_NOTDIR,
  181   NFSERR_ISDIR, NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  182   NFSERR_IO,    NFSERR_FBIG,    NFSERR_NOSPC,   NFSERR_IO,      NFSERR_ROFS,
  183   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  184   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  185   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  186   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  187   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  188   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  189   NFSERR_IO,    NFSERR_IO,      NFSERR_NAMETOL, NFSERR_IO,      NFSERR_IO,
  190   NFSERR_NOTEMPTY, NFSERR_IO,   NFSERR_IO,      NFSERR_DQUOT,   NFSERR_STALE,
  191   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  192   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  193   NFSERR_IO,
  194 };
  195 
  196 /*
  197  * Maps errno values to nfs error numbers.
  198  * Although it is not obvious whether or not NFS clients really care if
  199  * a returned error value is in the specified list for the procedure, the
  200  * safest thing to do is filter them appropriately. For Version 2, the
  201  * X/Open XNFS document is the only specification that defines error values
  202  * for each RPC (The RFC simply lists all possible error values for all RPCs),
  203  * so I have decided to not do this for Version 2.
  204  * The first entry is the default error return and the rest are the valid
  205  * errors for that RPC in increasing numeric order.
  206  */
  207 static short nfsv3err_null[] = {
  208         0,
  209         0,
  210 };
  211 
  212 static short nfsv3err_getattr[] = {
  213         NFSERR_IO,
  214         NFSERR_IO,
  215         NFSERR_STALE,
  216         NFSERR_BADHANDLE,
  217         NFSERR_SERVERFAULT,
  218         0,
  219 };
  220 
  221 static short nfsv3err_setattr[] = {
  222         NFSERR_IO,
  223         NFSERR_PERM,
  224         NFSERR_IO,
  225         NFSERR_ACCES,
  226         NFSERR_INVAL,
  227         NFSERR_NOSPC,
  228         NFSERR_ROFS,
  229         NFSERR_DQUOT,
  230         NFSERR_STALE,
  231         NFSERR_BADHANDLE,
  232         NFSERR_NOT_SYNC,
  233         NFSERR_SERVERFAULT,
  234         0,
  235 };
  236 
  237 static short nfsv3err_lookup[] = {
  238         NFSERR_IO,
  239         NFSERR_NOENT,
  240         NFSERR_IO,
  241         NFSERR_ACCES,
  242         NFSERR_NOTDIR,
  243         NFSERR_NAMETOL,
  244         NFSERR_STALE,
  245         NFSERR_BADHANDLE,
  246         NFSERR_SERVERFAULT,
  247         0,
  248 };
  249 
  250 static short nfsv3err_access[] = {
  251         NFSERR_IO,
  252         NFSERR_IO,
  253         NFSERR_STALE,
  254         NFSERR_BADHANDLE,
  255         NFSERR_SERVERFAULT,
  256         0,
  257 };
  258 
  259 static short nfsv3err_readlink[] = {
  260         NFSERR_IO,
  261         NFSERR_IO,
  262         NFSERR_ACCES,
  263         NFSERR_INVAL,
  264         NFSERR_STALE,
  265         NFSERR_BADHANDLE,
  266         NFSERR_NOTSUPP,
  267         NFSERR_SERVERFAULT,
  268         0,
  269 };
  270 
  271 static short nfsv3err_read[] = {
  272         NFSERR_IO,
  273         NFSERR_IO,
  274         NFSERR_NXIO,
  275         NFSERR_ACCES,
  276         NFSERR_INVAL,
  277         NFSERR_STALE,
  278         NFSERR_BADHANDLE,
  279         NFSERR_SERVERFAULT,
  280         0,
  281 };
  282 
  283 static short nfsv3err_write[] = {
  284         NFSERR_IO,
  285         NFSERR_IO,
  286         NFSERR_ACCES,
  287         NFSERR_INVAL,
  288         NFSERR_FBIG,
  289         NFSERR_NOSPC,
  290         NFSERR_ROFS,
  291         NFSERR_DQUOT,
  292         NFSERR_STALE,
  293         NFSERR_BADHANDLE,
  294         NFSERR_SERVERFAULT,
  295         0,
  296 };
  297 
  298 static short nfsv3err_create[] = {
  299         NFSERR_IO,
  300         NFSERR_IO,
  301         NFSERR_ACCES,
  302         NFSERR_EXIST,
  303         NFSERR_NOTDIR,
  304         NFSERR_NOSPC,
  305         NFSERR_ROFS,
  306         NFSERR_NAMETOL,
  307         NFSERR_DQUOT,
  308         NFSERR_STALE,
  309         NFSERR_BADHANDLE,
  310         NFSERR_NOTSUPP,
  311         NFSERR_SERVERFAULT,
  312         0,
  313 };
  314 
  315 static short nfsv3err_mkdir[] = {
  316         NFSERR_IO,
  317         NFSERR_IO,
  318         NFSERR_ACCES,
  319         NFSERR_EXIST,
  320         NFSERR_NOTDIR,
  321         NFSERR_NOSPC,
  322         NFSERR_ROFS,
  323         NFSERR_NAMETOL,
  324         NFSERR_DQUOT,
  325         NFSERR_STALE,
  326         NFSERR_BADHANDLE,
  327         NFSERR_NOTSUPP,
  328         NFSERR_SERVERFAULT,
  329         0,
  330 };
  331 
  332 static short nfsv3err_symlink[] = {
  333         NFSERR_IO,
  334         NFSERR_IO,
  335         NFSERR_ACCES,
  336         NFSERR_EXIST,
  337         NFSERR_NOTDIR,
  338         NFSERR_NOSPC,
  339         NFSERR_ROFS,
  340         NFSERR_NAMETOL,
  341         NFSERR_DQUOT,
  342         NFSERR_STALE,
  343         NFSERR_BADHANDLE,
  344         NFSERR_NOTSUPP,
  345         NFSERR_SERVERFAULT,
  346         0,
  347 };
  348 
  349 static short nfsv3err_mknod[] = {
  350         NFSERR_IO,
  351         NFSERR_IO,
  352         NFSERR_ACCES,
  353         NFSERR_EXIST,
  354         NFSERR_NOTDIR,
  355         NFSERR_NOSPC,
  356         NFSERR_ROFS,
  357         NFSERR_NAMETOL,
  358         NFSERR_DQUOT,
  359         NFSERR_STALE,
  360         NFSERR_BADHANDLE,
  361         NFSERR_NOTSUPP,
  362         NFSERR_SERVERFAULT,
  363         NFSERR_BADTYPE,
  364         0,
  365 };
  366 
  367 static short nfsv3err_remove[] = {
  368         NFSERR_IO,
  369         NFSERR_NOENT,
  370         NFSERR_IO,
  371         NFSERR_ACCES,
  372         NFSERR_NOTDIR,
  373         NFSERR_ROFS,
  374         NFSERR_NAMETOL,
  375         NFSERR_STALE,
  376         NFSERR_BADHANDLE,
  377         NFSERR_SERVERFAULT,
  378         0,
  379 };
  380 
  381 static short nfsv3err_rmdir[] = {
  382         NFSERR_IO,
  383         NFSERR_NOENT,
  384         NFSERR_IO,
  385         NFSERR_ACCES,
  386         NFSERR_EXIST,
  387         NFSERR_NOTDIR,
  388         NFSERR_INVAL,
  389         NFSERR_ROFS,
  390         NFSERR_NAMETOL,
  391         NFSERR_NOTEMPTY,
  392         NFSERR_STALE,
  393         NFSERR_BADHANDLE,
  394         NFSERR_NOTSUPP,
  395         NFSERR_SERVERFAULT,
  396         0,
  397 };
  398 
  399 static short nfsv3err_rename[] = {
  400         NFSERR_IO,
  401         NFSERR_NOENT,
  402         NFSERR_IO,
  403         NFSERR_ACCES,
  404         NFSERR_EXIST,
  405         NFSERR_XDEV,
  406         NFSERR_NOTDIR,
  407         NFSERR_ISDIR,
  408         NFSERR_INVAL,
  409         NFSERR_NOSPC,
  410         NFSERR_ROFS,
  411         NFSERR_MLINK,
  412         NFSERR_NAMETOL,
  413         NFSERR_NOTEMPTY,
  414         NFSERR_DQUOT,
  415         NFSERR_STALE,
  416         NFSERR_BADHANDLE,
  417         NFSERR_NOTSUPP,
  418         NFSERR_SERVERFAULT,
  419         0,
  420 };
  421 
  422 static short nfsv3err_link[] = {
  423         NFSERR_IO,
  424         NFSERR_IO,
  425         NFSERR_ACCES,
  426         NFSERR_EXIST,
  427         NFSERR_XDEV,
  428         NFSERR_NOTDIR,
  429         NFSERR_INVAL,
  430         NFSERR_NOSPC,
  431         NFSERR_ROFS,
  432         NFSERR_MLINK,
  433         NFSERR_NAMETOL,
  434         NFSERR_DQUOT,
  435         NFSERR_STALE,
  436         NFSERR_BADHANDLE,
  437         NFSERR_NOTSUPP,
  438         NFSERR_SERVERFAULT,
  439         0,
  440 };
  441 
  442 static short nfsv3err_readdir[] = {
  443         NFSERR_IO,
  444         NFSERR_IO,
  445         NFSERR_ACCES,
  446         NFSERR_NOTDIR,
  447         NFSERR_STALE,
  448         NFSERR_BADHANDLE,
  449         NFSERR_BAD_COOKIE,
  450         NFSERR_TOOSMALL,
  451         NFSERR_SERVERFAULT,
  452         0,
  453 };
  454 
  455 static short nfsv3err_readdirplus[] = {
  456         NFSERR_IO,
  457         NFSERR_IO,
  458         NFSERR_ACCES,
  459         NFSERR_NOTDIR,
  460         NFSERR_STALE,
  461         NFSERR_BADHANDLE,
  462         NFSERR_BAD_COOKIE,
  463         NFSERR_NOTSUPP,
  464         NFSERR_TOOSMALL,
  465         NFSERR_SERVERFAULT,
  466         0,
  467 };
  468 
  469 static short nfsv3err_fsstat[] = {
  470         NFSERR_IO,
  471         NFSERR_IO,
  472         NFSERR_STALE,
  473         NFSERR_BADHANDLE,
  474         NFSERR_SERVERFAULT,
  475         0,
  476 };
  477 
  478 static short nfsv3err_fsinfo[] = {
  479         NFSERR_STALE,
  480         NFSERR_STALE,
  481         NFSERR_BADHANDLE,
  482         NFSERR_SERVERFAULT,
  483         0,
  484 };
  485 
  486 static short nfsv3err_pathconf[] = {
  487         NFSERR_STALE,
  488         NFSERR_STALE,
  489         NFSERR_BADHANDLE,
  490         NFSERR_SERVERFAULT,
  491         0,
  492 };
  493 
  494 static short nfsv3err_commit[] = {
  495         NFSERR_IO,
  496         NFSERR_IO,
  497         NFSERR_STALE,
  498         NFSERR_BADHANDLE,
  499         NFSERR_SERVERFAULT,
  500         0,
  501 };
  502 
  503 static short *nfsrv_v3errmap[] = {
  504         nfsv3err_null,
  505         nfsv3err_getattr,
  506         nfsv3err_setattr,
  507         nfsv3err_lookup,
  508         nfsv3err_access,
  509         nfsv3err_readlink,
  510         nfsv3err_read,
  511         nfsv3err_write,
  512         nfsv3err_create,
  513         nfsv3err_mkdir,
  514         nfsv3err_symlink,
  515         nfsv3err_mknod,
  516         nfsv3err_remove,
  517         nfsv3err_rmdir,
  518         nfsv3err_rename,
  519         nfsv3err_link,
  520         nfsv3err_readdir,
  521         nfsv3err_readdirplus,
  522         nfsv3err_fsstat,
  523         nfsv3err_fsinfo,
  524         nfsv3err_pathconf,
  525         nfsv3err_commit,
  526 };
  527 
  528 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
  529 extern struct nfsrtt nfsrtt;
  530 
  531 struct pool nfsreqpl;
  532 
  533 /*
  534  * Create the header for an rpc request packet
  535  * The hsiz is the size of the rest of the nfs request header.
  536  * (just used to decide if a cluster is a good idea)
  537  */
  538 struct mbuf *
  539 nfsm_reqh(vp, procid, hsiz, bposp)
  540         struct vnode *vp;
  541         u_long procid;
  542         int hsiz;
  543         caddr_t *bposp;
  544 {
  545         struct mbuf *mb;
  546         caddr_t bpos;
  547 
  548         MGET(mb, M_WAIT, MT_DATA);
  549         if (hsiz >= MINCLSIZE)
  550                 MCLGET(mb, M_WAIT);
  551         mb->m_len = 0;
  552         bpos = mtod(mb, caddr_t);
  553         
  554         /* Finally, return values */
  555         *bposp = bpos;
  556         return (mb);
  557 }
  558 
  559 /*
  560  * Build the RPC header and fill in the authorization info.
  561  * The authorization string argument is only used when the credentials
  562  * come from outside of the kernel.
  563  * Returns the head of the mbuf list.
  564  */
  565 struct mbuf *
  566 nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
  567         verf_str, mrest, mrest_len, mbp, xidp)
  568         struct ucred *cr;
  569         int nmflag;
  570         int procid;
  571         int auth_type;
  572         int auth_len;
  573         char *auth_str;
  574         int verf_len;
  575         char *verf_str;
  576         struct mbuf *mrest;
  577         int mrest_len;
  578         struct mbuf **mbp;
  579         u_int32_t *xidp;
  580 {
  581         struct mbuf *mb;
  582         u_int32_t *tl;
  583         caddr_t bpos;
  584         int i;
  585         struct mbuf *mreq, *mb2;
  586         int siz, grpsiz, authsiz;
  587 
  588         authsiz = nfsm_rndup(auth_len);
  589         MGETHDR(mb, M_WAIT, MT_DATA);
  590         if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
  591                 MCLGET(mb, M_WAIT);
  592         } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
  593                 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
  594         } else {
  595                 MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
  596         }
  597         mb->m_len = 0;
  598         mreq = mb;
  599         bpos = mtod(mb, caddr_t);
  600 
  601         /*
  602          * First the RPC header.
  603          */
  604         nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
  605 
  606         /* Get a new (non-zero) xid */
  607 
  608         if ((nfs_xid == 0) && (nfs_xid_touched == 0)) {
  609                 nfs_xid = arc4random();
  610                 nfs_xid_touched = 1;
  611         } else {
  612                 while ((*xidp = arc4random() % 256) == 0)
  613                         ;
  614                 nfs_xid += *xidp;
  615         }
  616             
  617         *tl++ = *xidp = txdr_unsigned(nfs_xid);
  618         *tl++ = rpc_call;
  619         *tl++ = rpc_vers;
  620         *tl++ = txdr_unsigned(NFS_PROG);
  621         if (nmflag & NFSMNT_NFSV3)
  622                 *tl++ = txdr_unsigned(NFS_VER3);
  623         else
  624                 *tl++ = txdr_unsigned(NFS_VER2);
  625         if (nmflag & NFSMNT_NFSV3)
  626                 *tl++ = txdr_unsigned(procid);
  627         else
  628                 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
  629 
  630         /*
  631          * And then the authorization cred.
  632          */
  633         *tl++ = txdr_unsigned(auth_type);
  634         *tl = txdr_unsigned(authsiz);
  635         switch (auth_type) {
  636         case RPCAUTH_UNIX:
  637                 nfsm_build(tl, u_int32_t *, auth_len);
  638                 *tl++ = 0;              /* stamp ?? */
  639                 *tl++ = 0;              /* NULL hostname */
  640                 *tl++ = txdr_unsigned(cr->cr_uid);
  641                 *tl++ = txdr_unsigned(cr->cr_gid);
  642                 grpsiz = (auth_len >> 2) - 5;
  643                 *tl++ = txdr_unsigned(grpsiz);
  644                 for (i = 0; i < grpsiz; i++)
  645                         *tl++ = txdr_unsigned(cr->cr_groups[i]);
  646                 break;
  647         case RPCAUTH_KERB4:
  648                 siz = auth_len;
  649                 while (siz > 0) {
  650                         if (M_TRAILINGSPACE(mb) == 0) {
  651                                 MGET(mb2, M_WAIT, MT_DATA);
  652                                 if (siz >= MINCLSIZE)
  653                                         MCLGET(mb2, M_WAIT);
  654                                 mb->m_next = mb2;
  655                                 mb = mb2;
  656                                 mb->m_len = 0;
  657                                 bpos = mtod(mb, caddr_t);
  658                         }
  659                         i = min(siz, M_TRAILINGSPACE(mb));
  660                         bcopy(auth_str, bpos, i);
  661                         mb->m_len += i;
  662                         auth_str += i;
  663                         bpos += i;
  664                         siz -= i;
  665                 }
  666                 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
  667                         for (i = 0; i < siz; i++)
  668                                 *bpos++ = '\0';
  669                         mb->m_len += siz;
  670                 }
  671                 break;
  672         };
  673 
  674         /*
  675          * And the verifier...
  676          */
  677         nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  678         if (verf_str) {
  679                 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
  680                 *tl = txdr_unsigned(verf_len);
  681                 siz = verf_len;
  682                 while (siz > 0) {
  683                         if (M_TRAILINGSPACE(mb) == 0) {
  684                                 MGET(mb2, M_WAIT, MT_DATA);
  685                                 if (siz >= MINCLSIZE)
  686                                         MCLGET(mb2, M_WAIT);
  687                                 mb->m_next = mb2;
  688                                 mb = mb2;
  689                                 mb->m_len = 0;
  690                                 bpos = mtod(mb, caddr_t);
  691                         }
  692                         i = min(siz, M_TRAILINGSPACE(mb));
  693                         bcopy(verf_str, bpos, i);
  694                         mb->m_len += i;
  695                         verf_str += i;
  696                         bpos += i;
  697                         siz -= i;
  698                 }
  699                 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
  700                         for (i = 0; i < siz; i++)
  701                                 *bpos++ = '\0';
  702                         mb->m_len += siz;
  703                 }
  704         } else {
  705                 *tl++ = txdr_unsigned(RPCAUTH_NULL);
  706                 *tl = 0;
  707         }
  708         mb->m_next = mrest;
  709         mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
  710         mreq->m_pkthdr.rcvif = (struct ifnet *)0;
  711         *mbp = mb;
  712         return (mreq);
  713 }
  714 
  715 /*
  716  * copies mbuf chain to the uio scatter/gather list
  717  */
  718 int
  719 nfsm_mbuftouio(mrep, uiop, siz, dpos)
  720         struct mbuf **mrep;
  721         struct uio *uiop;
  722         int siz;
  723         caddr_t *dpos;
  724 {
  725         char *mbufcp, *uiocp;
  726         int xfer, left, len;
  727         struct mbuf *mp;
  728         long uiosiz, rem;
  729         int error = 0;
  730 
  731         mp = *mrep;
  732         mbufcp = *dpos;
  733         len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
  734         rem = nfsm_rndup(siz)-siz;
  735         while (siz > 0) {
  736                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
  737                         return (EFBIG);
  738                 left = uiop->uio_iov->iov_len;
  739                 uiocp = uiop->uio_iov->iov_base;
  740                 if (left > siz)
  741                         left = siz;
  742                 uiosiz = left;
  743                 while (left > 0) {
  744                         while (len == 0) {
  745                                 mp = mp->m_next;
  746                                 if (mp == NULL)
  747                                         return (EBADRPC);
  748                                 mbufcp = mtod(mp, caddr_t);
  749                                 len = mp->m_len;
  750                         }
  751                         xfer = (left > len) ? len : left;
  752 #ifdef notdef
  753                         /* Not Yet.. */
  754                         if (uiop->uio_iov->iov_op != NULL)
  755                                 (*(uiop->uio_iov->iov_op))
  756                                 (mbufcp, uiocp, xfer);
  757                         else
  758 #endif
  759                         if (uiop->uio_segflg == UIO_SYSSPACE)
  760                                 bcopy(mbufcp, uiocp, xfer);
  761                         else
  762                                 copyout(mbufcp, uiocp, xfer);
  763                         left -= xfer;
  764                         len -= xfer;
  765                         mbufcp += xfer;
  766                         uiocp += xfer;
  767                         uiop->uio_offset += xfer;
  768                         uiop->uio_resid -= xfer;
  769                 }
  770                 if (uiop->uio_iov->iov_len <= siz) {
  771                         uiop->uio_iovcnt--;
  772                         uiop->uio_iov++;
  773                 } else {
  774                         (char *)uiop->uio_iov->iov_base += uiosiz;
  775                         uiop->uio_iov->iov_len -= uiosiz;
  776                 }
  777                 siz -= uiosiz;
  778         }
  779         *dpos = mbufcp;
  780         *mrep = mp;
  781         if (rem > 0) {
  782                 if (len < rem)
  783                         error = nfs_adv(mrep, dpos, rem, len);
  784                 else
  785                         *dpos += rem;
  786         }
  787         return (error);
  788 }
  789 
  790 /*
  791  * copies a uio scatter/gather list to an mbuf chain.
  792  * NOTE: can ony handle iovcnt == 1
  793  */
  794 int
  795 nfsm_uiotombuf(uiop, mq, siz, bpos)
  796         struct uio *uiop;
  797         struct mbuf **mq;
  798         int siz;
  799         caddr_t *bpos;
  800 {
  801         char *uiocp;
  802         struct mbuf *mp, *mp2;
  803         int xfer, left, mlen;
  804         int uiosiz, clflg, rem;
  805         char *cp;
  806 
  807 #ifdef DIAGNOSTIC
  808         if (uiop->uio_iovcnt != 1)
  809                 panic("nfsm_uiotombuf: iovcnt != 1");
  810 #endif
  811 
  812         if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
  813                 clflg = 1;
  814         else
  815                 clflg = 0;
  816         rem = nfsm_rndup(siz)-siz;
  817         mp = mp2 = *mq;
  818         while (siz > 0) {
  819                 left = uiop->uio_iov->iov_len;
  820                 uiocp = uiop->uio_iov->iov_base;
  821                 if (left > siz)
  822                         left = siz;
  823                 uiosiz = left;
  824                 while (left > 0) {
  825                         mlen = M_TRAILINGSPACE(mp);
  826                         if (mlen == 0) {
  827                                 MGET(mp, M_WAIT, MT_DATA);
  828                                 if (clflg)
  829                                         MCLGET(mp, M_WAIT);
  830                                 mp->m_len = 0;
  831                                 mp2->m_next = mp;
  832                                 mp2 = mp;
  833                                 mlen = M_TRAILINGSPACE(mp);
  834                         }
  835                         xfer = (left > mlen) ? mlen : left;
  836 #ifdef notdef
  837                         /* Not Yet.. */
  838                         if (uiop->uio_iov->iov_op != NULL)
  839                                 (*(uiop->uio_iov->iov_op))
  840                                 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
  841                         else
  842 #endif
  843                         if (uiop->uio_segflg == UIO_SYSSPACE)
  844                                 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
  845                         else
  846                                 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
  847                         mp->m_len += xfer;
  848                         left -= xfer;
  849                         uiocp += xfer;
  850                         uiop->uio_offset += xfer;
  851                         uiop->uio_resid -= xfer;
  852                 }
  853                 (char *)uiop->uio_iov->iov_base += uiosiz;
  854                 uiop->uio_iov->iov_len -= uiosiz;
  855                 siz -= uiosiz;
  856         }
  857         if (rem > 0) {
  858                 if (rem > M_TRAILINGSPACE(mp)) {
  859                         MGET(mp, M_WAIT, MT_DATA);
  860                         mp->m_len = 0;
  861                         mp2->m_next = mp;
  862                 }
  863                 cp = mtod(mp, caddr_t)+mp->m_len;
  864                 for (left = 0; left < rem; left++)
  865                         *cp++ = '\0';
  866                 mp->m_len += rem;
  867                 *bpos = cp;
  868         } else
  869                 *bpos = mtod(mp, caddr_t)+mp->m_len;
  870         *mq = mp;
  871         return (0);
  872 }
  873 
  874 /*
  875  * Help break down an mbuf chain by setting the first siz bytes contiguous
  876  * pointed to by returned val.
  877  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
  878  * cases. (The macros use the vars. dpos and dpos2)
  879  */
  880 int
  881 nfsm_disct(mdp, dposp, siz, left, cp2)
  882         struct mbuf **mdp;
  883         caddr_t *dposp;
  884         int siz;
  885         int left;
  886         caddr_t *cp2;
  887 {
  888         struct mbuf *mp, *mp2;
  889         int siz2, xfer;
  890         caddr_t p;
  891 
  892         mp = *mdp;
  893         while (left == 0) {
  894                 *mdp = mp = mp->m_next;
  895                 if (mp == NULL)
  896                         return (EBADRPC);
  897                 left = mp->m_len;
  898                 *dposp = mtod(mp, caddr_t);
  899         }
  900         if (left >= siz) {
  901                 *cp2 = *dposp;
  902                 *dposp += siz;
  903         } else if (mp->m_next == NULL) {
  904                 return (EBADRPC);
  905         } else if (siz > MHLEN) {
  906                 panic("nfs S too big");
  907         } else {
  908                 MGET(mp2, M_WAIT, MT_DATA);
  909                 mp2->m_next = mp->m_next;
  910                 mp->m_next = mp2;
  911                 mp->m_len -= left;
  912                 mp = mp2;
  913                 *cp2 = p = mtod(mp, caddr_t);
  914                 bcopy(*dposp, p, left);         /* Copy what was left */
  915                 siz2 = siz-left;
  916                 p += left;
  917                 mp2 = mp->m_next;
  918                 /* Loop around copying up the siz2 bytes */
  919                 while (siz2 > 0) {
  920                         if (mp2 == NULL)
  921                                 return (EBADRPC);
  922                         xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
  923                         if (xfer > 0) {
  924                                 bcopy(mtod(mp2, caddr_t), p, xfer);
  925                                 NFSMADV(mp2, xfer);
  926                                 mp2->m_len -= xfer;
  927                                 p += xfer;
  928                                 siz2 -= xfer;
  929                         }
  930                         if (siz2 > 0)
  931                                 mp2 = mp2->m_next;
  932                 }
  933                 mp->m_len = siz;
  934                 *mdp = mp2;
  935                 *dposp = mtod(mp2, caddr_t);
  936         }
  937         return (0);
  938 }
  939 
  940 /*
  941  * Advance the position in the mbuf chain.
  942  */
  943 int
  944 nfs_adv(mdp, dposp, offs, left)
  945         struct mbuf **mdp;
  946         caddr_t *dposp;
  947         int offs;
  948         int left;
  949 {
  950         struct mbuf *m;
  951         int s;
  952 
  953         m = *mdp;
  954         s = left;
  955         while (s < offs) {
  956                 offs -= s;
  957                 m = m->m_next;
  958                 if (m == NULL)
  959                         return (EBADRPC);
  960                 s = m->m_len;
  961         }
  962         *mdp = m;
  963         *dposp = mtod(m, caddr_t)+offs;
  964         return (0);
  965 }
  966 
  967 /*
  968  * Copy a string into mbufs for the hard cases...
  969  */
  970 int
  971 nfsm_strtmbuf(mb, bpos, cp, siz)
  972         struct mbuf **mb;
  973         char **bpos;
  974         char *cp;
  975         long siz;
  976 {
  977         struct mbuf *m1 = NULL, *m2;
  978         long left, xfer, len, tlen;
  979         u_int32_t *tl;
  980         int putsize;
  981 
  982         putsize = 1;
  983         m2 = *mb;
  984         left = M_TRAILINGSPACE(m2);
  985         if (left > 0) {
  986                 tl = ((u_int32_t *)(*bpos));
  987                 *tl++ = txdr_unsigned(siz);
  988                 putsize = 0;
  989                 left -= NFSX_UNSIGNED;
  990                 m2->m_len += NFSX_UNSIGNED;
  991                 if (left > 0) {
  992                         bcopy(cp, (caddr_t) tl, left);
  993                         siz -= left;
  994                         cp += left;
  995                         m2->m_len += left;
  996                         left = 0;
  997                 }
  998         }
  999         /* Loop around adding mbufs */
 1000         while (siz > 0) {
 1001                 MGET(m1, M_WAIT, MT_DATA);
 1002                 if (siz > MLEN)
 1003                         MCLGET(m1, M_WAIT);
 1004                 m1->m_len = NFSMSIZ(m1);
 1005                 m2->m_next = m1;
 1006                 m2 = m1;
 1007                 tl = mtod(m1, u_int32_t *);
 1008                 tlen = 0;
 1009                 if (putsize) {
 1010                         *tl++ = txdr_unsigned(siz);
 1011                         m1->m_len -= NFSX_UNSIGNED;
 1012                         tlen = NFSX_UNSIGNED;
 1013                         putsize = 0;
 1014                 }
 1015                 if (siz < m1->m_len) {
 1016                         len = nfsm_rndup(siz);
 1017                         xfer = siz;
 1018                         if (xfer < len)
 1019                                 *(tl+(xfer>>2)) = 0;
 1020                 } else {
 1021                         xfer = len = m1->m_len;
 1022                 }
 1023                 bcopy(cp, (caddr_t) tl, xfer);
 1024                 m1->m_len = len+tlen;
 1025                 siz -= xfer;
 1026                 cp += xfer;
 1027         }
 1028         *mb = m1;
 1029         *bpos = mtod(m1, caddr_t)+m1->m_len;
 1030         return (0);
 1031 }
 1032 
 1033 /*
 1034  * Called once to initialize data structures...
 1035  */
 1036 void
 1037 nfs_init()
 1038 {
 1039         static struct timeout nfs_timer_to;
 1040 
 1041         nfsrtt.pos = 0;
 1042         rpc_vers = txdr_unsigned(RPC_VER2);
 1043         rpc_call = txdr_unsigned(RPC_CALL);
 1044         rpc_reply = txdr_unsigned(RPC_REPLY);
 1045         rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
 1046         rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
 1047         rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
 1048         rpc_autherr = txdr_unsigned(RPC_AUTHERR);
 1049         rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
 1050         rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
 1051         nfs_prog = txdr_unsigned(NFS_PROG);
 1052         nfs_true = txdr_unsigned(TRUE);
 1053         nfs_false = txdr_unsigned(FALSE);
 1054         nfs_xdrneg1 = txdr_unsigned(-1);
 1055         nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
 1056         if (nfs_ticks < 1)
 1057                 nfs_ticks = 1;
 1058 #ifdef NFSSERVER
 1059         nfsrv_init(0);                  /* Init server data structures */
 1060         nfsrv_initcache();              /* Init the server request cache */
 1061 #endif /* NFSSERVER */
 1062 
 1063         pool_init(&nfsreqpl, sizeof(struct nfsreq), 0, 0, 0, "nfsreqpl",
 1064             &pool_allocator_nointr);
 1065 
 1066         /*
 1067          * Initialize reply list and start timer
 1068          */
 1069         TAILQ_INIT(&nfs_reqq);
 1070 
 1071         timeout_set(&nfs_timer_to, nfs_timer, &nfs_timer_to);
 1072         nfs_timer(&nfs_timer_to);
 1073 }
 1074 
 1075 #ifdef NFSCLIENT
 1076 int
 1077 nfs_vfs_init(vfsp)
 1078         struct vfsconf *vfsp;
 1079 {
 1080         int i;
 1081 
 1082         /* Ensure async daemons disabled */
 1083         for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
 1084                 nfs_iodwant[i] = (struct proc *)0;
 1085         TAILQ_INIT(&nfs_bufq);
 1086         nfs_nhinit();                   /* Init the nfsnode table */
 1087 
 1088         return (0);
 1089 }
 1090 
 1091 /*
 1092  * Attribute cache routines.
 1093  * nfs_loadattrcache() - loads or updates the cache contents from attributes
 1094  *      that are on the mbuf list
 1095  * nfs_getattrcache() - returns valid attributes if found in cache, returns
 1096  *      error otherwise
 1097  */
 1098 
 1099 /*
 1100  * Load the attribute cache (that lives in the nfsnode entry) with
 1101  * the values on the mbuf list and
 1102  * Iff vap not NULL
 1103  *    copy the attributes to *vaper
 1104  */
 1105 int
 1106 nfs_loadattrcache(vpp, mdp, dposp, vaper)
 1107         struct vnode **vpp;
 1108         struct mbuf **mdp;
 1109         caddr_t *dposp;
 1110         struct vattr *vaper;
 1111 {
 1112         struct vnode *vp = *vpp;
 1113         struct vattr *vap;
 1114         struct nfs_fattr *fp;
 1115         extern int (**spec_nfsv2nodeop_p)(void *);
 1116         struct nfsnode *np;
 1117         int32_t t1;
 1118         caddr_t cp2;
 1119         int error = 0;
 1120         int32_t rdev;
 1121         struct mbuf *md;
 1122         enum vtype vtyp;
 1123         mode_t vmode;
 1124         struct timespec mtime;
 1125         struct vnode *nvp;
 1126         int v3 = NFS_ISV3(vp);
 1127 
 1128         md = *mdp;
 1129         t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
 1130         error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
 1131         if (error)
 1132                 return (error);
 1133         fp = (struct nfs_fattr *)cp2;
 1134         if (v3) {
 1135                 vtyp = nfsv3tov_type(fp->fa_type);
 1136                 vmode = fxdr_unsigned(mode_t, fp->fa_mode);
 1137                 rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1),
 1138                         fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2));
 1139                 fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
 1140         } else {
 1141                 vtyp = nfsv2tov_type(fp->fa_type);
 1142                 vmode = fxdr_unsigned(mode_t, fp->fa_mode);
 1143                 if (vtyp == VNON || vtyp == VREG)
 1144                         vtyp = IFTOVT(vmode);
 1145                 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
 1146                 fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
 1147 
 1148                 /*
 1149                  * Really ugly NFSv2 kludge.
 1150                  */
 1151                 if (vtyp == VCHR && rdev == 0xffffffff)
 1152                         vtyp = VFIFO;
 1153         }
 1154 
 1155         /*
 1156          * If v_type == VNON it is a new node, so fill in the v_type,
 1157          * n_mtime fields. Check to see if it represents a special 
 1158          * device, and if so, check for a possible alias. Once the
 1159          * correct vnode has been obtained, fill in the rest of the
 1160          * information.
 1161          */
 1162         np = VTONFS(vp);
 1163         if (vp->v_type != vtyp) {
 1164                 vp->v_type = vtyp;
 1165                 if (vp->v_type == VFIFO) {
 1166 #ifndef FIFO
 1167                         return (EOPNOTSUPP);
 1168 #else
 1169                         extern int (**fifo_nfsv2nodeop_p)(void *);
 1170                         vp->v_op = fifo_nfsv2nodeop_p;
 1171 #endif /* FIFO */
 1172                 }
 1173                 if (vp->v_type == VCHR || vp->v_type == VBLK) {
 1174                         vp->v_op = spec_nfsv2nodeop_p;
 1175                         nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
 1176                         if (nvp) {
 1177                                 /*
 1178                                  * Discard unneeded vnode, but save its nfsnode.
 1179                                  * Since the nfsnode does not have a lock, its
 1180                                  * vnode lock has to be carried over.
 1181                                  */
 1182 
 1183                                 nvp->v_data = vp->v_data;
 1184                                 vp->v_data = NULL;
 1185                                 vp->v_op = spec_vnodeop_p;
 1186                                 vrele(vp);
 1187                                 vgone(vp);
 1188                                 /*
 1189                                  * Reinitialize aliased node.
 1190                                  */
 1191                                 np->n_vnode = nvp;
 1192                                 *vpp = vp = nvp;
 1193                         }
 1194                 }
 1195                 np->n_mtime = mtime.tv_sec;
 1196         }
 1197         vap = &np->n_vattr;
 1198         vap->va_type = vtyp;
 1199         vap->va_mode = (vmode & 07777);
 1200         vap->va_rdev = (dev_t)rdev;
 1201         vap->va_mtime = mtime;
 1202         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
 1203         if (v3) {
 1204                 vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
 1205                 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
 1206                 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
 1207                 vap->va_size = fxdr_hyper(&fp->fa3_size);
 1208                 vap->va_blocksize = NFS_FABLKSIZE;
 1209                 vap->va_bytes = fxdr_hyper(&fp->fa3_used);
 1210                 vap->va_fileid = fxdr_unsigned(int32_t,
 1211                     fp->fa3_fileid.nfsuquad[1]);
 1212                 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
 1213                 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
 1214                 vap->va_flags = 0;
 1215                 vap->va_filerev = 0;
 1216         } else {
 1217                 vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
 1218                 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
 1219                 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
 1220                 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
 1221                 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
 1222                 vap->va_bytes =
 1223                     (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
 1224                     NFS_FABLKSIZE;
 1225                 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
 1226                 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
 1227                 vap->va_flags = 0;
 1228                 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
 1229                     fp->fa2_ctime.nfsv2_sec);
 1230                 vap->va_ctime.tv_nsec = 0;
 1231                 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
 1232                 vap->va_filerev = 0;
 1233         }
 1234         if (vap->va_size != np->n_size) {
 1235                 if (vap->va_type == VREG) {
 1236                         if (np->n_flag & NMODIFIED) {
 1237                                 if (vap->va_size < np->n_size)
 1238                                         vap->va_size = np->n_size;
 1239                                 else
 1240                                         np->n_size = vap->va_size;
 1241                         } else
 1242                                 np->n_size = vap->va_size;
 1243                         uvm_vnp_setsize(vp, np->n_size);
 1244                 } else
 1245                         np->n_size = vap->va_size;
 1246         }
 1247         np->n_attrstamp = time_second;
 1248         if (vaper != NULL) {
 1249                 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
 1250                 if (np->n_flag & NCHG) {
 1251                         if (np->n_flag & NACC)
 1252                                 vaper->va_atime = np->n_atim;
 1253                         if (np->n_flag & NUPD)
 1254                                 vaper->va_mtime = np->n_mtim;
 1255                 }
 1256         }
 1257         return (0);
 1258 }
 1259 
 1260 INLINE int
 1261 nfs_attrtimeo (np)
 1262         struct nfsnode *np;
 1263 {
 1264         struct vnode *vp = np->n_vnode;
 1265         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 1266         int tenthage = (time_second - np->n_mtime) / 10;
 1267         int minto, maxto;
 1268 
 1269         if (vp->v_type == VDIR) {
 1270                 maxto = nmp->nm_acdirmax;
 1271                 minto = nmp->nm_acdirmin;
 1272         }
 1273         else {
 1274                 maxto = nmp->nm_acregmax;
 1275                 minto = nmp->nm_acregmin;
 1276         }
 1277 
 1278         if (np->n_flag & NMODIFIED || tenthage < minto)
 1279                 return minto;
 1280         else if (tenthage < maxto)
 1281                 return tenthage;
 1282         else
 1283                 return maxto;
 1284 }
 1285 
 1286 /*
 1287  * Check the time stamp
 1288  * If the cache is valid, copy contents to *vap and return 0
 1289  * otherwise return an error
 1290  */
 1291 int
 1292 nfs_getattrcache(vp, vaper)
 1293         struct vnode *vp;
 1294         struct vattr *vaper;
 1295 {
 1296         struct nfsnode *np = VTONFS(vp);
 1297         struct vattr *vap;
 1298 
 1299         if (np->n_attrstamp == 0 ||
 1300             (time_second - np->n_attrstamp) >= nfs_attrtimeo(np)) {
 1301                 nfsstats.attrcache_misses++;
 1302                 return (ENOENT);
 1303         }
 1304         nfsstats.attrcache_hits++;
 1305         vap = &np->n_vattr;
 1306         if (vap->va_size != np->n_size) {
 1307                 if (vap->va_type == VREG) {
 1308                         if (np->n_flag & NMODIFIED) {
 1309                                 if (vap->va_size < np->n_size)
 1310                                         vap->va_size = np->n_size;
 1311                                 else
 1312                                         np->n_size = vap->va_size;
 1313                         } else
 1314                                 np->n_size = vap->va_size;
 1315                         uvm_vnp_setsize(vp, np->n_size);
 1316                 } else
 1317                         np->n_size = vap->va_size;
 1318         }
 1319         bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
 1320         if (np->n_flag & NCHG) {
 1321                 if (np->n_flag & NACC)
 1322                         vaper->va_atime = np->n_atim;
 1323                 if (np->n_flag & NUPD)
 1324                         vaper->va_mtime = np->n_mtim;
 1325         }
 1326         return (0);
 1327 }
 1328 #endif /* NFSCLIENT */
 1329 
 1330 /*
 1331  * Set up nameidata for a lookup() call and do it
 1332  */
 1333 int
 1334 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
 1335         struct nameidata *ndp;
 1336         fhandle_t *fhp;
 1337         int len;
 1338         struct nfssvc_sock *slp;
 1339         struct mbuf *nam;
 1340         struct mbuf **mdp;
 1341         caddr_t *dposp;
 1342         struct vnode **retdirp;
 1343         struct proc *p;
 1344         int kerbflag;
 1345 {
 1346         int i, rem;
 1347         struct mbuf *md;
 1348         char *fromcp, *tocp;
 1349         struct vnode *dp;
 1350         int error, rdonly;
 1351         struct componentname *cnp = &ndp->ni_cnd;
 1352 
 1353         *retdirp = (struct vnode *)0;
 1354         cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
 1355         /*
 1356          * Copy the name from the mbuf list to ndp->ni_pnbuf
 1357          * and set the various ndp fields appropriately.
 1358          */
 1359         fromcp = *dposp;
 1360         tocp = cnp->cn_pnbuf;
 1361         md = *mdp;
 1362         rem = mtod(md, caddr_t) + md->m_len - fromcp;
 1363         cnp->cn_hash = 0;
 1364         for (i = 0; i < len; i++) {
 1365                 while (rem == 0) {
 1366                         md = md->m_next;
 1367                         if (md == NULL) {
 1368                                 error = EBADRPC;
 1369                                 goto out;
 1370                         }
 1371                         fromcp = mtod(md, caddr_t);
 1372                         rem = md->m_len;
 1373                 }
 1374                 if (*fromcp == '\0' || *fromcp == '/') {
 1375                         error = EACCES;
 1376                         goto out;
 1377                 }
 1378                 cnp->cn_hash += (u_char)*fromcp;
 1379                 *tocp++ = *fromcp++;
 1380                 rem--;
 1381         }
 1382         *tocp = '\0';
 1383         *mdp = md;
 1384         *dposp = fromcp;
 1385         len = nfsm_rndup(len)-len;
 1386         if (len > 0) {
 1387                 if (rem >= len)
 1388                         *dposp += len;
 1389                 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
 1390                         goto out;
 1391         }
 1392         ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
 1393         cnp->cn_nameptr = cnp->cn_pnbuf;
 1394         /*
 1395          * Extract and set starting directory.
 1396          */
 1397         error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
 1398             nam, &rdonly, kerbflag);
 1399         if (error)
 1400                 goto out;
 1401         if (dp->v_type != VDIR) {
 1402                 vrele(dp);
 1403                 error = ENOTDIR;
 1404                 goto out;
 1405         }
 1406         VREF(dp);
 1407         *retdirp = dp;
 1408         ndp->ni_startdir = dp;
 1409         if (rdonly)
 1410                 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
 1411         else
 1412                 cnp->cn_flags |= NOCROSSMOUNT;
 1413         /*
 1414          * And call lookup() to do the real work
 1415          */
 1416         cnp->cn_proc = p;
 1417         error = lookup(ndp);
 1418         if (error)
 1419                 goto out;
 1420         /*
 1421          * Check for encountering a symbolic link
 1422          */
 1423         if (cnp->cn_flags & ISSYMLINK) {
 1424                 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
 1425                         vput(ndp->ni_dvp);
 1426                 else
 1427                         vrele(ndp->ni_dvp);
 1428                 vput(ndp->ni_vp);
 1429                 ndp->ni_vp = NULL;
 1430                 error = EINVAL;
 1431                 goto out;
 1432         }
 1433         /*
 1434          * Check for saved name request
 1435          */
 1436         if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
 1437                 cnp->cn_flags |= HASBUF;
 1438                 return (0);
 1439         }
 1440 out:
 1441         pool_put(&namei_pool, cnp->cn_pnbuf);
 1442         return (error);
 1443 }
 1444 
 1445 /*
 1446  * A fiddled version of m_adj() that ensures null fill to a long
 1447  * boundary and only trims off the back end
 1448  */
 1449 void
 1450 nfsm_adj(mp, len, nul)
 1451         struct mbuf *mp;
 1452         int len;
 1453         int nul;
 1454 {
 1455         struct mbuf *m;
 1456         int count, i;
 1457         char *cp;
 1458 
 1459         /*
 1460          * Trim from tail.  Scan the mbuf chain,
 1461          * calculating its length and finding the last mbuf.
 1462          * If the adjustment only affects this mbuf, then just
 1463          * adjust and return.  Otherwise, rescan and truncate
 1464          * after the remaining size.
 1465          */
 1466         count = 0;
 1467         m = mp;
 1468         for (;;) {
 1469                 count += m->m_len;
 1470                 if (m->m_next == (struct mbuf *)0)
 1471                         break;
 1472                 m = m->m_next;
 1473         }
 1474         if (m->m_len > len) {
 1475                 m->m_len -= len;
 1476                 if (nul > 0) {
 1477                         cp = mtod(m, caddr_t)+m->m_len-nul;
 1478                         for (i = 0; i < nul; i++)
 1479                                 *cp++ = '\0';
 1480                 }
 1481                 return;
 1482         }
 1483         count -= len;
 1484         if (count < 0)
 1485                 count = 0;
 1486         /*
 1487          * Correct length for chain is "count".
 1488          * Find the mbuf with last data, adjust its length,
 1489          * and toss data from remaining mbufs on chain.
 1490          */
 1491         for (m = mp; m; m = m->m_next) {
 1492                 if (m->m_len >= count) {
 1493                         m->m_len = count;
 1494                         if (nul > 0) {
 1495                                 cp = mtod(m, caddr_t)+m->m_len-nul;
 1496                                 for (i = 0; i < nul; i++)
 1497                                         *cp++ = '\0';
 1498                         }
 1499                         break;
 1500                 }
 1501                 count -= m->m_len;
 1502         }
 1503         for (m = m->m_next;m;m = m->m_next)
 1504                 m->m_len = 0;
 1505 }
 1506 
 1507 /*
 1508  * Make these functions instead of macros, so that the kernel text size
 1509  * doesn't get too big...
 1510  */
 1511 void
 1512 nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
 1513         struct nfsrv_descript *nfsd;
 1514         int before_ret;
 1515         struct vattr *before_vap;
 1516         int after_ret;
 1517         struct vattr *after_vap;
 1518         struct mbuf **mbp;
 1519         char **bposp;
 1520 {
 1521         struct mbuf *mb = *mbp, *mb2;
 1522         char *bpos = *bposp;
 1523         u_int32_t *tl;
 1524 
 1525         if (before_ret) {
 1526                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
 1527                 *tl = nfs_false;
 1528         } else {
 1529                 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 1530                 *tl++ = nfs_true;
 1531                 txdr_hyper(before_vap->va_size, tl);
 1532                 tl += 2;
 1533                 txdr_nfsv3time(&(before_vap->va_mtime), tl);
 1534                 tl += 2;
 1535                 txdr_nfsv3time(&(before_vap->va_ctime), tl);
 1536         }
 1537         *bposp = bpos;
 1538         *mbp = mb;
 1539         nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
 1540 }
 1541 
 1542 void
 1543 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
 1544         struct nfsrv_descript *nfsd;
 1545         int after_ret;
 1546         struct vattr *after_vap;
 1547         struct mbuf **mbp;
 1548         char **bposp;
 1549 {
 1550         struct mbuf *mb = *mbp, *mb2;
 1551         char *bpos = *bposp;
 1552         u_int32_t *tl;
 1553         struct nfs_fattr *fp;
 1554 
 1555         if (after_ret) {
 1556                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
 1557                 *tl = nfs_false;
 1558         } else {
 1559                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
 1560                 *tl++ = nfs_true;
 1561                 fp = (struct nfs_fattr *)tl;
 1562                 nfsm_srvfattr(nfsd, after_vap, fp);
 1563         }
 1564         *mbp = mb;
 1565         *bposp = bpos;
 1566 }
 1567 
 1568 void
 1569 nfsm_srvfattr(nfsd, vap, fp)
 1570         struct nfsrv_descript *nfsd;
 1571         struct vattr *vap;
 1572         struct nfs_fattr *fp;
 1573 {
 1574 
 1575         fp->fa_nlink = txdr_unsigned(vap->va_nlink);
 1576         fp->fa_uid = txdr_unsigned(vap->va_uid);
 1577         fp->fa_gid = txdr_unsigned(vap->va_gid);
 1578         if (nfsd->nd_flag & ND_NFSV3) {
 1579                 fp->fa_type = vtonfsv3_type(vap->va_type);
 1580                 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
 1581                 txdr_hyper(vap->va_size, &fp->fa3_size);
 1582                 txdr_hyper(vap->va_bytes, &fp->fa3_used);
 1583                 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
 1584                 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
 1585                 fp->fa3_fsid.nfsuquad[0] = 0;
 1586                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
 1587                 fp->fa3_fileid.nfsuquad[0] = 0;
 1588                 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
 1589                 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
 1590                 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
 1591                 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
 1592         } else {
 1593                 fp->fa_type = vtonfsv2_type(vap->va_type);
 1594                 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
 1595                 fp->fa2_size = txdr_unsigned(vap->va_size);
 1596                 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
 1597                 if (vap->va_type == VFIFO)
 1598                         fp->fa2_rdev = 0xffffffff;
 1599                 else
 1600                         fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
 1601                 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
 1602                 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
 1603                 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
 1604                 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
 1605                 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
 1606                 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
 1607         }
 1608 }
 1609 
 1610 /*
 1611  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
 1612  *      - look up fsid in mount list (if not found ret error)
 1613  *      - get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP()
 1614  *      - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
 1615  *      - if not lockflag unlock it with VOP_UNLOCK()
 1616  */
 1617 int
 1618 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
 1619         fhandle_t *fhp;
 1620         int lockflag;
 1621         struct vnode **vpp;
 1622         struct ucred *cred;
 1623         struct nfssvc_sock *slp;
 1624         struct mbuf *nam;
 1625         int *rdonlyp;
 1626         int kerbflag;
 1627 {
 1628         struct proc *p = curproc;       /* XXX */
 1629         struct mount *mp;
 1630         int i;
 1631         struct ucred *credanon;
 1632         int error, exflags;
 1633         struct sockaddr_in *saddr;
 1634 
 1635         *vpp = (struct vnode *)0;
 1636         mp = vfs_getvfs(&fhp->fh_fsid);
 1637 
 1638         if (!mp)
 1639                 return (ESTALE);
 1640         error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
 1641         if (error)
 1642                 return (error);
 1643         error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
 1644         if (error)
 1645                 return (error);
 1646 
 1647         saddr = mtod(nam, struct sockaddr_in *);
 1648         if (saddr->sin_family == AF_INET &&
 1649             (ntohs(saddr->sin_port) >= IPPORT_RESERVED ||
 1650             (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) {
 1651                 vput(*vpp);
 1652                 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
 1653         }
 1654 
 1655         /*
 1656          * Check/setup credentials.
 1657          */
 1658         if (exflags & MNT_EXKERB) {
 1659                 if (!kerbflag) {
 1660                         vput(*vpp);
 1661                         return (NFSERR_AUTHERR | AUTH_TOOWEAK);
 1662                 }
 1663         } else if (kerbflag) {
 1664                 vput(*vpp);
 1665                 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
 1666         } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
 1667                 cred->cr_uid = credanon->cr_uid;
 1668                 cred->cr_gid = credanon->cr_gid;
 1669                 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
 1670                         cred->cr_groups[i] = credanon->cr_groups[i];
 1671                 cred->cr_ngroups = i;
 1672         }
 1673         if (exflags & MNT_EXRDONLY)
 1674                 *rdonlyp = 1;
 1675         else
 1676                 *rdonlyp = 0;
 1677         if (!lockflag)
 1678                 VOP_UNLOCK(*vpp, 0, p);
 1679 
 1680         return (0);
 1681 }
 1682 
 1683 /*
 1684  * This function compares two net addresses by family and returns TRUE
 1685  * if they are the same host.
 1686  * If there is any doubt, return FALSE.
 1687  * The AF_INET family is handled as a special case so that address mbufs
 1688  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
 1689  */
 1690 int
 1691 netaddr_match(family, haddr, nam)
 1692         int family;
 1693         union nethostaddr *haddr;
 1694         struct mbuf *nam;
 1695 {
 1696         struct sockaddr_in *inetaddr;
 1697 
 1698         switch (family) {
 1699         case AF_INET:
 1700                 inetaddr = mtod(nam, struct sockaddr_in *);
 1701                 if (inetaddr->sin_family == AF_INET &&
 1702                     inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
 1703                         return (1);
 1704                 break;
 1705         default:
 1706                 break;
 1707         };
 1708         return (0);
 1709 }
 1710 
 1711 /*
 1712  * The write verifier has changed (probably due to a server reboot), so all
 1713  * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
 1714  * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
 1715  * flag. Once done the new write verifier can be set for the mount point.
 1716  */
 1717 void
 1718 nfs_clearcommit(mp)
 1719         struct mount *mp;
 1720 {
 1721         struct vnode *vp, *nvp;
 1722         struct buf *bp, *nbp;
 1723         int s;
 1724 
 1725         s = splbio();
 1726 loop:
 1727         for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) {
 1728                 if (vp->v_mount != mp)  /* Paranoia */
 1729                         goto loop;
 1730                 nvp = LIST_NEXT(vp, v_mntvnodes);
 1731                 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp != NULL; bp = nbp) {
 1732                         nbp = LIST_NEXT(bp, b_vnbufs);
 1733                         if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
 1734                                 == (B_DELWRI | B_NEEDCOMMIT))
 1735                                 bp->b_flags &= ~B_NEEDCOMMIT;
 1736                 }
 1737         }
 1738         splx(s);
 1739 }
 1740 
 1741 void
 1742 nfs_merge_commit_ranges(vp)
 1743         struct vnode *vp;
 1744 {
 1745         struct nfsnode *np = VTONFS(vp);
 1746 
 1747         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
 1748                 np->n_pushedlo = np->n_pushlo;
 1749                 np->n_pushedhi = np->n_pushhi;
 1750                 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
 1751         } else {
 1752                 if (np->n_pushlo < np->n_pushedlo)
 1753                         np->n_pushedlo = np->n_pushlo;
 1754                 if (np->n_pushhi > np->n_pushedhi)
 1755                         np->n_pushedhi = np->n_pushhi;
 1756         }
 1757 
 1758         np->n_pushlo = np->n_pushhi = 0;
 1759         np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
 1760 }
 1761 
 1762 int
 1763 nfs_in_committed_range(vp, bp)
 1764         struct vnode *vp;
 1765         struct buf *bp;
 1766 {
 1767         struct nfsnode *np = VTONFS(vp);
 1768         off_t lo, hi;
 1769 
 1770         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
 1771                 return 0;
 1772         lo = (off_t)bp->b_blkno * DEV_BSIZE;
 1773         hi = lo + bp->b_dirtyend;
 1774 
 1775         return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
 1776 }
 1777 
 1778 int
 1779 nfs_in_tobecommitted_range(vp, bp)
 1780         struct vnode *vp;
 1781         struct buf *bp;
 1782 {
 1783         struct nfsnode *np = VTONFS(vp);
 1784         off_t lo, hi;
 1785 
 1786         if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
 1787                 return 0;
 1788         lo = (off_t)bp->b_blkno * DEV_BSIZE;
 1789         hi = lo + bp->b_dirtyend;
 1790 
 1791         return (lo >= np->n_pushlo && hi <= np->n_pushhi);
 1792 }
 1793 
 1794 void
 1795 nfs_add_committed_range(vp, bp)
 1796         struct vnode *vp;
 1797         struct buf *bp;
 1798 {
 1799         struct nfsnode *np = VTONFS(vp);
 1800         off_t lo, hi;
 1801 
 1802         lo = (off_t)bp->b_blkno * DEV_BSIZE;
 1803         hi = lo + bp->b_dirtyend;
 1804 
 1805         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
 1806                 np->n_pushedlo = lo;
 1807                 np->n_pushedhi = hi;
 1808                 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
 1809         } else {
 1810                 if (hi > np->n_pushedhi)
 1811                         np->n_pushedhi = hi;
 1812                 if (lo < np->n_pushedlo)
 1813                         np->n_pushedlo = lo;
 1814         }
 1815 }
 1816 
 1817 void
 1818 nfs_del_committed_range(vp, bp)
 1819         struct vnode *vp;
 1820         struct buf *bp;
 1821 {
 1822         struct nfsnode *np = VTONFS(vp);
 1823         off_t lo, hi;
 1824 
 1825         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
 1826                 return;
 1827 
 1828         lo = (off_t)bp->b_blkno * DEV_BSIZE;
 1829         hi = lo + bp->b_dirtyend;
 1830 
 1831         if (lo > np->n_pushedhi || hi < np->n_pushedlo)
 1832                 return;
 1833         if (lo <= np->n_pushedlo)
 1834                 np->n_pushedlo = hi;
 1835         else if (hi >= np->n_pushedhi)
 1836                 np->n_pushedhi = lo;
 1837         else {
 1838                 /*
 1839                  * XXX There's only one range. If the deleted range
 1840                  * is in the middle, pick the largest of the
 1841                  * contiguous ranges that it leaves.
 1842                  */
 1843                 if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
 1844                         np->n_pushedhi = lo;
 1845                 else
 1846                         np->n_pushedlo = hi;
 1847         }
 1848 }
 1849 
 1850 void
 1851 nfs_add_tobecommitted_range(vp, bp)
 1852         struct vnode *vp;
 1853         struct buf *bp;
 1854 {
 1855         struct nfsnode *np = VTONFS(vp);
 1856         off_t lo, hi;
 1857 
 1858         lo = (off_t)bp->b_blkno * DEV_BSIZE;
 1859         hi = lo + bp->b_dirtyend;
 1860 
 1861         if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
 1862                 np->n_pushlo = lo;
 1863                 np->n_pushhi = hi;
 1864                 np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
 1865         } else {
 1866                 if (lo < np->n_pushlo)
 1867                         np->n_pushlo = lo;
 1868                 if (hi > np->n_pushhi)
 1869                         np->n_pushhi = hi;
 1870         }
 1871 }
 1872 
 1873 void
 1874 nfs_del_tobecommitted_range(vp, bp)
 1875         struct vnode *vp;
 1876         struct buf *bp;
 1877 {
 1878         struct nfsnode *np = VTONFS(vp);
 1879         off_t lo, hi;
 1880 
 1881         if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
 1882                 return;
 1883 
 1884         lo = (off_t)bp->b_blkno * DEV_BSIZE;
 1885         hi = lo + bp->b_dirtyend;
 1886 
 1887         if (lo > np->n_pushhi || hi < np->n_pushlo)
 1888                 return;
 1889 
 1890         if (lo <= np->n_pushlo)
 1891                 np->n_pushlo = hi;
 1892         else if (hi >= np->n_pushhi)
 1893                 np->n_pushhi = lo;
 1894         else {
 1895                 /*
 1896                  * XXX There's only one range. If the deleted range
 1897                  * is in the middle, pick the largest of the
 1898                  * contiguous ranges that it leaves.
 1899                  */
 1900                 if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
 1901                         np->n_pushhi = lo;
 1902                 else
 1903                         np->n_pushlo = hi;
 1904         }
 1905 }
 1906 
 1907 /*
 1908  * Map errnos to NFS error numbers. For Version 3 also filter out error
 1909  * numbers not specified for the associated procedure.
 1910  */
 1911 int
 1912 nfsrv_errmap(nd, err)
 1913         struct nfsrv_descript *nd;
 1914         int err;
 1915 {
 1916         short *defaulterrp, *errp;
 1917 
 1918         if (nd->nd_flag & ND_NFSV3) {
 1919             if (nd->nd_procnum <= NFSPROC_COMMIT) {
 1920                 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
 1921                 while (*++errp) {
 1922                         if (*errp == err)
 1923                                 return (err);
 1924                         else if (*errp > err)
 1925                                 break;
 1926                 }
 1927                 return ((int)*defaulterrp);
 1928             } else
 1929                 return (err & 0xffff);
 1930         }
 1931         if (err <= ELAST)
 1932                 return ((int)nfsrv_v2errmap[err - 1]);
 1933         return (NFSERR_IO);
 1934 }
 1935 
 1936 /*
 1937  * Sort the group list in increasing numerical order.
 1938  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
 1939  *  that used to be here.)
 1940  */
 1941 void
 1942 nfsrvw_sort(list, num)
 1943         gid_t *list;
 1944         int num;
 1945 {
 1946         int i, j;
 1947         gid_t v;
 1948 
 1949         /* Insertion sort. */
 1950         for (i = 1; i < num; i++) {
 1951                 v = list[i];
 1952                 /* find correct slot for value v, moving others up */
 1953                 for (j = i; --j >= 0 && v < list[j];)
 1954                         list[j + 1] = list[j];
 1955                 list[j + 1] = v;
 1956         }
 1957 }
 1958 
 1959 /*
 1960  * copy credentials making sure that the result can be compared with bcmp().
 1961  */
 1962 void
 1963 nfsrv_setcred(incred, outcred)
 1964         struct ucred *incred, *outcred;
 1965 {
 1966         int i;
 1967 
 1968         bzero((caddr_t)outcred, sizeof (struct ucred));
 1969         outcred->cr_ref = 1;
 1970         outcred->cr_uid = incred->cr_uid;
 1971         outcred->cr_gid = incred->cr_gid;
 1972         outcred->cr_ngroups = incred->cr_ngroups;
 1973         for (i = 0; i < incred->cr_ngroups; i++)
 1974                 outcred->cr_groups[i] = incred->cr_groups[i];
 1975         nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
 1976 }

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