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


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

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

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

    1 /*
    2  * Copyright (c) 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * Rick Macklem at The University of Guelph.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by the University of
   19  *      California, Berkeley and its contributors.
   20  * 4. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  *
   36  *      @(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
   37  * $FreeBSD$
   38  */
   39 
   40 /*
   41  * These functions support the macros and help fiddle mbuf chains for
   42  * the nfs op functions. They do things like create the rpc header and
   43  * copy data between mbuf chains and uio lists.
   44  */
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/kernel.h>
   48 #include <sys/buf.h>
   49 #include <sys/proc.h>
   50 #include <sys/mount.h>
   51 #include <sys/vnode.h>
   52 #include <sys/namei.h>
   53 #include <sys/mbuf.h>
   54 #include <sys/socket.h>
   55 #include <sys/stat.h>
   56 #include <sys/malloc.h>
   57 #include <sys/sysent.h>
   58 #include <sys/syscall.h>
   59 #include <sys/conf.h>
   60 
   61 #include <vm/vm.h>
   62 #include <vm/vm_object.h>
   63 #include <vm/vm_extern.h>
   64 #include <vm/vm_zone.h>
   65 
   66 #include <nfs/rpcv2.h>
   67 #include <nfs/nfsproto.h>
   68 #include <nfs/nfs.h>
   69 #include <nfs/nfsnode.h>
   70 #include <nfs/xdr_subs.h>
   71 #include <nfs/nfsm_subs.h>
   72 #include <nfs/nfsmount.h>
   73 #include <nfs/nqnfs.h>
   74 #include <nfs/nfsrtt.h>
   75 
   76 #include <netinet/in.h>
   77 
   78 /*
   79  * Data items converted to xdr at startup, since they are constant
   80  * This is kinda hokey, but may save a little time doing byte swaps
   81  */
   82 u_int32_t nfs_xdrneg1;
   83 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
   84         rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
   85         rpc_auth_kerb;
   86 u_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false;
   87 
   88 /* And other global data */
   89 static u_int32_t nfs_xid = 0;
   90 static enum vtype nv2tov_type[8]= {
   91         VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON,  VNON 
   92 };
   93 enum vtype nv3tov_type[8]= {
   94         VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
   95 };
   96 
   97 int nfs_ticks;
   98 int nfs_pbuf_freecnt = -1;      /* start out unlimited */
   99 
  100 struct nfs_reqq nfs_reqq;
  101 struct nfssvc_sockhead nfssvc_sockhead;
  102 int nfssvc_sockhead_flag;
  103 struct nfsd_head nfsd_head;
  104 int nfsd_head_flag;
  105 struct nfs_bufq nfs_bufq;
  106 struct nqtimerhead nqtimerhead;
  107 struct nqfhhashhead *nqfhhashtbl;
  108 u_long nqfhhash;
  109 
  110 static void (*nfs_prev_lease_updatetime) __P((int));
  111 static int nfs_prev_nfssvc_sy_narg;
  112 static sy_call_t *nfs_prev_nfssvc_sy_call;
  113 
  114 #ifndef NFS_NOSERVER
  115 
  116 static vop_t *nfs_prev_vop_lease_check;
  117 
  118 /*
  119  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
  120  */
  121 int nfsv3_procid[NFS_NPROCS] = {
  122         NFSPROC_NULL,
  123         NFSPROC_GETATTR,
  124         NFSPROC_SETATTR,
  125         NFSPROC_NOOP,
  126         NFSPROC_LOOKUP,
  127         NFSPROC_READLINK,
  128         NFSPROC_READ,
  129         NFSPROC_NOOP,
  130         NFSPROC_WRITE,
  131         NFSPROC_CREATE,
  132         NFSPROC_REMOVE,
  133         NFSPROC_RENAME,
  134         NFSPROC_LINK,
  135         NFSPROC_SYMLINK,
  136         NFSPROC_MKDIR,
  137         NFSPROC_RMDIR,
  138         NFSPROC_READDIR,
  139         NFSPROC_FSSTAT,
  140         NFSPROC_NOOP,
  141         NFSPROC_NOOP,
  142         NFSPROC_NOOP,
  143         NFSPROC_NOOP,
  144         NFSPROC_NOOP,
  145         NFSPROC_NOOP,
  146         NFSPROC_NOOP,
  147         NFSPROC_NOOP
  148 };
  149 
  150 #endif /* NFS_NOSERVER */
  151 /*
  152  * and the reverse mapping from generic to Version 2 procedure numbers
  153  */
  154 int nfsv2_procid[NFS_NPROCS] = {
  155         NFSV2PROC_NULL,
  156         NFSV2PROC_GETATTR,
  157         NFSV2PROC_SETATTR,
  158         NFSV2PROC_LOOKUP,
  159         NFSV2PROC_NOOP,
  160         NFSV2PROC_READLINK,
  161         NFSV2PROC_READ,
  162         NFSV2PROC_WRITE,
  163         NFSV2PROC_CREATE,
  164         NFSV2PROC_MKDIR,
  165         NFSV2PROC_SYMLINK,
  166         NFSV2PROC_CREATE,
  167         NFSV2PROC_REMOVE,
  168         NFSV2PROC_RMDIR,
  169         NFSV2PROC_RENAME,
  170         NFSV2PROC_LINK,
  171         NFSV2PROC_READDIR,
  172         NFSV2PROC_NOOP,
  173         NFSV2PROC_STATFS,
  174         NFSV2PROC_NOOP,
  175         NFSV2PROC_NOOP,
  176         NFSV2PROC_NOOP,
  177         NFSV2PROC_NOOP,
  178         NFSV2PROC_NOOP,
  179         NFSV2PROC_NOOP,
  180         NFSV2PROC_NOOP,
  181 };
  182 
  183 #ifndef NFS_NOSERVER
  184 /*
  185  * Maps errno values to nfs error numbers.
  186  * Use NFSERR_IO as the catch all for ones not specifically defined in
  187  * RFC 1094.
  188  */
  189 static u_char nfsrv_v2errmap[ELAST] = {
  190   NFSERR_PERM,  NFSERR_NOENT,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  191   NFSERR_NXIO,  NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  192   NFSERR_IO,    NFSERR_IO,      NFSERR_ACCES,   NFSERR_IO,      NFSERR_IO,
  193   NFSERR_IO,    NFSERR_EXIST,   NFSERR_IO,      NFSERR_NODEV,   NFSERR_NOTDIR,
  194   NFSERR_ISDIR, NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  195   NFSERR_IO,    NFSERR_FBIG,    NFSERR_NOSPC,   NFSERR_IO,      NFSERR_ROFS,
  196   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  197   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  198   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  199   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  200   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  201   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  202   NFSERR_IO,    NFSERR_IO,      NFSERR_NAMETOL, NFSERR_IO,      NFSERR_IO,
  203   NFSERR_NOTEMPTY, NFSERR_IO,   NFSERR_IO,      NFSERR_DQUOT,   NFSERR_STALE,
  204   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  205   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  206   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  207   NFSERR_IO,    NFSERR_IO /* << Last is 87 */
  208 };
  209 
  210 /*
  211  * Maps errno values to nfs error numbers.
  212  * Although it is not obvious whether or not NFS clients really care if
  213  * a returned error value is in the specified list for the procedure, the
  214  * safest thing to do is filter them appropriately. For Version 2, the
  215  * X/Open XNFS document is the only specification that defines error values
  216  * for each RPC (The RFC simply lists all possible error values for all RPCs),
  217  * so I have decided to not do this for Version 2.
  218  * The first entry is the default error return and the rest are the valid
  219  * errors for that RPC in increasing numeric order.
  220  */
  221 static short nfsv3err_null[] = {
  222         0,
  223         0,
  224 };
  225 
  226 static short nfsv3err_getattr[] = {
  227         NFSERR_IO,
  228         NFSERR_IO,
  229         NFSERR_STALE,
  230         NFSERR_BADHANDLE,
  231         NFSERR_SERVERFAULT,
  232         0,
  233 };
  234 
  235 static short nfsv3err_setattr[] = {
  236         NFSERR_IO,
  237         NFSERR_PERM,
  238         NFSERR_IO,
  239         NFSERR_ACCES,
  240         NFSERR_INVAL,
  241         NFSERR_NOSPC,
  242         NFSERR_ROFS,
  243         NFSERR_DQUOT,
  244         NFSERR_STALE,
  245         NFSERR_BADHANDLE,
  246         NFSERR_NOT_SYNC,
  247         NFSERR_SERVERFAULT,
  248         0,
  249 };
  250 
  251 static short nfsv3err_lookup[] = {
  252         NFSERR_IO,
  253         NFSERR_NOENT,
  254         NFSERR_IO,
  255         NFSERR_ACCES,
  256         NFSERR_NOTDIR,
  257         NFSERR_NAMETOL,
  258         NFSERR_STALE,
  259         NFSERR_BADHANDLE,
  260         NFSERR_SERVERFAULT,
  261         0,
  262 };
  263 
  264 static short nfsv3err_access[] = {
  265         NFSERR_IO,
  266         NFSERR_IO,
  267         NFSERR_STALE,
  268         NFSERR_BADHANDLE,
  269         NFSERR_SERVERFAULT,
  270         0,
  271 };
  272 
  273 static short nfsv3err_readlink[] = {
  274         NFSERR_IO,
  275         NFSERR_IO,
  276         NFSERR_ACCES,
  277         NFSERR_INVAL,
  278         NFSERR_STALE,
  279         NFSERR_BADHANDLE,
  280         NFSERR_NOTSUPP,
  281         NFSERR_SERVERFAULT,
  282         0,
  283 };
  284 
  285 static short nfsv3err_read[] = {
  286         NFSERR_IO,
  287         NFSERR_IO,
  288         NFSERR_NXIO,
  289         NFSERR_ACCES,
  290         NFSERR_INVAL,
  291         NFSERR_STALE,
  292         NFSERR_BADHANDLE,
  293         NFSERR_SERVERFAULT,
  294         0,
  295 };
  296 
  297 static short nfsv3err_write[] = {
  298         NFSERR_IO,
  299         NFSERR_IO,
  300         NFSERR_ACCES,
  301         NFSERR_INVAL,
  302         NFSERR_FBIG,
  303         NFSERR_NOSPC,
  304         NFSERR_ROFS,
  305         NFSERR_DQUOT,
  306         NFSERR_STALE,
  307         NFSERR_BADHANDLE,
  308         NFSERR_SERVERFAULT,
  309         0,
  310 };
  311 
  312 static short nfsv3err_create[] = {
  313         NFSERR_IO,
  314         NFSERR_IO,
  315         NFSERR_ACCES,
  316         NFSERR_EXIST,
  317         NFSERR_NOTDIR,
  318         NFSERR_NOSPC,
  319         NFSERR_ROFS,
  320         NFSERR_NAMETOL,
  321         NFSERR_DQUOT,
  322         NFSERR_STALE,
  323         NFSERR_BADHANDLE,
  324         NFSERR_NOTSUPP,
  325         NFSERR_SERVERFAULT,
  326         0,
  327 };
  328 
  329 static short nfsv3err_mkdir[] = {
  330         NFSERR_IO,
  331         NFSERR_IO,
  332         NFSERR_ACCES,
  333         NFSERR_EXIST,
  334         NFSERR_NOTDIR,
  335         NFSERR_NOSPC,
  336         NFSERR_ROFS,
  337         NFSERR_NAMETOL,
  338         NFSERR_DQUOT,
  339         NFSERR_STALE,
  340         NFSERR_BADHANDLE,
  341         NFSERR_NOTSUPP,
  342         NFSERR_SERVERFAULT,
  343         0,
  344 };
  345 
  346 static short nfsv3err_symlink[] = {
  347         NFSERR_IO,
  348         NFSERR_IO,
  349         NFSERR_ACCES,
  350         NFSERR_EXIST,
  351         NFSERR_NOTDIR,
  352         NFSERR_NOSPC,
  353         NFSERR_ROFS,
  354         NFSERR_NAMETOL,
  355         NFSERR_DQUOT,
  356         NFSERR_STALE,
  357         NFSERR_BADHANDLE,
  358         NFSERR_NOTSUPP,
  359         NFSERR_SERVERFAULT,
  360         0,
  361 };
  362 
  363 static short nfsv3err_mknod[] = {
  364         NFSERR_IO,
  365         NFSERR_IO,
  366         NFSERR_ACCES,
  367         NFSERR_EXIST,
  368         NFSERR_NOTDIR,
  369         NFSERR_NOSPC,
  370         NFSERR_ROFS,
  371         NFSERR_NAMETOL,
  372         NFSERR_DQUOT,
  373         NFSERR_STALE,
  374         NFSERR_BADHANDLE,
  375         NFSERR_NOTSUPP,
  376         NFSERR_SERVERFAULT,
  377         NFSERR_BADTYPE,
  378         0,
  379 };
  380 
  381 static short nfsv3err_remove[] = {
  382         NFSERR_IO,
  383         NFSERR_NOENT,
  384         NFSERR_IO,
  385         NFSERR_ACCES,
  386         NFSERR_NOTDIR,
  387         NFSERR_ROFS,
  388         NFSERR_NAMETOL,
  389         NFSERR_STALE,
  390         NFSERR_BADHANDLE,
  391         NFSERR_SERVERFAULT,
  392         0,
  393 };
  394 
  395 static short nfsv3err_rmdir[] = {
  396         NFSERR_IO,
  397         NFSERR_NOENT,
  398         NFSERR_IO,
  399         NFSERR_ACCES,
  400         NFSERR_EXIST,
  401         NFSERR_NOTDIR,
  402         NFSERR_INVAL,
  403         NFSERR_ROFS,
  404         NFSERR_NAMETOL,
  405         NFSERR_NOTEMPTY,
  406         NFSERR_STALE,
  407         NFSERR_BADHANDLE,
  408         NFSERR_NOTSUPP,
  409         NFSERR_SERVERFAULT,
  410         0,
  411 };
  412 
  413 static short nfsv3err_rename[] = {
  414         NFSERR_IO,
  415         NFSERR_NOENT,
  416         NFSERR_IO,
  417         NFSERR_ACCES,
  418         NFSERR_EXIST,
  419         NFSERR_XDEV,
  420         NFSERR_NOTDIR,
  421         NFSERR_ISDIR,
  422         NFSERR_INVAL,
  423         NFSERR_NOSPC,
  424         NFSERR_ROFS,
  425         NFSERR_MLINK,
  426         NFSERR_NAMETOL,
  427         NFSERR_NOTEMPTY,
  428         NFSERR_DQUOT,
  429         NFSERR_STALE,
  430         NFSERR_BADHANDLE,
  431         NFSERR_NOTSUPP,
  432         NFSERR_SERVERFAULT,
  433         0,
  434 };
  435 
  436 static short nfsv3err_link[] = {
  437         NFSERR_IO,
  438         NFSERR_IO,
  439         NFSERR_ACCES,
  440         NFSERR_EXIST,
  441         NFSERR_XDEV,
  442         NFSERR_NOTDIR,
  443         NFSERR_INVAL,
  444         NFSERR_NOSPC,
  445         NFSERR_ROFS,
  446         NFSERR_MLINK,
  447         NFSERR_NAMETOL,
  448         NFSERR_DQUOT,
  449         NFSERR_STALE,
  450         NFSERR_BADHANDLE,
  451         NFSERR_NOTSUPP,
  452         NFSERR_SERVERFAULT,
  453         0,
  454 };
  455 
  456 static short nfsv3err_readdir[] = {
  457         NFSERR_IO,
  458         NFSERR_IO,
  459         NFSERR_ACCES,
  460         NFSERR_NOTDIR,
  461         NFSERR_STALE,
  462         NFSERR_BADHANDLE,
  463         NFSERR_BAD_COOKIE,
  464         NFSERR_TOOSMALL,
  465         NFSERR_SERVERFAULT,
  466         0,
  467 };
  468 
  469 static short nfsv3err_readdirplus[] = {
  470         NFSERR_IO,
  471         NFSERR_IO,
  472         NFSERR_ACCES,
  473         NFSERR_NOTDIR,
  474         NFSERR_STALE,
  475         NFSERR_BADHANDLE,
  476         NFSERR_BAD_COOKIE,
  477         NFSERR_NOTSUPP,
  478         NFSERR_TOOSMALL,
  479         NFSERR_SERVERFAULT,
  480         0,
  481 };
  482 
  483 static short nfsv3err_fsstat[] = {
  484         NFSERR_IO,
  485         NFSERR_IO,
  486         NFSERR_STALE,
  487         NFSERR_BADHANDLE,
  488         NFSERR_SERVERFAULT,
  489         0,
  490 };
  491 
  492 static short nfsv3err_fsinfo[] = {
  493         NFSERR_STALE,
  494         NFSERR_STALE,
  495         NFSERR_BADHANDLE,
  496         NFSERR_SERVERFAULT,
  497         0,
  498 };
  499 
  500 static short nfsv3err_pathconf[] = {
  501         NFSERR_STALE,
  502         NFSERR_STALE,
  503         NFSERR_BADHANDLE,
  504         NFSERR_SERVERFAULT,
  505         0,
  506 };
  507 
  508 static short nfsv3err_commit[] = {
  509         NFSERR_IO,
  510         NFSERR_IO,
  511         NFSERR_STALE,
  512         NFSERR_BADHANDLE,
  513         NFSERR_SERVERFAULT,
  514         0,
  515 };
  516 
  517 static short *nfsrv_v3errmap[] = {
  518         nfsv3err_null,
  519         nfsv3err_getattr,
  520         nfsv3err_setattr,
  521         nfsv3err_lookup,
  522         nfsv3err_access,
  523         nfsv3err_readlink,
  524         nfsv3err_read,
  525         nfsv3err_write,
  526         nfsv3err_create,
  527         nfsv3err_mkdir,
  528         nfsv3err_symlink,
  529         nfsv3err_mknod,
  530         nfsv3err_remove,
  531         nfsv3err_rmdir,
  532         nfsv3err_rename,
  533         nfsv3err_link,
  534         nfsv3err_readdir,
  535         nfsv3err_readdirplus,
  536         nfsv3err_fsstat,
  537         nfsv3err_fsinfo,
  538         nfsv3err_pathconf,
  539         nfsv3err_commit,
  540 };
  541 
  542 #endif /* NFS_NOSERVER */
  543 
  544 extern struct nfsrtt nfsrtt;
  545 extern time_t nqnfsstarttime;
  546 extern int nqsrv_clockskew;
  547 extern int nqsrv_writeslack;
  548 extern int nqsrv_maxlease;
  549 extern struct nfsstats nfsstats;
  550 extern int nqnfs_piggy[NFS_NPROCS];
  551 extern nfstype nfsv2_type[9];
  552 extern nfstype nfsv3_type[9];
  553 extern struct nfsnodehashhead *nfsnodehashtbl;
  554 extern u_long nfsnodehash;
  555 
  556 struct nfssvc_args;
  557 extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
  558 
  559 LIST_HEAD(nfsnodehashhead, nfsnode);
  560 
  561 u_int32_t
  562 nfs_xid_gen(void)
  563 {
  564         /* Get a pretty random xid to start with */
  565         if (!nfs_xid)
  566                 nfs_xid = random();
  567         /*
  568          * Skip zero xid if it should ever happen.
  569          */
  570         if (++nfs_xid == 0)
  571                 nfs_xid++;
  572         return nfs_xid;
  573 }
  574 
  575 int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
  576 
  577 u_quad_t
  578 nfs_curusec() 
  579 {
  580         struct timeval tv;
  581         
  582         getmicrotime(&tv);
  583         return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec);
  584 }
  585 
  586 /*
  587  * Create the header for an rpc request packet
  588  * The hsiz is the size of the rest of the nfs request header.
  589  * (just used to decide if a cluster is a good idea)
  590  */
  591 struct mbuf *
  592 nfsm_reqh(vp, procid, hsiz, bposp)
  593         struct vnode *vp;
  594         u_long procid;
  595         int hsiz;
  596         caddr_t *bposp;
  597 {
  598         register struct mbuf *mb;
  599         register u_int32_t *tl;
  600         register caddr_t bpos;
  601         struct mbuf *mb2;
  602         struct nfsmount *nmp;
  603         int nqflag;
  604 
  605         MGET(mb, M_WAIT, MT_DATA);
  606         if (hsiz >= MINCLSIZE)
  607                 MCLGET(mb, M_WAIT);
  608         mb->m_len = 0;
  609         bpos = mtod(mb, caddr_t);
  610 
  611         /*
  612          * For NQNFS, add lease request.
  613          */
  614         if (vp) {
  615                 nmp = VFSTONFS(vp->v_mount);
  616                 if (nmp->nm_flag & NFSMNT_NQNFS) {
  617                         nqflag = NQNFS_NEEDLEASE(vp, procid);
  618                         if (nqflag) {
  619                                 nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED);
  620                                 *tl++ = txdr_unsigned(nqflag);
  621                                 *tl = txdr_unsigned(nmp->nm_leaseterm);
  622                         } else {
  623                                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
  624                                 *tl = 0;
  625                         }
  626                 }
  627         }
  628         /* Finally, return values */
  629         *bposp = bpos;
  630         return (mb);
  631 }
  632 
  633 /*
  634  * Build the RPC header and fill in the authorization info.
  635  * The authorization string argument is only used when the credentials
  636  * come from outside of the kernel.
  637  * Returns the head of the mbuf list.
  638  */
  639 struct mbuf *
  640 nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
  641         verf_str, mrest, mrest_len, mbp, xidpp)
  642         register struct ucred *cr;
  643         int nmflag;
  644         int procid;
  645         int auth_type;
  646         int auth_len;
  647         char *auth_str;
  648         int verf_len;
  649         char *verf_str;
  650         struct mbuf *mrest;
  651         int mrest_len;
  652         struct mbuf **mbp;
  653         u_int32_t **xidpp;
  654 {
  655         register struct mbuf *mb;
  656         register u_int32_t *tl;
  657         register caddr_t bpos;
  658         register int i;
  659         struct mbuf *mreq, *mb2;
  660         int siz, grpsiz, authsiz;
  661 
  662         authsiz = nfsm_rndup(auth_len);
  663         MGETHDR(mb, M_WAIT, MT_DATA);
  664         if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
  665                 MCLGET(mb, M_WAIT);
  666         } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
  667                 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
  668         } else {
  669                 MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
  670         }
  671         mb->m_len = 0;
  672         mreq = mb;
  673         bpos = mtod(mb, caddr_t);
  674 
  675         /*
  676          * First the RPC header.
  677          */
  678         nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
  679 
  680         *xidpp = tl;
  681         *tl++ = txdr_unsigned(nfs_xid_gen());
  682         *tl++ = rpc_call;
  683         *tl++ = rpc_vers;
  684         if (nmflag & NFSMNT_NQNFS) {
  685                 *tl++ = txdr_unsigned(NQNFS_PROG);
  686                 *tl++ = txdr_unsigned(NQNFS_VER3);
  687         } else {
  688                 *tl++ = txdr_unsigned(NFS_PROG);
  689                 if (nmflag & NFSMNT_NFSV3)
  690                         *tl++ = txdr_unsigned(NFS_VER3);
  691                 else
  692                         *tl++ = txdr_unsigned(NFS_VER2);
  693         }
  694         if (nmflag & NFSMNT_NFSV3)
  695                 *tl++ = txdr_unsigned(procid);
  696         else
  697                 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
  698 
  699         /*
  700          * And then the authorization cred.
  701          */
  702         *tl++ = txdr_unsigned(auth_type);
  703         *tl = txdr_unsigned(authsiz);
  704         switch (auth_type) {
  705         case RPCAUTH_UNIX:
  706                 nfsm_build(tl, u_int32_t *, auth_len);
  707                 *tl++ = 0;              /* stamp ?? */
  708                 *tl++ = 0;              /* NULL hostname */
  709                 *tl++ = txdr_unsigned(cr->cr_uid);
  710                 *tl++ = txdr_unsigned(cr->cr_groups[0]);
  711                 grpsiz = (auth_len >> 2) - 5;
  712                 *tl++ = txdr_unsigned(grpsiz);
  713                 for (i = 1; i <= grpsiz; i++)
  714                         *tl++ = txdr_unsigned(cr->cr_groups[i]);
  715                 break;
  716         case RPCAUTH_KERB4:
  717                 siz = auth_len;
  718                 while (siz > 0) {
  719                         if (M_TRAILINGSPACE(mb) == 0) {
  720                                 MGET(mb2, M_WAIT, MT_DATA);
  721                                 if (siz >= MINCLSIZE)
  722                                         MCLGET(mb2, M_WAIT);
  723                                 mb->m_next = mb2;
  724                                 mb = mb2;
  725                                 mb->m_len = 0;
  726                                 bpos = mtod(mb, caddr_t);
  727                         }
  728                         i = min(siz, M_TRAILINGSPACE(mb));
  729                         bcopy(auth_str, bpos, i);
  730                         mb->m_len += i;
  731                         auth_str += i;
  732                         bpos += i;
  733                         siz -= i;
  734                 }
  735                 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
  736                         for (i = 0; i < siz; i++)
  737                                 *bpos++ = '\0';
  738                         mb->m_len += siz;
  739                 }
  740                 break;
  741         };
  742 
  743         /*
  744          * And the verifier...
  745          */
  746         nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  747         if (verf_str) {
  748                 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
  749                 *tl = txdr_unsigned(verf_len);
  750                 siz = verf_len;
  751                 while (siz > 0) {
  752                         if (M_TRAILINGSPACE(mb) == 0) {
  753                                 MGET(mb2, M_WAIT, MT_DATA);
  754                                 if (siz >= MINCLSIZE)
  755                                         MCLGET(mb2, M_WAIT);
  756                                 mb->m_next = mb2;
  757                                 mb = mb2;
  758                                 mb->m_len = 0;
  759                                 bpos = mtod(mb, caddr_t);
  760                         }
  761                         i = min(siz, M_TRAILINGSPACE(mb));
  762                         bcopy(verf_str, bpos, i);
  763                         mb->m_len += i;
  764                         verf_str += i;
  765                         bpos += i;
  766                         siz -= i;
  767                 }
  768                 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
  769                         for (i = 0; i < siz; i++)
  770                                 *bpos++ = '\0';
  771                         mb->m_len += siz;
  772                 }
  773         } else {
  774                 *tl++ = txdr_unsigned(RPCAUTH_NULL);
  775                 *tl = 0;
  776         }
  777         mb->m_next = mrest;
  778         mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
  779         mreq->m_pkthdr.rcvif = (struct ifnet *)0;
  780         *mbp = mb;
  781         return (mreq);
  782 }
  783 
  784 /*
  785  * copies mbuf chain to the uio scatter/gather list
  786  */
  787 int
  788 nfsm_mbuftouio(mrep, uiop, siz, dpos)
  789         struct mbuf **mrep;
  790         register struct uio *uiop;
  791         int siz;
  792         caddr_t *dpos;
  793 {
  794         register char *mbufcp, *uiocp;
  795         register int xfer, left, len;
  796         register struct mbuf *mp;
  797         long uiosiz, rem;
  798         int error = 0;
  799 
  800         mp = *mrep;
  801         mbufcp = *dpos;
  802         len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
  803         rem = nfsm_rndup(siz)-siz;
  804         while (siz > 0) {
  805                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
  806                         return (EFBIG);
  807                 left = uiop->uio_iov->iov_len;
  808                 uiocp = uiop->uio_iov->iov_base;
  809                 if (left > siz)
  810                         left = siz;
  811                 uiosiz = left;
  812                 while (left > 0) {
  813                         while (len == 0) {
  814                                 mp = mp->m_next;
  815                                 if (mp == NULL)
  816                                         return (EBADRPC);
  817                                 mbufcp = mtod(mp, caddr_t);
  818                                 len = mp->m_len;
  819                         }
  820                         xfer = (left > len) ? len : left;
  821 #ifdef notdef
  822                         /* Not Yet.. */
  823                         if (uiop->uio_iov->iov_op != NULL)
  824                                 (*(uiop->uio_iov->iov_op))
  825                                 (mbufcp, uiocp, xfer);
  826                         else
  827 #endif
  828                         if (uiop->uio_segflg == UIO_SYSSPACE)
  829                                 bcopy(mbufcp, uiocp, xfer);
  830                         else
  831                                 copyout(mbufcp, uiocp, xfer);
  832                         left -= xfer;
  833                         len -= xfer;
  834                         mbufcp += xfer;
  835                         uiocp += xfer;
  836                         uiop->uio_offset += xfer;
  837                         uiop->uio_resid -= xfer;
  838                 }
  839                 if (uiop->uio_iov->iov_len <= siz) {
  840                         uiop->uio_iovcnt--;
  841                         uiop->uio_iov++;
  842                 } else {
  843                         uiop->uio_iov->iov_base += uiosiz;
  844                         uiop->uio_iov->iov_len -= uiosiz;
  845                 }
  846                 siz -= uiosiz;
  847         }
  848         *dpos = mbufcp;
  849         *mrep = mp;
  850         if (rem > 0) {
  851                 if (len < rem)
  852                         error = nfs_adv(mrep, dpos, rem, len);
  853                 else
  854                         *dpos += rem;
  855         }
  856         return (error);
  857 }
  858 
  859 /*
  860  * copies a uio scatter/gather list to an mbuf chain.
  861  * NOTE: can ony handle iovcnt == 1
  862  */
  863 int
  864 nfsm_uiotombuf(uiop, mq, siz, bpos)
  865         register struct uio *uiop;
  866         struct mbuf **mq;
  867         int siz;
  868         caddr_t *bpos;
  869 {
  870         register char *uiocp;
  871         register struct mbuf *mp, *mp2;
  872         register int xfer, left, mlen;
  873         int uiosiz, clflg, rem;
  874         char *cp;
  875 
  876 #ifdef DIAGNOSTIC
  877         if (uiop->uio_iovcnt != 1)
  878                 panic("nfsm_uiotombuf: iovcnt != 1");
  879 #endif
  880 
  881         if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
  882                 clflg = 1;
  883         else
  884                 clflg = 0;
  885         rem = nfsm_rndup(siz)-siz;
  886         mp = mp2 = *mq;
  887         while (siz > 0) {
  888                 left = uiop->uio_iov->iov_len;
  889                 uiocp = uiop->uio_iov->iov_base;
  890                 if (left > siz)
  891                         left = siz;
  892                 uiosiz = left;
  893                 while (left > 0) {
  894                         mlen = M_TRAILINGSPACE(mp);
  895                         if (mlen == 0) {
  896                                 MGET(mp, M_WAIT, MT_DATA);
  897                                 if (clflg)
  898                                         MCLGET(mp, M_WAIT);
  899                                 mp->m_len = 0;
  900                                 mp2->m_next = mp;
  901                                 mp2 = mp;
  902                                 mlen = M_TRAILINGSPACE(mp);
  903                         }
  904                         xfer = (left > mlen) ? mlen : left;
  905 #ifdef notdef
  906                         /* Not Yet.. */
  907                         if (uiop->uio_iov->iov_op != NULL)
  908                                 (*(uiop->uio_iov->iov_op))
  909                                 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
  910                         else
  911 #endif
  912                         if (uiop->uio_segflg == UIO_SYSSPACE)
  913                                 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
  914                         else
  915                                 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
  916                         mp->m_len += xfer;
  917                         left -= xfer;
  918                         uiocp += xfer;
  919                         uiop->uio_offset += xfer;
  920                         uiop->uio_resid -= xfer;
  921                 }
  922                 uiop->uio_iov->iov_base += uiosiz;
  923                 uiop->uio_iov->iov_len -= uiosiz;
  924                 siz -= uiosiz;
  925         }
  926         if (rem > 0) {
  927                 if (rem > M_TRAILINGSPACE(mp)) {
  928                         MGET(mp, M_WAIT, MT_DATA);
  929                         mp->m_len = 0;
  930                         mp2->m_next = mp;
  931                 }
  932                 cp = mtod(mp, caddr_t)+mp->m_len;
  933                 for (left = 0; left < rem; left++)
  934                         *cp++ = '\0';
  935                 mp->m_len += rem;
  936                 *bpos = cp;
  937         } else
  938                 *bpos = mtod(mp, caddr_t)+mp->m_len;
  939         *mq = mp;
  940         return (0);
  941 }
  942 
  943 /*
  944  * Help break down an mbuf chain by setting the first siz bytes contiguous
  945  * pointed to by returned val.
  946  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
  947  * cases. (The macros use the vars. dpos and dpos2)
  948  */
  949 int
  950 nfsm_disct(mdp, dposp, siz, left, cp2)
  951         struct mbuf **mdp;
  952         caddr_t *dposp;
  953         int siz;
  954         int left;
  955         caddr_t *cp2;
  956 {
  957         register struct mbuf *mp, *mp2;
  958         register int siz2, xfer;
  959         register caddr_t p;
  960 
  961         mp = *mdp;
  962         while (left == 0) {
  963                 *mdp = mp = mp->m_next;
  964                 if (mp == NULL)
  965                         return (EBADRPC);
  966                 left = mp->m_len;
  967                 *dposp = mtod(mp, caddr_t);
  968         }
  969         if (left >= siz) {
  970                 *cp2 = *dposp;
  971                 *dposp += siz;
  972         } else if (mp->m_next == NULL) {
  973                 return (EBADRPC);
  974         } else if (siz > MHLEN) {
  975                 panic("nfs S too big");
  976         } else {
  977                 MGET(mp2, M_WAIT, MT_DATA);
  978                 mp2->m_next = mp->m_next;
  979                 mp->m_next = mp2;
  980                 mp->m_len -= left;
  981                 mp = mp2;
  982                 *cp2 = p = mtod(mp, caddr_t);
  983                 bcopy(*dposp, p, left);         /* Copy what was left */
  984                 siz2 = siz-left;
  985                 p += left;
  986                 mp2 = mp->m_next;
  987                 /* Loop around copying up the siz2 bytes */
  988                 while (siz2 > 0) {
  989                         if (mp2 == NULL)
  990                                 return (EBADRPC);
  991                         xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
  992                         if (xfer > 0) {
  993                                 bcopy(mtod(mp2, caddr_t), p, xfer);
  994                                 NFSMADV(mp2, xfer);
  995                                 mp2->m_len -= xfer;
  996                                 p += xfer;
  997                                 siz2 -= xfer;
  998                         }
  999                         if (siz2 > 0)
 1000                                 mp2 = mp2->m_next;
 1001                 }
 1002                 mp->m_len = siz;
 1003                 *mdp = mp2;
 1004                 *dposp = mtod(mp2, caddr_t);
 1005         }
 1006         return (0);
 1007 }
 1008 
 1009 /*
 1010  * Advance the position in the mbuf chain.
 1011  */
 1012 int
 1013 nfs_adv(mdp, dposp, offs, left)
 1014         struct mbuf **mdp;
 1015         caddr_t *dposp;
 1016         int offs;
 1017         int left;
 1018 {
 1019         register struct mbuf *m;
 1020         register int s;
 1021 
 1022         m = *mdp;
 1023         s = left;
 1024         while (s < offs) {
 1025                 offs -= s;
 1026                 m = m->m_next;
 1027                 if (m == NULL)
 1028                         return (EBADRPC);
 1029                 s = m->m_len;
 1030         }
 1031         *mdp = m;
 1032         *dposp = mtod(m, caddr_t)+offs;
 1033         return (0);
 1034 }
 1035 
 1036 /*
 1037  * Copy a string into mbufs for the hard cases...
 1038  */
 1039 int
 1040 nfsm_strtmbuf(mb, bpos, cp, siz)
 1041         struct mbuf **mb;
 1042         char **bpos;
 1043         const char *cp;
 1044         long siz;
 1045 {
 1046         register struct mbuf *m1 = NULL, *m2;
 1047         long left, xfer, len, tlen;
 1048         u_int32_t *tl;
 1049         int putsize;
 1050 
 1051         putsize = 1;
 1052         m2 = *mb;
 1053         left = M_TRAILINGSPACE(m2);
 1054         if (left > 0) {
 1055                 tl = ((u_int32_t *)(*bpos));
 1056                 *tl++ = txdr_unsigned(siz);
 1057                 putsize = 0;
 1058                 left -= NFSX_UNSIGNED;
 1059                 m2->m_len += NFSX_UNSIGNED;
 1060                 if (left > 0) {
 1061                         bcopy(cp, (caddr_t) tl, left);
 1062                         siz -= left;
 1063                         cp += left;
 1064                         m2->m_len += left;
 1065                         left = 0;
 1066                 }
 1067         }
 1068         /* Loop around adding mbufs */
 1069         while (siz > 0) {
 1070                 MGET(m1, M_WAIT, MT_DATA);
 1071                 if (siz > MLEN)
 1072                         MCLGET(m1, M_WAIT);
 1073                 m1->m_len = NFSMSIZ(m1);
 1074                 m2->m_next = m1;
 1075                 m2 = m1;
 1076                 tl = mtod(m1, u_int32_t *);
 1077                 tlen = 0;
 1078                 if (putsize) {
 1079                         *tl++ = txdr_unsigned(siz);
 1080                         m1->m_len -= NFSX_UNSIGNED;
 1081                         tlen = NFSX_UNSIGNED;
 1082                         putsize = 0;
 1083                 }
 1084                 if (siz < m1->m_len) {
 1085                         len = nfsm_rndup(siz);
 1086                         xfer = siz;
 1087                         if (xfer < len)
 1088                                 *(tl+(xfer>>2)) = 0;
 1089                 } else {
 1090                         xfer = len = m1->m_len;
 1091                 }
 1092                 bcopy(cp, (caddr_t) tl, xfer);
 1093                 m1->m_len = len+tlen;
 1094                 siz -= xfer;
 1095                 cp += xfer;
 1096         }
 1097         *mb = m1;
 1098         *bpos = mtod(m1, caddr_t)+m1->m_len;
 1099         return (0);
 1100 }
 1101 
 1102 /*
 1103  * Called once to initialize data structures...
 1104  */
 1105 int
 1106 nfs_init(vfsp)
 1107         struct vfsconf *vfsp;
 1108 {
 1109         register int i;
 1110 
 1111         nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1);
 1112 
 1113         nfs_mount_type = vfsp->vfc_typenum;
 1114         nfsrtt.pos = 0;
 1115         rpc_vers = txdr_unsigned(RPC_VER2);
 1116         rpc_call = txdr_unsigned(RPC_CALL);
 1117         rpc_reply = txdr_unsigned(RPC_REPLY);
 1118         rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
 1119         rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
 1120         rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
 1121         rpc_autherr = txdr_unsigned(RPC_AUTHERR);
 1122         rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
 1123         rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
 1124         nfs_prog = txdr_unsigned(NFS_PROG);
 1125         nqnfs_prog = txdr_unsigned(NQNFS_PROG);
 1126         nfs_true = txdr_unsigned(TRUE);
 1127         nfs_false = txdr_unsigned(FALSE);
 1128         nfs_xdrneg1 = txdr_unsigned(-1);
 1129         nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
 1130         if (nfs_ticks < 1)
 1131                 nfs_ticks = 1;
 1132         /* Ensure async daemons disabled */
 1133         for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
 1134                 nfs_iodwant[i] = (struct proc *)0;
 1135                 nfs_iodmount[i] = (struct nfsmount *)0;
 1136         }
 1137         nfs_nhinit();                   /* Init the nfsnode table */
 1138 #ifndef NFS_NOSERVER
 1139         nfsrv_init(0);                  /* Init server data structures */
 1140         nfsrv_initcache();              /* Init the server request cache */
 1141 #endif
 1142 
 1143         /*
 1144          * Initialize the nqnfs server stuff.
 1145          */
 1146         if (nqnfsstarttime == 0) {
 1147                 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
 1148                         + nqsrv_clockskew + nqsrv_writeslack;
 1149                 NQLOADNOVRAM(nqnfsstarttime);
 1150                 CIRCLEQ_INIT(&nqtimerhead);
 1151                 nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
 1152         }
 1153 
 1154         /*
 1155          * Initialize reply list and start timer
 1156          */
 1157         TAILQ_INIT(&nfs_reqq);
 1158 
 1159         nfs_timer(0);
 1160 
 1161         /*
 1162          * Set up lease_check and lease_updatetime so that other parts
 1163          * of the system can call us, if we are loadable.
 1164          */
 1165 #ifndef NFS_NOSERVER
 1166         nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)];
 1167         default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check;
 1168 #endif
 1169         nfs_prev_lease_updatetime = lease_updatetime;
 1170         lease_updatetime = nfs_lease_updatetime;
 1171         nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
 1172         sysent[SYS_nfssvc].sy_narg = 2;
 1173         nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
 1174         sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
 1175 
 1176         nfs_pbuf_freecnt = nswbuf / 2 + 1;
 1177 
 1178         return (0);
 1179 }
 1180 
 1181 int
 1182 nfs_uninit(vfsp)
 1183         struct vfsconf *vfsp;
 1184 {
 1185 
 1186         untimeout(nfs_timer, (void *)NULL, nfs_timer_handle);
 1187         nfs_mount_type = -1;
 1188 #ifndef NFS_NOSERVER
 1189         default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check;
 1190 #endif
 1191         lease_updatetime = nfs_prev_lease_updatetime;
 1192         sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
 1193         sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
 1194         return (0);
 1195 }
 1196 
 1197 /*
 1198  * Attribute cache routines.
 1199  * nfs_loadattrcache() - loads or updates the cache contents from attributes
 1200  *      that are on the mbuf list
 1201  * nfs_getattrcache() - returns valid attributes if found in cache, returns
 1202  *      error otherwise
 1203  */
 1204 
 1205 /*
 1206  * Load the attribute cache (that lives in the nfsnode entry) with
 1207  * the values on the mbuf list and
 1208  * Iff vap not NULL
 1209  *    copy the attributes to *vaper
 1210  */
 1211 int
 1212 nfs_loadattrcache(vpp, mdp, dposp, vaper, dontshrink)
 1213         struct vnode **vpp;
 1214         struct mbuf **mdp;
 1215         caddr_t *dposp;
 1216         struct vattr *vaper;
 1217         int dontshrink;
 1218 {
 1219         register struct vnode *vp = *vpp;
 1220         register struct vattr *vap;
 1221         register struct nfs_fattr *fp;
 1222         register struct nfsnode *np;
 1223         register int32_t t1;
 1224         caddr_t cp2;
 1225         int error = 0, rdev;
 1226         struct mbuf *md;
 1227         enum vtype vtyp;
 1228         u_short vmode;
 1229         struct timespec mtime;
 1230         int v3 = NFS_ISV3(vp);
 1231 
 1232         md = *mdp;
 1233         t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
 1234         if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0)
 1235                 return (error);
 1236         fp = (struct nfs_fattr *)cp2;
 1237         if (v3) {
 1238                 vtyp = nfsv3tov_type(fp->fa_type);
 1239                 vmode = fxdr_unsigned(u_short, fp->fa_mode);
 1240                 rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
 1241                         fxdr_unsigned(int, fp->fa3_rdev.specdata2));
 1242                 fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
 1243         } else {
 1244                 vtyp = nfsv2tov_type(fp->fa_type);
 1245                 vmode = fxdr_unsigned(u_short, fp->fa_mode);
 1246                 /*
 1247                  * XXX
 1248                  *
 1249                  * The duplicate information returned in fa_type and fa_mode
 1250                  * is an ambiguity in the NFS version 2 protocol.
 1251                  *
 1252                  * VREG should be taken literally as a regular file.  If a
 1253                  * server intents to return some type information differently
 1254                  * in the upper bits of the mode field (e.g. for sockets, or
 1255                  * FIFOs), NFSv2 mandates fa_type to be VNON.  Anyway, we
 1256                  * leave the examination of the mode bits even in the VREG
 1257                  * case to avoid breakage for bogus servers, but we make sure
 1258                  * that there are actually type bits set in the upper part of
 1259                  * fa_mode (and failing that, trust the va_type field).
 1260                  *
 1261                  * NFSv3 cleared the issue, and requires fa_mode to not
 1262                  * contain any type information (while also introduing sockets
 1263                  * and FIFOs for fa_type).
 1264                  */
 1265                 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
 1266                         vtyp = IFTOVT(vmode);
 1267                 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
 1268                 fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
 1269 
 1270                 /*
 1271                  * Really ugly NFSv2 kludge.
 1272                  */
 1273                 if (vtyp == VCHR && rdev == 0xffffffff)
 1274                         vtyp = VFIFO;
 1275         }
 1276 
 1277         /*
 1278          * If v_type == VNON it is a new node, so fill in the v_type,
 1279          * n_mtime fields. Check to see if it represents a special
 1280          * device, and if so, check for a possible alias. Once the
 1281          * correct vnode has been obtained, fill in the rest of the
 1282          * information.
 1283          */
 1284         np = VTONFS(vp);
 1285         if (vp->v_type != vtyp) {
 1286                 vp->v_type = vtyp;
 1287                 if (vp->v_type == VFIFO) {
 1288                         vp->v_op = fifo_nfsv2nodeop_p;
 1289                 }
 1290                 if (vp->v_type == VCHR || vp->v_type == VBLK) {
 1291                         vp->v_op = spec_nfsv2nodeop_p;
 1292                         addaliasu(vp, rdev);
 1293                 }
 1294                 np->n_mtime = mtime.tv_sec;
 1295         }
 1296         vap = &np->n_vattr;
 1297         vap->va_type = vtyp;
 1298         vap->va_mode = (vmode & 07777);
 1299         vap->va_rdev = rdev;
 1300         vap->va_mtime = mtime;
 1301         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
 1302         if (v3) {
 1303                 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
 1304                 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
 1305                 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
 1306                 vap->va_size = fxdr_hyper(&fp->fa3_size);
 1307                 vap->va_blocksize = NFS_FABLKSIZE;
 1308                 vap->va_bytes = fxdr_hyper(&fp->fa3_used);
 1309                 vap->va_fileid = fxdr_unsigned(int32_t,
 1310                     fp->fa3_fileid.nfsuquad[1]);
 1311                 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
 1312                 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
 1313                 vap->va_flags = 0;
 1314                 vap->va_filerev = 0;
 1315         } else {
 1316                 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
 1317                 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
 1318                 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
 1319                 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
 1320                 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
 1321                 vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks)
 1322                     * NFS_FABLKSIZE;
 1323                 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
 1324                 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
 1325                 vap->va_flags = 0;
 1326                 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
 1327                     fp->fa2_ctime.nfsv2_sec);
 1328                 vap->va_ctime.tv_nsec = 0;
 1329                 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
 1330                 vap->va_filerev = 0;
 1331         }
 1332         np->n_attrstamp = time_second;
 1333         if (vap->va_size != np->n_size) {
 1334                 if (vap->va_type == VREG) {
 1335                         if (dontshrink && vap->va_size < np->n_size) {
 1336                                 /*
 1337                                  * We've been told not to shrink the file;
 1338                                  * zero np->n_attrstamp to indicate that
 1339                                  * the attributes are stale.
 1340                                  */
 1341                                 vap->va_size = np->n_size;
 1342                                 np->n_attrstamp = 0;
 1343                         } else if (np->n_flag & NMODIFIED) {
 1344                                 /*
 1345                                  * We've modified the file: Use the larger
 1346                                  * of our size, and the server's size.
 1347                                  */
 1348                                 if (vap->va_size < np->n_size) {
 1349                                         vap->va_size = np->n_size;
 1350                                 } else {
 1351                                         np->n_size = vap->va_size;
 1352                                         np->n_flag |= NSIZECHANGED;
 1353                                 }
 1354                         } else {
 1355                                 np->n_size = vap->va_size;
 1356                                 np->n_flag |= NSIZECHANGED;
 1357                         }
 1358                         vnode_pager_setsize(vp, np->n_size);
 1359                 } else {
 1360                         np->n_size = vap->va_size;
 1361                 }
 1362         }
 1363         if (vaper != NULL) {
 1364                 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
 1365                 if (np->n_flag & NCHG) {
 1366                         if (np->n_flag & NACC)
 1367                                 vaper->va_atime = np->n_atim;
 1368                         if (np->n_flag & NUPD)
 1369                                 vaper->va_mtime = np->n_mtim;
 1370                 }
 1371         }
 1372         return (0);
 1373 }
 1374 
 1375 #ifdef NFS_ACDEBUG
 1376 #include <sys/sysctl.h>
 1377 SYSCTL_DECL(_vfs_nfs);
 1378 static int nfs_acdebug;
 1379 SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, "");
 1380 #endif
 1381 
 1382 /*
 1383  * Check the time stamp
 1384  * If the cache is valid, copy contents to *vap and return 0
 1385  * otherwise return an error
 1386  */
 1387 int
 1388 nfs_getattrcache(vp, vaper)
 1389         register struct vnode *vp;
 1390         struct vattr *vaper;
 1391 {
 1392         register struct nfsnode *np;
 1393         register struct vattr *vap;
 1394         struct nfsmount *nmp;
 1395         int timeo;
 1396 
 1397         np = VTONFS(vp);
 1398         vap = &np->n_vattr;
 1399         nmp = VFSTONFS(vp->v_mount);
 1400         /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
 1401         timeo = (time_second - np->n_mtime) / 10;
 1402 
 1403 #ifdef NFS_ACDEBUG
 1404         if (nfs_acdebug>1)
 1405                 printf("nfs_getattrcache: initial timeo = %d\n", timeo);
 1406 #endif
 1407 
 1408         if (vap->va_type == VDIR) {
 1409                 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
 1410                         timeo = nmp->nm_acdirmin;
 1411                 else if (timeo > nmp->nm_acdirmax)
 1412                         timeo = nmp->nm_acdirmax;
 1413         } else {
 1414                 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
 1415                         timeo = nmp->nm_acregmin;
 1416                 else if (timeo > nmp->nm_acregmax)
 1417                         timeo = nmp->nm_acregmax;
 1418         }
 1419 
 1420 #ifdef NFS_ACDEBUG
 1421         if (nfs_acdebug > 2)
 1422                 printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
 1423                         nmp->nm_acregmin, nmp->nm_acregmax,
 1424                         nmp->nm_acdirmin, nmp->nm_acdirmax);
 1425 
 1426         if (nfs_acdebug)
 1427                 printf("nfs_getattrcache: age = %d; final timeo = %d\n",
 1428                         (time_second - np->n_attrstamp), timeo);
 1429 #endif
 1430 
 1431         if ((time_second - np->n_attrstamp) >= timeo) {
 1432                 nfsstats.attrcache_misses++;
 1433                 return (ENOENT);
 1434         }
 1435         nfsstats.attrcache_hits++;
 1436         if (vap->va_size != np->n_size) {
 1437                 if (vap->va_type == VREG) {
 1438                         if (np->n_flag & NMODIFIED) {
 1439                                 if (vap->va_size < np->n_size)
 1440                                         vap->va_size = np->n_size;
 1441                                 else
 1442                                         np->n_size = vap->va_size;
 1443                         } else {
 1444                                 np->n_size = vap->va_size;
 1445                         }
 1446                         vnode_pager_setsize(vp, np->n_size);
 1447                 } else {
 1448                         np->n_size = vap->va_size;
 1449                 }
 1450         }
 1451         bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
 1452         if (np->n_flag & NCHG) {
 1453                 if (np->n_flag & NACC)
 1454                         vaper->va_atime = np->n_atim;
 1455                 if (np->n_flag & NUPD)
 1456                         vaper->va_mtime = np->n_mtim;
 1457         }
 1458         return (0);
 1459 }
 1460 
 1461 #ifndef NFS_NOSERVER
 1462 /*
 1463  * Set up nameidata for a lookup() call and do it.
 1464  *
 1465  * If pubflag is set, this call is done for a lookup operation on the
 1466  * public filehandle. In that case we allow crossing mountpoints and
 1467  * absolute pathnames. However, the caller is expected to check that
 1468  * the lookup result is within the public fs, and deny access if
 1469  * it is not.
 1470  *
 1471  * nfs_namei() clears out garbage fields that namei() might leave garbage.
 1472  * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
 1473  * error occurs but the parent was not requested.
 1474  *
 1475  * dirp may be set whether an error is returned or not, and must be 
 1476  * released by the caller.
 1477  */
 1478 int
 1479 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
 1480         register struct nameidata *ndp;
 1481         fhandle_t *fhp;
 1482         int len;
 1483         struct nfssvc_sock *slp;
 1484         struct sockaddr *nam;
 1485         struct mbuf **mdp;
 1486         caddr_t *dposp;
 1487         struct vnode **retdirp;
 1488         struct proc *p;
 1489         int kerbflag, pubflag;
 1490 {
 1491         register int i, rem;
 1492         register struct mbuf *md;
 1493         register char *fromcp, *tocp, *cp;
 1494         struct iovec aiov;
 1495         struct uio auio;
 1496         struct vnode *dp;
 1497         int error, rdonly, linklen;
 1498         struct componentname *cnp = &ndp->ni_cnd;
 1499 
 1500         *retdirp = (struct vnode *)0;
 1501         cnp->cn_pnbuf = zalloc(namei_zone);
 1502 
 1503         /*
 1504          * Copy the name from the mbuf list to ndp->ni_pnbuf
 1505          * and set the various ndp fields appropriately.
 1506          */
 1507         fromcp = *dposp;
 1508         tocp = cnp->cn_pnbuf;
 1509         md = *mdp;
 1510         rem = mtod(md, caddr_t) + md->m_len - fromcp;
 1511         for (i = 0; i < len; i++) {
 1512                 while (rem == 0) {
 1513                         md = md->m_next;
 1514                         if (md == NULL) {
 1515                                 error = EBADRPC;
 1516                                 goto out;
 1517                         }
 1518                         fromcp = mtod(md, caddr_t);
 1519                         rem = md->m_len;
 1520                 }
 1521                 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
 1522                         error = EACCES;
 1523                         goto out;
 1524                 }
 1525                 *tocp++ = *fromcp++;
 1526                 rem--;
 1527         }
 1528         *tocp = '\0';
 1529         *mdp = md;
 1530         *dposp = fromcp;
 1531         len = nfsm_rndup(len)-len;
 1532         if (len > 0) {
 1533                 if (rem >= len)
 1534                         *dposp += len;
 1535                 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
 1536                         goto out;
 1537         }
 1538 
 1539         /*
 1540          * Extract and set starting directory.
 1541          */
 1542         error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
 1543             nam, &rdonly, kerbflag, pubflag);
 1544         if (error)
 1545                 goto out;
 1546         if (dp->v_type != VDIR) {
 1547                 vrele(dp);
 1548                 error = ENOTDIR;
 1549                 goto out;
 1550         }
 1551 
 1552         if (rdonly)
 1553                 cnp->cn_flags |= RDONLY;
 1554 
 1555         /*
 1556          * Set return directory.  Reference to dp is implicitly transfered 
 1557          * to the returned pointer
 1558          */
 1559         *retdirp = dp;
 1560 
 1561         if (pubflag) {
 1562                 /*
 1563                  * Oh joy. For WebNFS, handle those pesky '%' escapes,
 1564                  * and the 'native path' indicator.
 1565                  */
 1566                 cp = zalloc(namei_zone);
 1567                 fromcp = cnp->cn_pnbuf;
 1568                 tocp = cp;
 1569                 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
 1570                         switch ((unsigned char)*fromcp) {
 1571                         case WEBNFS_NATIVE_CHAR:
 1572                                 /*
 1573                                  * 'Native' path for us is the same
 1574                                  * as a path according to the NFS spec,
 1575                                  * just skip the escape char.
 1576                                  */
 1577                                 fromcp++;
 1578                                 break;
 1579                         /*
 1580                          * More may be added in the future, range 0x80-0xff
 1581                          */
 1582                         default:
 1583                                 error = EIO;
 1584                                 zfree(namei_zone, cp);
 1585                                 goto out;
 1586                         }
 1587                 }
 1588                 /*
 1589                  * Translate the '%' escapes, URL-style.
 1590                  */
 1591                 while (*fromcp != '\0') {
 1592                         if (*fromcp == WEBNFS_ESC_CHAR) {
 1593                                 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
 1594                                         fromcp++;
 1595                                         *tocp++ = HEXSTRTOI(fromcp);
 1596                                         fromcp += 2;
 1597                                         continue;
 1598                                 } else {
 1599                                         error = ENOENT;
 1600                                         zfree(namei_zone, cp);
 1601                                         goto out;
 1602                                 }
 1603                         } else
 1604                                 *tocp++ = *fromcp++;
 1605                 }
 1606                 *tocp = '\0';
 1607                 zfree(namei_zone, cnp->cn_pnbuf);
 1608                 cnp->cn_pnbuf = cp;
 1609         }
 1610 
 1611         ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
 1612         ndp->ni_segflg = UIO_SYSSPACE;
 1613 
 1614         if (pubflag) {
 1615                 ndp->ni_rootdir = rootvnode;
 1616                 ndp->ni_loopcnt = 0;
 1617                 if (cnp->cn_pnbuf[0] == '/')
 1618                         dp = rootvnode;
 1619         } else {
 1620                 cnp->cn_flags |= NOCROSSMOUNT;
 1621         }
 1622 
 1623         /*
 1624          * Initialize for scan, set ni_startdir and bump ref on dp again
 1625          * becuase lookup() will dereference ni_startdir.
 1626          */
 1627 
 1628         cnp->cn_proc = p;
 1629         VREF(dp);
 1630         ndp->ni_startdir = dp;
 1631 
 1632         for (;;) {
 1633                 cnp->cn_nameptr = cnp->cn_pnbuf;
 1634                 /*
 1635                  * Call lookup() to do the real work.  If an error occurs,
 1636                  * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
 1637                  * we do not have to dereference anything before returning.
 1638                  * In either case ni_startdir will be dereferenced and NULLed
 1639                  * out.
 1640                  */
 1641                 error = lookup(ndp);
 1642                 if (error)
 1643                         break;
 1644 
 1645                 /*
 1646                  * Check for encountering a symbolic link.  Trivial 
 1647                  * termination occurs if no symlink encountered.
 1648                  * Note: zfree is safe because error is 0, so we will
 1649                  * not zfree it again when we break.
 1650                  */
 1651                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
 1652                         nfsrv_object_create(ndp->ni_vp);
 1653                         if (cnp->cn_flags & (SAVENAME | SAVESTART))
 1654                                 cnp->cn_flags |= HASBUF;
 1655                         else
 1656                                 zfree(namei_zone, cnp->cn_pnbuf);
 1657                         break;
 1658                 }
 1659 
 1660                 /*
 1661                  * Validate symlink
 1662                  */
 1663                 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
 1664                         VOP_UNLOCK(ndp->ni_dvp, 0, p);
 1665                 if (!pubflag) {
 1666                         error = EINVAL;
 1667                         goto badlink2;
 1668                 }
 1669 
 1670                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
 1671                         error = ELOOP;
 1672                         goto badlink2;
 1673                 }
 1674                 if (ndp->ni_pathlen > 1)
 1675                         cp = zalloc(namei_zone);
 1676                 else
 1677                         cp = cnp->cn_pnbuf;
 1678                 aiov.iov_base = cp;
 1679                 aiov.iov_len = MAXPATHLEN;
 1680                 auio.uio_iov = &aiov;
 1681                 auio.uio_iovcnt = 1;
 1682                 auio.uio_offset = 0;
 1683                 auio.uio_rw = UIO_READ;
 1684                 auio.uio_segflg = UIO_SYSSPACE;
 1685                 auio.uio_procp = (struct proc *)0;
 1686                 auio.uio_resid = MAXPATHLEN;
 1687                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
 1688                 if (error) {
 1689                 badlink1:
 1690                         if (ndp->ni_pathlen > 1)
 1691                                 zfree(namei_zone, cp);
 1692                 badlink2:
 1693                         vrele(ndp->ni_dvp);
 1694                         vput(ndp->ni_vp);
 1695                         break;
 1696                 }
 1697                 linklen = MAXPATHLEN - auio.uio_resid;
 1698                 if (linklen == 0) {
 1699                         error = ENOENT;
 1700                         goto badlink1;
 1701                 }
 1702                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
 1703                         error = ENAMETOOLONG;
 1704                         goto badlink1;
 1705                 }
 1706 
 1707                 /*
 1708                  * Adjust or replace path
 1709                  */
 1710                 if (ndp->ni_pathlen > 1) {
 1711                         bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
 1712                         zfree(namei_zone, cnp->cn_pnbuf);
 1713                         cnp->cn_pnbuf = cp;
 1714                 } else
 1715                         cnp->cn_pnbuf[linklen] = '\0';
 1716                 ndp->ni_pathlen += linklen;
 1717 
 1718                 /*
 1719                  * Cleanup refs for next loop and check if root directory 
 1720                  * should replace current directory.  Normally ni_dvp 
 1721                  * becomes the new base directory and is cleaned up when
 1722                  * we loop.  Explicitly null pointers after invalidation
 1723                  * to clarify operation.
 1724                  */
 1725                 vput(ndp->ni_vp);
 1726                 ndp->ni_vp = NULL;
 1727 
 1728                 if (cnp->cn_pnbuf[0] == '/') {
 1729                         vrele(ndp->ni_dvp);
 1730                         ndp->ni_dvp = ndp->ni_rootdir;
 1731                         VREF(ndp->ni_dvp);
 1732                 }
 1733                 ndp->ni_startdir = ndp->ni_dvp;
 1734                 ndp->ni_dvp = NULL;
 1735         }
 1736 
 1737         /*
 1738          * nfs_namei() guarentees that fields will not contain garbage
 1739          * whether an error occurs or not.  This allows the caller to track
 1740          * cleanup state trivially.
 1741          */
 1742 out:
 1743         if (error) {
 1744                 zfree(namei_zone, cnp->cn_pnbuf);
 1745                 ndp->ni_vp = NULL;
 1746                 ndp->ni_dvp = NULL;
 1747                 ndp->ni_startdir = NULL;
 1748                 cnp->cn_flags &= ~HASBUF;
 1749         } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
 1750                 ndp->ni_dvp = NULL;
 1751         }
 1752         return (error);
 1753 }
 1754 
 1755 /*
 1756  * A fiddled version of m_adj() that ensures null fill to a long
 1757  * boundary and only trims off the back end
 1758  */
 1759 void
 1760 nfsm_adj(mp, len, nul)
 1761         struct mbuf *mp;
 1762         register int len;
 1763         int nul;
 1764 {
 1765         register struct mbuf *m;
 1766         register int count, i;
 1767         register char *cp;
 1768 
 1769         /*
 1770          * Trim from tail.  Scan the mbuf chain,
 1771          * calculating its length and finding the last mbuf.
 1772          * If the adjustment only affects this mbuf, then just
 1773          * adjust and return.  Otherwise, rescan and truncate
 1774          * after the remaining size.
 1775          */
 1776         count = 0;
 1777         m = mp;
 1778         for (;;) {
 1779                 count += m->m_len;
 1780                 if (m->m_next == (struct mbuf *)0)
 1781                         break;
 1782                 m = m->m_next;
 1783         }
 1784         if (m->m_len > len) {
 1785                 m->m_len -= len;
 1786                 if (nul > 0) {
 1787                         cp = mtod(m, caddr_t)+m->m_len-nul;
 1788                         for (i = 0; i < nul; i++)
 1789                                 *cp++ = '\0';
 1790                 }
 1791                 return;
 1792         }
 1793         count -= len;
 1794         if (count < 0)
 1795                 count = 0;
 1796         /*
 1797          * Correct length for chain is "count".
 1798          * Find the mbuf with last data, adjust its length,
 1799          * and toss data from remaining mbufs on chain.
 1800          */
 1801         for (m = mp; m; m = m->m_next) {
 1802                 if (m->m_len >= count) {
 1803                         m->m_len = count;
 1804                         if (nul > 0) {
 1805                                 cp = mtod(m, caddr_t)+m->m_len-nul;
 1806                                 for (i = 0; i < nul; i++)
 1807                                         *cp++ = '\0';
 1808                         }
 1809                         break;
 1810                 }
 1811                 count -= m->m_len;
 1812         }
 1813         for (m = m->m_next;m;m = m->m_next)
 1814                 m->m_len = 0;
 1815 }
 1816 
 1817 /*
 1818  * Make these functions instead of macros, so that the kernel text size
 1819  * doesn't get too big...
 1820  */
 1821 void
 1822 nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
 1823         struct nfsrv_descript *nfsd;
 1824         int before_ret;
 1825         register struct vattr *before_vap;
 1826         int after_ret;
 1827         struct vattr *after_vap;
 1828         struct mbuf **mbp;
 1829         char **bposp;
 1830 {
 1831         register struct mbuf *mb = *mbp, *mb2;
 1832         register char *bpos = *bposp;
 1833         register u_int32_t *tl;
 1834 
 1835         if (before_ret) {
 1836                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
 1837                 *tl = nfs_false;
 1838         } else {
 1839                 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 1840                 *tl++ = nfs_true;
 1841                 txdr_hyper(before_vap->va_size, tl);
 1842                 tl += 2;
 1843                 txdr_nfsv3time(&(before_vap->va_mtime), tl);
 1844                 tl += 2;
 1845                 txdr_nfsv3time(&(before_vap->va_ctime), tl);
 1846         }
 1847         *bposp = bpos;
 1848         *mbp = mb;
 1849         nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
 1850 }
 1851 
 1852 void
 1853 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
 1854         struct nfsrv_descript *nfsd;
 1855         int after_ret;
 1856         struct vattr *after_vap;
 1857         struct mbuf **mbp;
 1858         char **bposp;
 1859 {
 1860         register struct mbuf *mb = *mbp, *mb2;
 1861         register char *bpos = *bposp;
 1862         register u_int32_t *tl;
 1863         register struct nfs_fattr *fp;
 1864 
 1865         if (after_ret) {
 1866                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
 1867                 *tl = nfs_false;
 1868         } else {
 1869                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
 1870                 *tl++ = nfs_true;
 1871                 fp = (struct nfs_fattr *)tl;
 1872                 nfsm_srvfattr(nfsd, after_vap, fp);
 1873         }
 1874         *mbp = mb;
 1875         *bposp = bpos;
 1876 }
 1877 
 1878 void
 1879 nfsm_srvfattr(nfsd, vap, fp)
 1880         register struct nfsrv_descript *nfsd;
 1881         register struct vattr *vap;
 1882         register struct nfs_fattr *fp;
 1883 {
 1884 
 1885         fp->fa_nlink = txdr_unsigned(vap->va_nlink);
 1886         fp->fa_uid = txdr_unsigned(vap->va_uid);
 1887         fp->fa_gid = txdr_unsigned(vap->va_gid);
 1888         if (nfsd->nd_flag & ND_NFSV3) {
 1889                 fp->fa_type = vtonfsv3_type(vap->va_type);
 1890                 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
 1891                 txdr_hyper(vap->va_size, &fp->fa3_size);
 1892                 txdr_hyper(vap->va_bytes, &fp->fa3_used);
 1893                 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
 1894                 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
 1895                 fp->fa3_fsid.nfsuquad[0] = 0;
 1896                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
 1897                 fp->fa3_fileid.nfsuquad[0] = 0;
 1898                 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
 1899                 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
 1900                 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
 1901                 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
 1902         } else {
 1903                 fp->fa_type = vtonfsv2_type(vap->va_type);
 1904                 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
 1905                 fp->fa2_size = txdr_unsigned(vap->va_size);
 1906                 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
 1907                 if (vap->va_type == VFIFO)
 1908                         fp->fa2_rdev = 0xffffffff;
 1909                 else
 1910                         fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
 1911                 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
 1912                 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
 1913                 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
 1914                 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
 1915                 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
 1916                 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
 1917         }
 1918 }
 1919 
 1920 /*
 1921  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
 1922  *      - look up fsid in mount list (if not found ret error)
 1923  *      - get vp and export rights by calling VFS_FHTOVP()
 1924  *      - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
 1925  *      - if not lockflag unlock it with VOP_UNLOCK()
 1926  */
 1927 int
 1928 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
 1929         fhandle_t *fhp;
 1930         int lockflag;
 1931         struct vnode **vpp;
 1932         struct ucred *cred;
 1933         struct nfssvc_sock *slp;
 1934         struct sockaddr *nam;
 1935         int *rdonlyp;
 1936         int kerbflag;
 1937         int pubflag;
 1938 {
 1939         struct proc *p = curproc; /* XXX */
 1940         register struct mount *mp;
 1941         register int i;
 1942         struct ucred *credanon;
 1943         int error, exflags;
 1944 #ifdef MNT_EXNORESPORT          /* XXX needs mountd and /etc/exports help yet */
 1945         struct sockaddr_int *saddr;
 1946 #endif
 1947 
 1948         *vpp = (struct vnode *)0;
 1949 
 1950         if (nfs_ispublicfh(fhp)) {
 1951                 if (!pubflag || !nfs_pub.np_valid)
 1952                         return (ESTALE);
 1953                 fhp = &nfs_pub.np_handle;
 1954         }
 1955 
 1956         mp = vfs_getvfs(&fhp->fh_fsid);
 1957         if (!mp)
 1958                 return (ESTALE);
 1959         error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
 1960         if (error)
 1961                 return (error); 
 1962         error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
 1963         if (error)
 1964                 return (error);
 1965 #ifdef MNT_EXNORESPORT
 1966         if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
 1967                 saddr = (struct sockaddr_in *)nam;
 1968                 if (saddr->sin_family == AF_INET &&
 1969                     ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
 1970                         vput(*vpp);
 1971                         *vpp = NULL;
 1972                         return (NFSERR_AUTHERR | AUTH_TOOWEAK);
 1973                 }
 1974         }
 1975 #endif
 1976         /*
 1977          * Check/setup credentials.
 1978          */
 1979         if (exflags & MNT_EXKERB) {
 1980                 if (!kerbflag) {
 1981                         vput(*vpp);
 1982                         *vpp = NULL;
 1983                         return (NFSERR_AUTHERR | AUTH_TOOWEAK);
 1984                 }
 1985         } else if (kerbflag) {
 1986                 vput(*vpp);
 1987                 *vpp = NULL;
 1988                 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
 1989         } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
 1990                 cred->cr_uid = credanon->cr_uid;
 1991                 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
 1992                         cred->cr_groups[i] = credanon->cr_groups[i];
 1993                 cred->cr_ngroups = i;
 1994         }
 1995         if (exflags & MNT_EXRDONLY)
 1996                 *rdonlyp = 1;
 1997         else
 1998                 *rdonlyp = 0;
 1999 
 2000         nfsrv_object_create(*vpp);
 2001 
 2002         if (!lockflag)
 2003                 VOP_UNLOCK(*vpp, 0, p);
 2004         return (0);
 2005 }
 2006 
 2007 
 2008 /*
 2009  * WebNFS: check if a filehandle is a public filehandle. For v3, this
 2010  * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
 2011  * transformed this to all zeroes in both cases, so check for it.
 2012  */
 2013 int
 2014 nfs_ispublicfh(fhp)
 2015         fhandle_t *fhp;
 2016 {
 2017         char *cp = (char *)fhp;
 2018         int i;
 2019 
 2020         for (i = 0; i < NFSX_V3FH; i++)
 2021                 if (*cp++ != 0)
 2022                         return (FALSE);
 2023         return (TRUE);
 2024 }
 2025   
 2026 #endif /* NFS_NOSERVER */
 2027 /*
 2028  * This function compares two net addresses by family and returns TRUE
 2029  * if they are the same host.
 2030  * If there is any doubt, return FALSE.
 2031  * The AF_INET family is handled as a special case so that address mbufs
 2032  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
 2033  */
 2034 int
 2035 netaddr_match(family, haddr, nam)
 2036         int family;
 2037         union nethostaddr *haddr;
 2038         struct sockaddr *nam;
 2039 {
 2040         register struct sockaddr_in *inetaddr;
 2041 
 2042         switch (family) {
 2043         case AF_INET:
 2044                 inetaddr = (struct sockaddr_in *)nam;
 2045                 if (inetaddr->sin_family == AF_INET &&
 2046                     inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
 2047                         return (1);
 2048                 break;
 2049         default:
 2050                 break;
 2051         };
 2052         return (0);
 2053 }
 2054 
 2055 static nfsuint64 nfs_nullcookie = { { 0, 0 } };
 2056 /*
 2057  * This function finds the directory cookie that corresponds to the
 2058  * logical byte offset given.
 2059  */
 2060 nfsuint64 *
 2061 nfs_getcookie(np, off, add)
 2062         register struct nfsnode *np;
 2063         off_t off;
 2064         int add;
 2065 {
 2066         register struct nfsdmap *dp, *dp2;
 2067         register int pos;
 2068 
 2069         pos = (uoff_t)off / NFS_DIRBLKSIZ;
 2070         if (pos == 0 || off < 0) {
 2071 #ifdef DIAGNOSTIC
 2072                 if (add)
 2073                         panic("nfs getcookie add at <= 0");
 2074 #endif
 2075                 return (&nfs_nullcookie);
 2076         }
 2077         pos--;
 2078         dp = np->n_cookies.lh_first;
 2079         if (!dp) {
 2080                 if (add) {
 2081                         MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
 2082                                 M_NFSDIROFF, M_WAITOK);
 2083                         dp->ndm_eocookie = 0;
 2084                         LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
 2085                 } else
 2086                         return ((nfsuint64 *)0);
 2087         }
 2088         while (pos >= NFSNUMCOOKIES) {
 2089                 pos -= NFSNUMCOOKIES;
 2090                 if (dp->ndm_list.le_next) {
 2091                         if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
 2092                                 pos >= dp->ndm_eocookie)
 2093                                 return ((nfsuint64 *)0);
 2094                         dp = dp->ndm_list.le_next;
 2095                 } else if (add) {
 2096                         MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
 2097                                 M_NFSDIROFF, M_WAITOK);
 2098                         dp2->ndm_eocookie = 0;
 2099                         LIST_INSERT_AFTER(dp, dp2, ndm_list);
 2100                         dp = dp2;
 2101                 } else
 2102                         return ((nfsuint64 *)0);
 2103         }
 2104         if (pos >= dp->ndm_eocookie) {
 2105                 if (add)
 2106                         dp->ndm_eocookie = pos + 1;
 2107                 else
 2108                         return ((nfsuint64 *)0);
 2109         }
 2110         return (&dp->ndm_cookies[pos]);
 2111 }
 2112 
 2113 /*
 2114  * Invalidate cached directory information, except for the actual directory
 2115  * blocks (which are invalidated separately).
 2116  * Done mainly to avoid the use of stale offset cookies.
 2117  */
 2118 void
 2119 nfs_invaldir(vp)
 2120         register struct vnode *vp;
 2121 {
 2122         register struct nfsnode *np = VTONFS(vp);
 2123 
 2124 #ifdef DIAGNOSTIC
 2125         if (vp->v_type != VDIR)
 2126                 panic("nfs: invaldir not dir");
 2127 #endif
 2128         np->n_direofoffset = 0;
 2129         np->n_cookieverf.nfsuquad[0] = 0;
 2130         np->n_cookieverf.nfsuquad[1] = 0;
 2131         if (np->n_cookies.lh_first)
 2132                 np->n_cookies.lh_first->ndm_eocookie = 0;
 2133 }
 2134 
 2135 /*
 2136  * The write verifier has changed (probably due to a server reboot), so all
 2137  * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
 2138  * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
 2139  * and B_CLUSTEROK flags.  Once done the new write verifier can be set for the
 2140  * mount point.
 2141  *
 2142  * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 
 2143  * writes are not clusterable.
 2144  */
 2145 void
 2146 nfs_clearcommit(mp)
 2147         struct mount *mp;
 2148 {
 2149         register struct vnode *vp, *nvp;
 2150         register struct buf *bp, *nbp;
 2151         int s;
 2152 
 2153         s = splbio();
 2154 loop:
 2155         for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); vp; vp = nvp) {
 2156                 if (vp->v_mount != mp)  /* Paranoia */
 2157                         goto loop;
 2158                 nvp = TAILQ_NEXT(vp, v_nmntvnodes);
 2159                 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
 2160                         nbp = TAILQ_NEXT(bp, b_vnbufs);
 2161                         if (BUF_REFCNT(bp) == 0 &&
 2162                             (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
 2163                                 == (B_DELWRI | B_NEEDCOMMIT))
 2164                                 bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
 2165                 }
 2166         }
 2167         splx(s);
 2168 }
 2169 
 2170 #ifndef NFS_NOSERVER
 2171 /*
 2172  * Map errnos to NFS error numbers. For Version 3 also filter out error
 2173  * numbers not specified for the associated procedure.
 2174  */
 2175 int
 2176 nfsrv_errmap(nd, err)
 2177         struct nfsrv_descript *nd;
 2178         register int err;
 2179 {
 2180         register short *defaulterrp, *errp;
 2181 
 2182         if (nd->nd_flag & ND_NFSV3) {
 2183             if (nd->nd_procnum <= NFSPROC_COMMIT) {
 2184                 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
 2185                 while (*++errp) {
 2186                         if (*errp == err)
 2187                                 return (err);
 2188                         else if (*errp > err)
 2189                                 break;
 2190                 }
 2191                 return ((int)*defaulterrp);
 2192             } else
 2193                 return (err & 0xffff);
 2194         }
 2195         if (err <= ELAST)
 2196                 return ((int)nfsrv_v2errmap[err - 1]);
 2197         return (NFSERR_IO);
 2198 }
 2199 
 2200 int
 2201 nfsrv_object_create(vp)
 2202         struct vnode *vp;
 2203 {
 2204 
 2205         if (vp == NULL || vp->v_type != VREG)
 2206                 return (1);
 2207         return (vfs_object_create(vp, curproc,
 2208                                   curproc ? curproc->p_ucred : NULL));
 2209 }
 2210 
 2211 /*
 2212  * Sort the group list in increasing numerical order.
 2213  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
 2214  *  that used to be here.)
 2215  */
 2216 void
 2217 nfsrvw_sort(list, num)
 2218         register gid_t *list;
 2219         register int num;
 2220 {
 2221         register int i, j;
 2222         gid_t v;
 2223 
 2224         /* Insertion sort. */
 2225         for (i = 1; i < num; i++) {
 2226                 v = list[i];
 2227                 /* find correct slot for value v, moving others up */
 2228                 for (j = i; --j >= 0 && v < list[j];)
 2229                         list[j + 1] = list[j];
 2230                 list[j + 1] = v;
 2231         }
 2232 }
 2233 
 2234 /*
 2235  * copy credentials making sure that the result can be compared with bcmp().
 2236  */
 2237 void
 2238 nfsrv_setcred(incred, outcred)
 2239         register struct ucred *incred, *outcred;
 2240 {
 2241         register int i;
 2242 
 2243         bzero((caddr_t)outcred, sizeof (struct ucred));
 2244         outcred->cr_ref = 1;
 2245         outcred->cr_uid = incred->cr_uid;
 2246         outcred->cr_ngroups = incred->cr_ngroups;
 2247         for (i = 0; i < incred->cr_ngroups; i++)
 2248                 outcred->cr_groups[i] = incred->cr_groups[i];
 2249         nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
 2250 }
 2251 #endif /* NFS_NOSERVER */

Cache object: d105dc28ee8e7ac978ea4e4105538b36


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


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