nfs_subs.c revision 16365
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * This code is derived from software contributed to Berkeley by
61541Srgrimes * Rick Macklem at The University of Guelph.
71541Srgrimes *
81541Srgrimes * Redistribution and use in source and binary forms, with or without
91541Srgrimes * modification, are permitted provided that the following conditions
101541Srgrimes * are met:
111541Srgrimes * 1. Redistributions of source code must retain the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer.
131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer in the
151541Srgrimes *    documentation and/or other materials provided with the distribution.
161541Srgrimes * 3. All advertising materials mentioning features or use of this software
171541Srgrimes *    must display the following acknowledgement:
181541Srgrimes *	This product includes software developed by the University of
191541Srgrimes *	California, Berkeley and its contributors.
201541Srgrimes * 4. Neither the name of the University nor the names of its contributors
211541Srgrimes *    may be used to endorse or promote products derived from this software
221541Srgrimes *    without specific prior written permission.
231541Srgrimes *
241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341541Srgrimes * SUCH DAMAGE.
351541Srgrimes *
361541Srgrimes *	@(#)nfs_subs.c	8.3 (Berkeley) 1/4/94
3716365Sphk * $Id: nfs_subs.c,v 1.28 1996/01/19 03:58:52 dyson Exp $
381541Srgrimes */
391541Srgrimes
401541Srgrimes/*
411541Srgrimes * These functions support the macros and help fiddle mbuf chains for
421541Srgrimes * the nfs op functions. They do things like create the rpc header and
431541Srgrimes * copy data between mbuf chains and uio lists.
441541Srgrimes */
451541Srgrimes#include <sys/param.h>
461541Srgrimes#include <sys/proc.h>
471541Srgrimes#include <sys/systm.h>
481541Srgrimes#include <sys/kernel.h>
491541Srgrimes#include <sys/mount.h>
501541Srgrimes#include <sys/vnode.h>
511541Srgrimes#include <sys/namei.h>
521541Srgrimes#include <sys/mbuf.h>
531541Srgrimes#include <sys/socket.h>
541541Srgrimes#include <sys/stat.h>
559336Sdfr#include <sys/malloc.h>
562997Swollman#ifdef VFS_LKM
572997Swollman#include <sys/sysent.h>
582997Swollman#include <sys/syscall.h>
592997Swollman#endif
601541Srgrimes
613305Sphk#include <vm/vm.h>
6212662Sdg#include <vm/vm_param.h>
6312662Sdg#include <vm/vm_object.h>
6412662Sdg#include <vm/vm_extern.h>
659507Sdg#include <vm/vnode_pager.h>
663305Sphk
671541Srgrimes#include <nfs/rpcv2.h>
689336Sdfr#include <nfs/nfsproto.h>
691541Srgrimes#include <nfs/nfsnode.h>
701541Srgrimes#include <nfs/nfs.h>
711541Srgrimes#include <nfs/xdr_subs.h>
721541Srgrimes#include <nfs/nfsm_subs.h>
731541Srgrimes#include <nfs/nfsmount.h>
741541Srgrimes#include <nfs/nqnfs.h>
751541Srgrimes#include <nfs/nfsrtt.h>
761541Srgrimes
771541Srgrimes#include <miscfs/specfs/specdev.h>
781541Srgrimes
791541Srgrimes#include <netinet/in.h>
801541Srgrimes#ifdef ISO
811541Srgrimes#include <netiso/iso.h>
821541Srgrimes#endif
831541Srgrimes
841541Srgrimes/*
851541Srgrimes * Data items converted to xdr at startup, since they are constant
861541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps
871541Srgrimes */
881541Srgrimesu_long nfs_xdrneg1;
891541Srgrimesu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
909336Sdfr	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
911541Srgrimes	rpc_auth_kerb;
929336Sdfru_long nfs_prog, nqnfs_prog, nfs_true, nfs_false;
931541Srgrimes
941541Srgrimes/* And other global data */
951541Srgrimesstatic u_long nfs_xid = 0;
9612911Sphkstatic enum vtype nv2tov_type[8]= {
9712911Sphk	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON,  VNON
9812911Sphk};
9912911Sphkenum vtype nv3tov_type[8]= {
10012911Sphk	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
10112911Sphk};
10212911Sphk
1039336Sdfrint nfs_ticks;
1049336Sdfr
1059759Sbdestruct nfs_reqq nfs_reqq;
1069759Sbdestruct nfssvc_sockhead nfssvc_sockhead;
1079759Sbdeint nfssvc_sockhead_flag;
1089759Sbdestruct nfsd_head nfsd_head;
1099759Sbdeint nfsd_head_flag;
1109759Sbdestruct nfs_bufq nfs_bufq;
1119759Sbdestruct nqtimerhead nqtimerhead;
1129759Sbdestruct nqfhhashhead *nqfhhashtbl;
1139759Sbdeu_long nqfhhash;
1149759Sbde
11513416Sphk#ifndef NFS_NOSERVER
1169336Sdfr/*
1179336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers.
1189336Sdfr */
1199336Sdfrint nfsv3_procid[NFS_NPROCS] = {
1209336Sdfr	NFSPROC_NULL,
1219336Sdfr	NFSPROC_GETATTR,
1229336Sdfr	NFSPROC_SETATTR,
1239336Sdfr	NFSPROC_NOOP,
1249336Sdfr	NFSPROC_LOOKUP,
1259336Sdfr	NFSPROC_READLINK,
1269336Sdfr	NFSPROC_READ,
1279336Sdfr	NFSPROC_NOOP,
1289336Sdfr	NFSPROC_WRITE,
1299336Sdfr	NFSPROC_CREATE,
1309336Sdfr	NFSPROC_REMOVE,
1319336Sdfr	NFSPROC_RENAME,
1329336Sdfr	NFSPROC_LINK,
1339336Sdfr	NFSPROC_SYMLINK,
1349336Sdfr	NFSPROC_MKDIR,
1359336Sdfr	NFSPROC_RMDIR,
1369336Sdfr	NFSPROC_READDIR,
1379336Sdfr	NFSPROC_FSSTAT,
1389336Sdfr	NFSPROC_NOOP,
1399336Sdfr	NFSPROC_NOOP,
1409336Sdfr	NFSPROC_NOOP,
1419336Sdfr	NFSPROC_NOOP,
1429336Sdfr	NFSPROC_NOOP,
1439336Sdfr	NFSPROC_NOOP,
1449336Sdfr	NFSPROC_NOOP,
1459336Sdfr	NFSPROC_NOOP
1469336Sdfr};
1479336Sdfr
14813416Sphk#endif /* NFS_NOSERVER */
1499336Sdfr/*
1509336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers
1519336Sdfr */
1529336Sdfrint nfsv2_procid[NFS_NPROCS] = {
1539336Sdfr	NFSV2PROC_NULL,
1549336Sdfr	NFSV2PROC_GETATTR,
1559336Sdfr	NFSV2PROC_SETATTR,
1569336Sdfr	NFSV2PROC_LOOKUP,
1579336Sdfr	NFSV2PROC_NOOP,
1589336Sdfr	NFSV2PROC_READLINK,
1599336Sdfr	NFSV2PROC_READ,
1609336Sdfr	NFSV2PROC_WRITE,
1619336Sdfr	NFSV2PROC_CREATE,
1629336Sdfr	NFSV2PROC_MKDIR,
1639336Sdfr	NFSV2PROC_SYMLINK,
1649336Sdfr	NFSV2PROC_CREATE,
1659336Sdfr	NFSV2PROC_REMOVE,
1669336Sdfr	NFSV2PROC_RMDIR,
1679336Sdfr	NFSV2PROC_RENAME,
1689336Sdfr	NFSV2PROC_LINK,
1699336Sdfr	NFSV2PROC_READDIR,
1709336Sdfr	NFSV2PROC_NOOP,
1719336Sdfr	NFSV2PROC_STATFS,
1729336Sdfr	NFSV2PROC_NOOP,
1739336Sdfr	NFSV2PROC_NOOP,
1749336Sdfr	NFSV2PROC_NOOP,
1759336Sdfr	NFSV2PROC_NOOP,
1769336Sdfr	NFSV2PROC_NOOP,
1779336Sdfr	NFSV2PROC_NOOP,
1789336Sdfr	NFSV2PROC_NOOP,
1799336Sdfr};
1809336Sdfr
18113416Sphk#ifndef NFS_NOSERVER
1829336Sdfr/*
1839336Sdfr * Maps errno values to nfs error numbers.
1849336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in
1859336Sdfr * RFC 1094.
1869336Sdfr */
1879336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = {
1889336Sdfr  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1899336Sdfr  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1909336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
1919336Sdfr  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
1929336Sdfr  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1939336Sdfr  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
1949336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1959336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1969336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1979336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1989336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1999336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
2009336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
2019336Sdfr  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
2029336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
2039336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
2049336Sdfr  NFSERR_IO,
2059336Sdfr};
2069336Sdfr
2079336Sdfr/*
2089336Sdfr * Maps errno values to nfs error numbers.
2099336Sdfr * Although it is not obvious whether or not NFS clients really care if
2109336Sdfr * a returned error value is in the specified list for the procedure, the
2119336Sdfr * safest thing to do is filter them appropriately. For Version 2, the
2129336Sdfr * X/Open XNFS document is the only specification that defines error values
2139336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs),
2149336Sdfr * so I have decided to not do this for Version 2.
2159336Sdfr * The first entry is the default error return and the rest are the valid
2169336Sdfr * errors for that RPC in increasing numeric order.
2179336Sdfr */
2189336Sdfrstatic short nfsv3err_null[] = {
2199336Sdfr	0,
2209336Sdfr	0,
2219336Sdfr};
2229336Sdfr
2239336Sdfrstatic short nfsv3err_getattr[] = {
2249336Sdfr	NFSERR_IO,
2259336Sdfr	NFSERR_IO,
2269336Sdfr	NFSERR_STALE,
2279336Sdfr	NFSERR_BADHANDLE,
2289336Sdfr	NFSERR_SERVERFAULT,
2299336Sdfr	0,
2309336Sdfr};
2319336Sdfr
2329336Sdfrstatic short nfsv3err_setattr[] = {
2339336Sdfr	NFSERR_IO,
2349336Sdfr	NFSERR_PERM,
2359336Sdfr	NFSERR_IO,
2369336Sdfr	NFSERR_ACCES,
2379336Sdfr	NFSERR_INVAL,
2389336Sdfr	NFSERR_NOSPC,
2399336Sdfr	NFSERR_ROFS,
2409336Sdfr	NFSERR_DQUOT,
2419336Sdfr	NFSERR_STALE,
2429336Sdfr	NFSERR_BADHANDLE,
2439336Sdfr	NFSERR_NOT_SYNC,
2449336Sdfr	NFSERR_SERVERFAULT,
2459336Sdfr	0,
2469336Sdfr};
2479336Sdfr
2489336Sdfrstatic short nfsv3err_lookup[] = {
2499336Sdfr	NFSERR_IO,
2509336Sdfr	NFSERR_NOENT,
2519336Sdfr	NFSERR_IO,
2529336Sdfr	NFSERR_ACCES,
2539336Sdfr	NFSERR_NOTDIR,
2549336Sdfr	NFSERR_NAMETOL,
2559336Sdfr	NFSERR_STALE,
2569336Sdfr	NFSERR_BADHANDLE,
2579336Sdfr	NFSERR_SERVERFAULT,
2589336Sdfr	0,
2599336Sdfr};
2609336Sdfr
2619336Sdfrstatic short nfsv3err_access[] = {
2629336Sdfr	NFSERR_IO,
2639336Sdfr	NFSERR_IO,
2649336Sdfr	NFSERR_STALE,
2659336Sdfr	NFSERR_BADHANDLE,
2669336Sdfr	NFSERR_SERVERFAULT,
2679336Sdfr	0,
2689336Sdfr};
2699336Sdfr
2709336Sdfrstatic short nfsv3err_readlink[] = {
2719336Sdfr	NFSERR_IO,
2729336Sdfr	NFSERR_IO,
2739336Sdfr	NFSERR_ACCES,
2749336Sdfr	NFSERR_INVAL,
2759336Sdfr	NFSERR_STALE,
2769336Sdfr	NFSERR_BADHANDLE,
2779336Sdfr	NFSERR_NOTSUPP,
2789336Sdfr	NFSERR_SERVERFAULT,
2799336Sdfr	0,
2809336Sdfr};
2819336Sdfr
2829336Sdfrstatic short nfsv3err_read[] = {
2839336Sdfr	NFSERR_IO,
2849336Sdfr	NFSERR_IO,
2859336Sdfr	NFSERR_NXIO,
2869336Sdfr	NFSERR_ACCES,
2879336Sdfr	NFSERR_INVAL,
2889336Sdfr	NFSERR_STALE,
2899336Sdfr	NFSERR_BADHANDLE,
2909336Sdfr	NFSERR_SERVERFAULT,
2919336Sdfr	0,
2929336Sdfr};
2939336Sdfr
2949336Sdfrstatic short nfsv3err_write[] = {
2959336Sdfr	NFSERR_IO,
2969336Sdfr	NFSERR_IO,
2979336Sdfr	NFSERR_ACCES,
2989336Sdfr	NFSERR_INVAL,
2999336Sdfr	NFSERR_FBIG,
3009336Sdfr	NFSERR_NOSPC,
3019336Sdfr	NFSERR_ROFS,
3029336Sdfr	NFSERR_DQUOT,
3039336Sdfr	NFSERR_STALE,
3049336Sdfr	NFSERR_BADHANDLE,
3059336Sdfr	NFSERR_SERVERFAULT,
3069336Sdfr	0,
3079336Sdfr};
3089336Sdfr
3099336Sdfrstatic short nfsv3err_create[] = {
3109336Sdfr	NFSERR_IO,
3119336Sdfr	NFSERR_IO,
3129336Sdfr	NFSERR_ACCES,
3139336Sdfr	NFSERR_EXIST,
3149336Sdfr	NFSERR_NOTDIR,
3159336Sdfr	NFSERR_NOSPC,
3169336Sdfr	NFSERR_ROFS,
3179336Sdfr	NFSERR_NAMETOL,
3189336Sdfr	NFSERR_DQUOT,
3199336Sdfr	NFSERR_STALE,
3209336Sdfr	NFSERR_BADHANDLE,
3219336Sdfr	NFSERR_NOTSUPP,
3229336Sdfr	NFSERR_SERVERFAULT,
3239336Sdfr	0,
3249336Sdfr};
3259336Sdfr
3269336Sdfrstatic short nfsv3err_mkdir[] = {
3279336Sdfr	NFSERR_IO,
3289336Sdfr	NFSERR_IO,
3299336Sdfr	NFSERR_ACCES,
3309336Sdfr	NFSERR_EXIST,
3319336Sdfr	NFSERR_NOTDIR,
3329336Sdfr	NFSERR_NOSPC,
3339336Sdfr	NFSERR_ROFS,
3349336Sdfr	NFSERR_NAMETOL,
3359336Sdfr	NFSERR_DQUOT,
3369336Sdfr	NFSERR_STALE,
3379336Sdfr	NFSERR_BADHANDLE,
3389336Sdfr	NFSERR_NOTSUPP,
3399336Sdfr	NFSERR_SERVERFAULT,
3409336Sdfr	0,
3419336Sdfr};
3429336Sdfr
3439336Sdfrstatic short nfsv3err_symlink[] = {
3449336Sdfr	NFSERR_IO,
3459336Sdfr	NFSERR_IO,
3469336Sdfr	NFSERR_ACCES,
3479336Sdfr	NFSERR_EXIST,
3489336Sdfr	NFSERR_NOTDIR,
3499336Sdfr	NFSERR_NOSPC,
3509336Sdfr	NFSERR_ROFS,
3519336Sdfr	NFSERR_NAMETOL,
3529336Sdfr	NFSERR_DQUOT,
3539336Sdfr	NFSERR_STALE,
3549336Sdfr	NFSERR_BADHANDLE,
3559336Sdfr	NFSERR_NOTSUPP,
3569336Sdfr	NFSERR_SERVERFAULT,
3579336Sdfr	0,
3589336Sdfr};
3599336Sdfr
3609336Sdfrstatic short nfsv3err_mknod[] = {
3619336Sdfr	NFSERR_IO,
3629336Sdfr	NFSERR_IO,
3639336Sdfr	NFSERR_ACCES,
3649336Sdfr	NFSERR_EXIST,
3659336Sdfr	NFSERR_NOTDIR,
3669336Sdfr	NFSERR_NOSPC,
3679336Sdfr	NFSERR_ROFS,
3689336Sdfr	NFSERR_NAMETOL,
3699336Sdfr	NFSERR_DQUOT,
3709336Sdfr	NFSERR_STALE,
3719336Sdfr	NFSERR_BADHANDLE,
3729336Sdfr	NFSERR_NOTSUPP,
3739336Sdfr	NFSERR_SERVERFAULT,
3749336Sdfr	NFSERR_BADTYPE,
3759336Sdfr	0,
3769336Sdfr};
3779336Sdfr
3789336Sdfrstatic short nfsv3err_remove[] = {
3799336Sdfr	NFSERR_IO,
3809336Sdfr	NFSERR_NOENT,
3819336Sdfr	NFSERR_IO,
3829336Sdfr	NFSERR_ACCES,
3839336Sdfr	NFSERR_NOTDIR,
3849336Sdfr	NFSERR_ROFS,
3859336Sdfr	NFSERR_NAMETOL,
3869336Sdfr	NFSERR_STALE,
3879336Sdfr	NFSERR_BADHANDLE,
3889336Sdfr	NFSERR_SERVERFAULT,
3899336Sdfr	0,
3909336Sdfr};
3919336Sdfr
3929336Sdfrstatic short nfsv3err_rmdir[] = {
3939336Sdfr	NFSERR_IO,
3949336Sdfr	NFSERR_NOENT,
3959336Sdfr	NFSERR_IO,
3969336Sdfr	NFSERR_ACCES,
3979336Sdfr	NFSERR_EXIST,
3989336Sdfr	NFSERR_NOTDIR,
3999336Sdfr	NFSERR_INVAL,
4009336Sdfr	NFSERR_ROFS,
4019336Sdfr	NFSERR_NAMETOL,
4029336Sdfr	NFSERR_NOTEMPTY,
4039336Sdfr	NFSERR_STALE,
4049336Sdfr	NFSERR_BADHANDLE,
4059336Sdfr	NFSERR_NOTSUPP,
4069336Sdfr	NFSERR_SERVERFAULT,
4079336Sdfr	0,
4089336Sdfr};
4099336Sdfr
4109336Sdfrstatic short nfsv3err_rename[] = {
4119336Sdfr	NFSERR_IO,
4129336Sdfr	NFSERR_NOENT,
4139336Sdfr	NFSERR_IO,
4149336Sdfr	NFSERR_ACCES,
4159336Sdfr	NFSERR_EXIST,
4169336Sdfr	NFSERR_XDEV,
4179336Sdfr	NFSERR_NOTDIR,
4189336Sdfr	NFSERR_ISDIR,
4199336Sdfr	NFSERR_INVAL,
4209336Sdfr	NFSERR_NOSPC,
4219336Sdfr	NFSERR_ROFS,
4229336Sdfr	NFSERR_MLINK,
4239336Sdfr	NFSERR_NAMETOL,
4249336Sdfr	NFSERR_NOTEMPTY,
4259336Sdfr	NFSERR_DQUOT,
4269336Sdfr	NFSERR_STALE,
4279336Sdfr	NFSERR_BADHANDLE,
4289336Sdfr	NFSERR_NOTSUPP,
4299336Sdfr	NFSERR_SERVERFAULT,
4309336Sdfr	0,
4319336Sdfr};
4329336Sdfr
4339336Sdfrstatic short nfsv3err_link[] = {
4349336Sdfr	NFSERR_IO,
4359336Sdfr	NFSERR_IO,
4369336Sdfr	NFSERR_ACCES,
4379336Sdfr	NFSERR_EXIST,
4389336Sdfr	NFSERR_XDEV,
4399336Sdfr	NFSERR_NOTDIR,
4409336Sdfr	NFSERR_INVAL,
4419336Sdfr	NFSERR_NOSPC,
4429336Sdfr	NFSERR_ROFS,
4439336Sdfr	NFSERR_MLINK,
4449336Sdfr	NFSERR_NAMETOL,
4459336Sdfr	NFSERR_DQUOT,
4469336Sdfr	NFSERR_STALE,
4479336Sdfr	NFSERR_BADHANDLE,
4489336Sdfr	NFSERR_NOTSUPP,
4499336Sdfr	NFSERR_SERVERFAULT,
4509336Sdfr	0,
4519336Sdfr};
4529336Sdfr
4539336Sdfrstatic short nfsv3err_readdir[] = {
4549336Sdfr	NFSERR_IO,
4559336Sdfr	NFSERR_IO,
4569336Sdfr	NFSERR_ACCES,
4579336Sdfr	NFSERR_NOTDIR,
4589336Sdfr	NFSERR_STALE,
4599336Sdfr	NFSERR_BADHANDLE,
4609336Sdfr	NFSERR_BAD_COOKIE,
4619336Sdfr	NFSERR_TOOSMALL,
4629336Sdfr	NFSERR_SERVERFAULT,
4639336Sdfr	0,
4649336Sdfr};
4659336Sdfr
4669336Sdfrstatic short nfsv3err_readdirplus[] = {
4679336Sdfr	NFSERR_IO,
4689336Sdfr	NFSERR_IO,
4699336Sdfr	NFSERR_ACCES,
4709336Sdfr	NFSERR_NOTDIR,
4719336Sdfr	NFSERR_STALE,
4729336Sdfr	NFSERR_BADHANDLE,
4739336Sdfr	NFSERR_BAD_COOKIE,
4749336Sdfr	NFSERR_NOTSUPP,
4759336Sdfr	NFSERR_TOOSMALL,
4769336Sdfr	NFSERR_SERVERFAULT,
4779336Sdfr	0,
4789336Sdfr};
4799336Sdfr
4809336Sdfrstatic short nfsv3err_fsstat[] = {
4819336Sdfr	NFSERR_IO,
4829336Sdfr	NFSERR_IO,
4839336Sdfr	NFSERR_STALE,
4849336Sdfr	NFSERR_BADHANDLE,
4859336Sdfr	NFSERR_SERVERFAULT,
4869336Sdfr	0,
4879336Sdfr};
4889336Sdfr
4899336Sdfrstatic short nfsv3err_fsinfo[] = {
4909336Sdfr	NFSERR_STALE,
4919336Sdfr	NFSERR_STALE,
4929336Sdfr	NFSERR_BADHANDLE,
4939336Sdfr	NFSERR_SERVERFAULT,
4949336Sdfr	0,
4959336Sdfr};
4969336Sdfr
4979336Sdfrstatic short nfsv3err_pathconf[] = {
4989336Sdfr	NFSERR_STALE,
4999336Sdfr	NFSERR_STALE,
5009336Sdfr	NFSERR_BADHANDLE,
5019336Sdfr	NFSERR_SERVERFAULT,
5029336Sdfr	0,
5039336Sdfr};
5049336Sdfr
5059336Sdfrstatic short nfsv3err_commit[] = {
5069336Sdfr	NFSERR_IO,
5079336Sdfr	NFSERR_IO,
5089336Sdfr	NFSERR_STALE,
5099336Sdfr	NFSERR_BADHANDLE,
5109336Sdfr	NFSERR_SERVERFAULT,
5119336Sdfr	0,
5129336Sdfr};
5139336Sdfr
5149336Sdfrstatic short *nfsrv_v3errmap[] = {
5159336Sdfr	nfsv3err_null,
5169336Sdfr	nfsv3err_getattr,
5179336Sdfr	nfsv3err_setattr,
5189336Sdfr	nfsv3err_lookup,
5199336Sdfr	nfsv3err_access,
5209336Sdfr	nfsv3err_readlink,
5219336Sdfr	nfsv3err_read,
5229336Sdfr	nfsv3err_write,
5239336Sdfr	nfsv3err_create,
5249336Sdfr	nfsv3err_mkdir,
5259336Sdfr	nfsv3err_symlink,
5269336Sdfr	nfsv3err_mknod,
5279336Sdfr	nfsv3err_remove,
5289336Sdfr	nfsv3err_rmdir,
5299336Sdfr	nfsv3err_rename,
5309336Sdfr	nfsv3err_link,
5319336Sdfr	nfsv3err_readdir,
5329336Sdfr	nfsv3err_readdirplus,
5339336Sdfr	nfsv3err_fsstat,
5349336Sdfr	nfsv3err_fsinfo,
5359336Sdfr	nfsv3err_pathconf,
5369336Sdfr	nfsv3err_commit,
5379336Sdfr};
5389336Sdfr
53913416Sphk#endif /* NFS_NOSERVER */
54013416Sphk
5411541Srgrimesextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
5421541Srgrimesextern struct nfsrtt nfsrtt;
5431541Srgrimesextern time_t nqnfsstarttime;
5441541Srgrimesextern int nqsrv_clockskew;
5451541Srgrimesextern int nqsrv_writeslack;
5461541Srgrimesextern int nqsrv_maxlease;
5479336Sdfrextern struct nfsstats nfsstats;
5489336Sdfrextern int nqnfs_piggy[NFS_NPROCS];
5499336Sdfrextern nfstype nfsv2_type[9];
5509336Sdfrextern nfstype nfsv3_type[9];
5519336Sdfrextern struct nfsnodehashhead *nfsnodehashtbl;
5529336Sdfrextern u_long nfsnodehash;
5531541Srgrimes
5542997Swollman#ifdef VFS_LKM
5552997Swollmanstruct getfh_args;
5562997Swollmanextern int getfh(struct proc *, struct getfh_args *, int *);
5572997Swollmanstruct nfssvc_args;
5582997Swollmanextern int nfssvc(struct proc *, struct nfssvc_args *, int *);
5592997Swollman#endif
5602997Swollman
5613664SphkLIST_HEAD(nfsnodehashhead, nfsnode);
5623664Sphk
5631541Srgrimes/*
5641541Srgrimes * Create the header for an rpc request packet
5651541Srgrimes * The hsiz is the size of the rest of the nfs request header.
5661541Srgrimes * (just used to decide if a cluster is a good idea)
5671541Srgrimes */
5681541Srgrimesstruct mbuf *
5691541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp)
5701541Srgrimes	struct vnode *vp;
5711541Srgrimes	u_long procid;
5721541Srgrimes	int hsiz;
5731541Srgrimes	caddr_t *bposp;
5741541Srgrimes{
5751541Srgrimes	register struct mbuf *mb;
5761541Srgrimes	register u_long *tl;
5771541Srgrimes	register caddr_t bpos;
5781541Srgrimes	struct mbuf *mb2;
5791541Srgrimes	struct nfsmount *nmp;
5801541Srgrimes	int nqflag;
5811541Srgrimes
5821541Srgrimes	MGET(mb, M_WAIT, MT_DATA);
5831541Srgrimes	if (hsiz >= MINCLSIZE)
5841541Srgrimes		MCLGET(mb, M_WAIT);
5851541Srgrimes	mb->m_len = 0;
5861541Srgrimes	bpos = mtod(mb, caddr_t);
5878876Srgrimes
5881541Srgrimes	/*
5891541Srgrimes	 * For NQNFS, add lease request.
5901541Srgrimes	 */
5911541Srgrimes	if (vp) {
5921541Srgrimes		nmp = VFSTONFS(vp->v_mount);
5931541Srgrimes		if (nmp->nm_flag & NFSMNT_NQNFS) {
5941541Srgrimes			nqflag = NQNFS_NEEDLEASE(vp, procid);
5951541Srgrimes			if (nqflag) {
5961541Srgrimes				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
5971541Srgrimes				*tl++ = txdr_unsigned(nqflag);
5981541Srgrimes				*tl = txdr_unsigned(nmp->nm_leaseterm);
5991541Srgrimes			} else {
6001541Srgrimes				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
6011541Srgrimes				*tl = 0;
6021541Srgrimes			}
6031541Srgrimes		}
6041541Srgrimes	}
6051541Srgrimes	/* Finally, return values */
6061541Srgrimes	*bposp = bpos;
6071541Srgrimes	return (mb);
6081541Srgrimes}
6091541Srgrimes
6101541Srgrimes/*
6111541Srgrimes * Build the RPC header and fill in the authorization info.
6121541Srgrimes * The authorization string argument is only used when the credentials
6131541Srgrimes * come from outside of the kernel.
6141541Srgrimes * Returns the head of the mbuf list.
6151541Srgrimes */
6161541Srgrimesstruct mbuf *
6179336Sdfrnfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
6189336Sdfr	verf_str, mrest, mrest_len, mbp, xidp)
6191541Srgrimes	register struct ucred *cr;
6209336Sdfr	int nmflag;
6211541Srgrimes	int procid;
6221541Srgrimes	int auth_type;
6231541Srgrimes	int auth_len;
6241541Srgrimes	char *auth_str;
6259336Sdfr	int verf_len;
6269336Sdfr	char *verf_str;
6271541Srgrimes	struct mbuf *mrest;
6281541Srgrimes	int mrest_len;
6291541Srgrimes	struct mbuf **mbp;
6301541Srgrimes	u_long *xidp;
6311541Srgrimes{
6321541Srgrimes	register struct mbuf *mb;
6331541Srgrimes	register u_long *tl;
6341541Srgrimes	register caddr_t bpos;
6351541Srgrimes	register int i;
6361541Srgrimes	struct mbuf *mreq, *mb2;
6371541Srgrimes	int siz, grpsiz, authsiz;
6381541Srgrimes
6391541Srgrimes	authsiz = nfsm_rndup(auth_len);
6401541Srgrimes	MGETHDR(mb, M_WAIT, MT_DATA);
6419336Sdfr	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
6421541Srgrimes		MCLGET(mb, M_WAIT);
6439336Sdfr	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
6449336Sdfr		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
6451541Srgrimes	} else {
6469336Sdfr		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
6471541Srgrimes	}
6481541Srgrimes	mb->m_len = 0;
6491541Srgrimes	mreq = mb;
6501541Srgrimes	bpos = mtod(mb, caddr_t);
6511541Srgrimes
6521541Srgrimes	/*
6531541Srgrimes	 * First the RPC header.
6541541Srgrimes	 */
6559336Sdfr	nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
6561541Srgrimes	if (++nfs_xid == 0)
6571541Srgrimes		nfs_xid++;
6581541Srgrimes	*tl++ = *xidp = txdr_unsigned(nfs_xid);
6591541Srgrimes	*tl++ = rpc_call;
6601541Srgrimes	*tl++ = rpc_vers;
6619336Sdfr	if (nmflag & NFSMNT_NQNFS) {
6621541Srgrimes		*tl++ = txdr_unsigned(NQNFS_PROG);
6639336Sdfr		*tl++ = txdr_unsigned(NQNFS_VER3);
6641541Srgrimes	} else {
6651541Srgrimes		*tl++ = txdr_unsigned(NFS_PROG);
6669336Sdfr		if (nmflag & NFSMNT_NFSV3)
6679336Sdfr			*tl++ = txdr_unsigned(NFS_VER3);
6689336Sdfr		else
6699336Sdfr			*tl++ = txdr_unsigned(NFS_VER2);
6701541Srgrimes	}
6719336Sdfr	if (nmflag & NFSMNT_NFSV3)
6729336Sdfr		*tl++ = txdr_unsigned(procid);
6739336Sdfr	else
6749336Sdfr		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
6751541Srgrimes
6761541Srgrimes	/*
6771541Srgrimes	 * And then the authorization cred.
6781541Srgrimes	 */
6791541Srgrimes	*tl++ = txdr_unsigned(auth_type);
6801541Srgrimes	*tl = txdr_unsigned(authsiz);
6811541Srgrimes	switch (auth_type) {
6821541Srgrimes	case RPCAUTH_UNIX:
6831541Srgrimes		nfsm_build(tl, u_long *, auth_len);
6841541Srgrimes		*tl++ = 0;		/* stamp ?? */
6851541Srgrimes		*tl++ = 0;		/* NULL hostname */
6861541Srgrimes		*tl++ = txdr_unsigned(cr->cr_uid);
6871541Srgrimes		*tl++ = txdr_unsigned(cr->cr_groups[0]);
6881541Srgrimes		grpsiz = (auth_len >> 2) - 5;
6891541Srgrimes		*tl++ = txdr_unsigned(grpsiz);
6901541Srgrimes		for (i = 1; i <= grpsiz; i++)
6911541Srgrimes			*tl++ = txdr_unsigned(cr->cr_groups[i]);
6921541Srgrimes		break;
6939336Sdfr	case RPCAUTH_KERB4:
6941541Srgrimes		siz = auth_len;
6951541Srgrimes		while (siz > 0) {
6961541Srgrimes			if (M_TRAILINGSPACE(mb) == 0) {
6971541Srgrimes				MGET(mb2, M_WAIT, MT_DATA);
6981541Srgrimes				if (siz >= MINCLSIZE)
6991541Srgrimes					MCLGET(mb2, M_WAIT);
7001541Srgrimes				mb->m_next = mb2;
7011541Srgrimes				mb = mb2;
7021541Srgrimes				mb->m_len = 0;
7031541Srgrimes				bpos = mtod(mb, caddr_t);
7041541Srgrimes			}
7051541Srgrimes			i = min(siz, M_TRAILINGSPACE(mb));
7061541Srgrimes			bcopy(auth_str, bpos, i);
7071541Srgrimes			mb->m_len += i;
7081541Srgrimes			auth_str += i;
7091541Srgrimes			bpos += i;
7101541Srgrimes			siz -= i;
7111541Srgrimes		}
7121541Srgrimes		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
7131541Srgrimes			for (i = 0; i < siz; i++)
7141541Srgrimes				*bpos++ = '\0';
7151541Srgrimes			mb->m_len += siz;
7161541Srgrimes		}
7171541Srgrimes		break;
7181541Srgrimes	};
7199336Sdfr
7209336Sdfr	/*
7219336Sdfr	 * And the verifier...
7229336Sdfr	 */
7239336Sdfr	nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
7249336Sdfr	if (verf_str) {
7259336Sdfr		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
7269336Sdfr		*tl = txdr_unsigned(verf_len);
7279336Sdfr		siz = verf_len;
7289336Sdfr		while (siz > 0) {
7299336Sdfr			if (M_TRAILINGSPACE(mb) == 0) {
7309336Sdfr				MGET(mb2, M_WAIT, MT_DATA);
7319336Sdfr				if (siz >= MINCLSIZE)
7329336Sdfr					MCLGET(mb2, M_WAIT);
7339336Sdfr				mb->m_next = mb2;
7349336Sdfr				mb = mb2;
7359336Sdfr				mb->m_len = 0;
7369336Sdfr				bpos = mtod(mb, caddr_t);
7379336Sdfr			}
7389336Sdfr			i = min(siz, M_TRAILINGSPACE(mb));
7399336Sdfr			bcopy(verf_str, bpos, i);
7409336Sdfr			mb->m_len += i;
7419336Sdfr			verf_str += i;
7429336Sdfr			bpos += i;
7439336Sdfr			siz -= i;
7449336Sdfr		}
7459336Sdfr		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
7469336Sdfr			for (i = 0; i < siz; i++)
7479336Sdfr				*bpos++ = '\0';
7489336Sdfr			mb->m_len += siz;
7499336Sdfr		}
7509336Sdfr	} else {
7519336Sdfr		*tl++ = txdr_unsigned(RPCAUTH_NULL);
7529336Sdfr		*tl = 0;
7539336Sdfr	}
7541541Srgrimes	mb->m_next = mrest;
7559336Sdfr	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
7561541Srgrimes	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
7571541Srgrimes	*mbp = mb;
7581541Srgrimes	return (mreq);
7591541Srgrimes}
7601541Srgrimes
7611541Srgrimes/*
7621541Srgrimes * copies mbuf chain to the uio scatter/gather list
7631541Srgrimes */
7641549Srgrimesint
7651541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos)
7661541Srgrimes	struct mbuf **mrep;
7671541Srgrimes	register struct uio *uiop;
7681541Srgrimes	int siz;
7691541Srgrimes	caddr_t *dpos;
7701541Srgrimes{
7711541Srgrimes	register char *mbufcp, *uiocp;
7721541Srgrimes	register int xfer, left, len;
7731541Srgrimes	register struct mbuf *mp;
7741541Srgrimes	long uiosiz, rem;
7751541Srgrimes	int error = 0;
7761541Srgrimes
7771541Srgrimes	mp = *mrep;
7781541Srgrimes	mbufcp = *dpos;
7791541Srgrimes	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
7801541Srgrimes	rem = nfsm_rndup(siz)-siz;
7811541Srgrimes	while (siz > 0) {
7821541Srgrimes		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
7831541Srgrimes			return (EFBIG);
7841541Srgrimes		left = uiop->uio_iov->iov_len;
7851541Srgrimes		uiocp = uiop->uio_iov->iov_base;
7861541Srgrimes		if (left > siz)
7871541Srgrimes			left = siz;
7881541Srgrimes		uiosiz = left;
7891541Srgrimes		while (left > 0) {
7901541Srgrimes			while (len == 0) {
7911541Srgrimes				mp = mp->m_next;
7921541Srgrimes				if (mp == NULL)
7931541Srgrimes					return (EBADRPC);
7941541Srgrimes				mbufcp = mtod(mp, caddr_t);
7951541Srgrimes				len = mp->m_len;
7961541Srgrimes			}
7971541Srgrimes			xfer = (left > len) ? len : left;
7981541Srgrimes#ifdef notdef
7991541Srgrimes			/* Not Yet.. */
8001541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
8011541Srgrimes				(*(uiop->uio_iov->iov_op))
8021541Srgrimes				(mbufcp, uiocp, xfer);
8031541Srgrimes			else
8041541Srgrimes#endif
8051541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
8061541Srgrimes				bcopy(mbufcp, uiocp, xfer);
8071541Srgrimes			else
8081541Srgrimes				copyout(mbufcp, uiocp, xfer);
8091541Srgrimes			left -= xfer;
8101541Srgrimes			len -= xfer;
8111541Srgrimes			mbufcp += xfer;
8121541Srgrimes			uiocp += xfer;
8131541Srgrimes			uiop->uio_offset += xfer;
8141541Srgrimes			uiop->uio_resid -= xfer;
8151541Srgrimes		}
8161541Srgrimes		if (uiop->uio_iov->iov_len <= siz) {
8171541Srgrimes			uiop->uio_iovcnt--;
8181541Srgrimes			uiop->uio_iov++;
8191541Srgrimes		} else {
8201541Srgrimes			uiop->uio_iov->iov_base += uiosiz;
8211541Srgrimes			uiop->uio_iov->iov_len -= uiosiz;
8221541Srgrimes		}
8231541Srgrimes		siz -= uiosiz;
8241541Srgrimes	}
8251541Srgrimes	*dpos = mbufcp;
8261541Srgrimes	*mrep = mp;
8271541Srgrimes	if (rem > 0) {
8281541Srgrimes		if (len < rem)
8291541Srgrimes			error = nfs_adv(mrep, dpos, rem, len);
8301541Srgrimes		else
8311541Srgrimes			*dpos += rem;
8321541Srgrimes	}
8331541Srgrimes	return (error);
8341541Srgrimes}
8351541Srgrimes
8361541Srgrimes/*
8371541Srgrimes * copies a uio scatter/gather list to an mbuf chain...
8381541Srgrimes */
8391549Srgrimesint
8401541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos)
8411541Srgrimes	register struct uio *uiop;
8421541Srgrimes	struct mbuf **mq;
8431541Srgrimes	int siz;
8441541Srgrimes	caddr_t *bpos;
8451541Srgrimes{
8461541Srgrimes	register char *uiocp;
8471541Srgrimes	register struct mbuf *mp, *mp2;
8481541Srgrimes	register int xfer, left, mlen;
8491541Srgrimes	int uiosiz, clflg, rem;
8501541Srgrimes	char *cp;
8511541Srgrimes
8521541Srgrimes	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
8531541Srgrimes		clflg = 1;
8541541Srgrimes	else
8551541Srgrimes		clflg = 0;
8561541Srgrimes	rem = nfsm_rndup(siz)-siz;
8571541Srgrimes	mp = mp2 = *mq;
8581541Srgrimes	while (siz > 0) {
8591541Srgrimes		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
8601541Srgrimes			return (EINVAL);
8611541Srgrimes		left = uiop->uio_iov->iov_len;
8621541Srgrimes		uiocp = uiop->uio_iov->iov_base;
8631541Srgrimes		if (left > siz)
8641541Srgrimes			left = siz;
8651541Srgrimes		uiosiz = left;
8661541Srgrimes		while (left > 0) {
8671541Srgrimes			mlen = M_TRAILINGSPACE(mp);
8681541Srgrimes			if (mlen == 0) {
8691541Srgrimes				MGET(mp, M_WAIT, MT_DATA);
8701541Srgrimes				if (clflg)
8711541Srgrimes					MCLGET(mp, M_WAIT);
8721541Srgrimes				mp->m_len = 0;
8731541Srgrimes				mp2->m_next = mp;
8741541Srgrimes				mp2 = mp;
8751541Srgrimes				mlen = M_TRAILINGSPACE(mp);
8761541Srgrimes			}
8771541Srgrimes			xfer = (left > mlen) ? mlen : left;
8781541Srgrimes#ifdef notdef
8791541Srgrimes			/* Not Yet.. */
8801541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
8811541Srgrimes				(*(uiop->uio_iov->iov_op))
8821541Srgrimes				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
8831541Srgrimes			else
8841541Srgrimes#endif
8851541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
8861541Srgrimes				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
8871541Srgrimes			else
8881541Srgrimes				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
8891541Srgrimes			mp->m_len += xfer;
8901541Srgrimes			left -= xfer;
8911541Srgrimes			uiocp += xfer;
8921541Srgrimes			uiop->uio_offset += xfer;
8931541Srgrimes			uiop->uio_resid -= xfer;
8941541Srgrimes		}
8951541Srgrimes		if (uiop->uio_iov->iov_len <= siz) {
8961541Srgrimes			uiop->uio_iovcnt--;
8971541Srgrimes			uiop->uio_iov++;
8981541Srgrimes		} else {
8991541Srgrimes			uiop->uio_iov->iov_base += uiosiz;
9001541Srgrimes			uiop->uio_iov->iov_len -= uiosiz;
9011541Srgrimes		}
9021541Srgrimes		siz -= uiosiz;
9031541Srgrimes	}
9041541Srgrimes	if (rem > 0) {
9051541Srgrimes		if (rem > M_TRAILINGSPACE(mp)) {
9061541Srgrimes			MGET(mp, M_WAIT, MT_DATA);
9071541Srgrimes			mp->m_len = 0;
9081541Srgrimes			mp2->m_next = mp;
9091541Srgrimes		}
9101541Srgrimes		cp = mtod(mp, caddr_t)+mp->m_len;
9111541Srgrimes		for (left = 0; left < rem; left++)
9121541Srgrimes			*cp++ = '\0';
9131541Srgrimes		mp->m_len += rem;
9141541Srgrimes		*bpos = cp;
9151541Srgrimes	} else
9161541Srgrimes		*bpos = mtod(mp, caddr_t)+mp->m_len;
9171541Srgrimes	*mq = mp;
9181541Srgrimes	return (0);
9191541Srgrimes}
9201541Srgrimes
9211541Srgrimes/*
9221541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous
9231541Srgrimes * pointed to by returned val.
9241541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
9251541Srgrimes * cases. (The macros use the vars. dpos and dpos2)
9261541Srgrimes */
9271549Srgrimesint
9281541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2)
9291541Srgrimes	struct mbuf **mdp;
9301541Srgrimes	caddr_t *dposp;
9311541Srgrimes	int siz;
9321541Srgrimes	int left;
9331541Srgrimes	caddr_t *cp2;
9341541Srgrimes{
9351541Srgrimes	register struct mbuf *mp, *mp2;
9361541Srgrimes	register int siz2, xfer;
9371541Srgrimes	register caddr_t p;
9381541Srgrimes
9391541Srgrimes	mp = *mdp;
9401541Srgrimes	while (left == 0) {
9411541Srgrimes		*mdp = mp = mp->m_next;
9421541Srgrimes		if (mp == NULL)
9431541Srgrimes			return (EBADRPC);
9441541Srgrimes		left = mp->m_len;
9451541Srgrimes		*dposp = mtod(mp, caddr_t);
9461541Srgrimes	}
9471541Srgrimes	if (left >= siz) {
9481541Srgrimes		*cp2 = *dposp;
9491541Srgrimes		*dposp += siz;
9501541Srgrimes	} else if (mp->m_next == NULL) {
9511541Srgrimes		return (EBADRPC);
9521541Srgrimes	} else if (siz > MHLEN) {
9531541Srgrimes		panic("nfs S too big");
9541541Srgrimes	} else {
9551541Srgrimes		MGET(mp2, M_WAIT, MT_DATA);
9561541Srgrimes		mp2->m_next = mp->m_next;
9571541Srgrimes		mp->m_next = mp2;
9581541Srgrimes		mp->m_len -= left;
9591541Srgrimes		mp = mp2;
9601541Srgrimes		*cp2 = p = mtod(mp, caddr_t);
9611541Srgrimes		bcopy(*dposp, p, left);		/* Copy what was left */
9621541Srgrimes		siz2 = siz-left;
9631541Srgrimes		p += left;
9641541Srgrimes		mp2 = mp->m_next;
9651541Srgrimes		/* Loop around copying up the siz2 bytes */
9661541Srgrimes		while (siz2 > 0) {
9671541Srgrimes			if (mp2 == NULL)
9681541Srgrimes				return (EBADRPC);
9691541Srgrimes			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
9701541Srgrimes			if (xfer > 0) {
9711541Srgrimes				bcopy(mtod(mp2, caddr_t), p, xfer);
9721541Srgrimes				NFSMADV(mp2, xfer);
9731541Srgrimes				mp2->m_len -= xfer;
9741541Srgrimes				p += xfer;
9751541Srgrimes				siz2 -= xfer;
9761541Srgrimes			}
9771541Srgrimes			if (siz2 > 0)
9781541Srgrimes				mp2 = mp2->m_next;
9791541Srgrimes		}
9801541Srgrimes		mp->m_len = siz;
9811541Srgrimes		*mdp = mp2;
9821541Srgrimes		*dposp = mtod(mp2, caddr_t);
9831541Srgrimes	}
9841541Srgrimes	return (0);
9851541Srgrimes}
9861541Srgrimes
9871541Srgrimes/*
9881541Srgrimes * Advance the position in the mbuf chain.
9891541Srgrimes */
9901549Srgrimesint
9911541Srgrimesnfs_adv(mdp, dposp, offs, left)
9921541Srgrimes	struct mbuf **mdp;
9931541Srgrimes	caddr_t *dposp;
9941541Srgrimes	int offs;
9951541Srgrimes	int left;
9961541Srgrimes{
9971541Srgrimes	register struct mbuf *m;
9981541Srgrimes	register int s;
9991541Srgrimes
10001541Srgrimes	m = *mdp;
10011541Srgrimes	s = left;
10021541Srgrimes	while (s < offs) {
10031541Srgrimes		offs -= s;
10041541Srgrimes		m = m->m_next;
10051541Srgrimes		if (m == NULL)
10061541Srgrimes			return (EBADRPC);
10071541Srgrimes		s = m->m_len;
10081541Srgrimes	}
10091541Srgrimes	*mdp = m;
10101541Srgrimes	*dposp = mtod(m, caddr_t)+offs;
10111541Srgrimes	return (0);
10121541Srgrimes}
10131541Srgrimes
10141541Srgrimes/*
10151541Srgrimes * Copy a string into mbufs for the hard cases...
10161541Srgrimes */
10171549Srgrimesint
10181541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz)
10191541Srgrimes	struct mbuf **mb;
10201541Srgrimes	char **bpos;
10211541Srgrimes	char *cp;
10221541Srgrimes	long siz;
10231541Srgrimes{
10241549Srgrimes	register struct mbuf *m1 = 0, *m2;
10251541Srgrimes	long left, xfer, len, tlen;
10261541Srgrimes	u_long *tl;
10271541Srgrimes	int putsize;
10281541Srgrimes
10291541Srgrimes	putsize = 1;
10301541Srgrimes	m2 = *mb;
10311541Srgrimes	left = M_TRAILINGSPACE(m2);
10321541Srgrimes	if (left > 0) {
10331541Srgrimes		tl = ((u_long *)(*bpos));
10341541Srgrimes		*tl++ = txdr_unsigned(siz);
10351541Srgrimes		putsize = 0;
10361541Srgrimes		left -= NFSX_UNSIGNED;
10371541Srgrimes		m2->m_len += NFSX_UNSIGNED;
10381541Srgrimes		if (left > 0) {
10391541Srgrimes			bcopy(cp, (caddr_t) tl, left);
10401541Srgrimes			siz -= left;
10411541Srgrimes			cp += left;
10421541Srgrimes			m2->m_len += left;
10431541Srgrimes			left = 0;
10441541Srgrimes		}
10451541Srgrimes	}
10461541Srgrimes	/* Loop around adding mbufs */
10471541Srgrimes	while (siz > 0) {
10481541Srgrimes		MGET(m1, M_WAIT, MT_DATA);
10491541Srgrimes		if (siz > MLEN)
10501541Srgrimes			MCLGET(m1, M_WAIT);
10511541Srgrimes		m1->m_len = NFSMSIZ(m1);
10521541Srgrimes		m2->m_next = m1;
10531541Srgrimes		m2 = m1;
10541541Srgrimes		tl = mtod(m1, u_long *);
10551541Srgrimes		tlen = 0;
10561541Srgrimes		if (putsize) {
10571541Srgrimes			*tl++ = txdr_unsigned(siz);
10581541Srgrimes			m1->m_len -= NFSX_UNSIGNED;
10591541Srgrimes			tlen = NFSX_UNSIGNED;
10601541Srgrimes			putsize = 0;
10611541Srgrimes		}
10621541Srgrimes		if (siz < m1->m_len) {
10631541Srgrimes			len = nfsm_rndup(siz);
10641541Srgrimes			xfer = siz;
10651541Srgrimes			if (xfer < len)
10661541Srgrimes				*(tl+(xfer>>2)) = 0;
10671541Srgrimes		} else {
10681541Srgrimes			xfer = len = m1->m_len;
10691541Srgrimes		}
10701541Srgrimes		bcopy(cp, (caddr_t) tl, xfer);
10711541Srgrimes		m1->m_len = len+tlen;
10721541Srgrimes		siz -= xfer;
10731541Srgrimes		cp += xfer;
10741541Srgrimes	}
10751541Srgrimes	*mb = m1;
10761541Srgrimes	*bpos = mtod(m1, caddr_t)+m1->m_len;
10771541Srgrimes	return (0);
10781541Srgrimes}
10791541Srgrimes
10801541Srgrimes/*
10811541Srgrimes * Called once to initialize data structures...
10821541Srgrimes */
10831549Srgrimesint
10841541Srgrimesnfs_init()
10851541Srgrimes{
10861541Srgrimes	register int i;
10871541Srgrimes
10889336Sdfr	/*
10899336Sdfr	 * Check to see if major data structures haven't bloated.
10909336Sdfr	 */
10919336Sdfr	if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
10929336Sdfr		printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
10939336Sdfr		printf("Try reducing NFS_SMALLFH\n");
10949336Sdfr	}
10959336Sdfr	if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
10969336Sdfr		printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
10979336Sdfr		printf("Try reducing NFS_MUIDHASHSIZ\n");
10989336Sdfr	}
10999336Sdfr	if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
11009336Sdfr		printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
11019336Sdfr		printf("Try reducing NFS_UIDHASHSIZ\n");
11029336Sdfr	}
11039336Sdfr	if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
11049336Sdfr		printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
11059336Sdfr		printf("Try unionizing the nu_nickname and nu_flag fields\n");
11069336Sdfr	}
11071541Srgrimes	nfsrtt.pos = 0;
11081541Srgrimes	rpc_vers = txdr_unsigned(RPC_VER2);
11091541Srgrimes	rpc_call = txdr_unsigned(RPC_CALL);
11101541Srgrimes	rpc_reply = txdr_unsigned(RPC_REPLY);
11111541Srgrimes	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
11121541Srgrimes	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
11131541Srgrimes	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
11141541Srgrimes	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
11151541Srgrimes	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
11169336Sdfr	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
11171541Srgrimes	nfs_prog = txdr_unsigned(NFS_PROG);
11189336Sdfr	nqnfs_prog = txdr_unsigned(NQNFS_PROG);
11191541Srgrimes	nfs_true = txdr_unsigned(TRUE);
11201541Srgrimes	nfs_false = txdr_unsigned(FALSE);
11213664Sphk	nfs_xdrneg1 = txdr_unsigned(-1);
11229336Sdfr	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
11239336Sdfr	if (nfs_ticks < 1)
11249336Sdfr		nfs_ticks = 1;
11251541Srgrimes	/* Ensure async daemons disabled */
11261541Srgrimes	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
11271541Srgrimes		nfs_iodwant[i] = (struct proc *)0;
11281541Srgrimes	TAILQ_INIT(&nfs_bufq);
11291541Srgrimes	nfs_nhinit();			/* Init the nfsnode table */
113013416Sphk#ifndef NFS_NOSERVER
11311541Srgrimes	nfsrv_init(0);			/* Init server data structures */
11321541Srgrimes	nfsrv_initcache();		/* Init the server request cache */
113313416Sphk#endif
11341541Srgrimes
11351541Srgrimes	/*
11361541Srgrimes	 * Initialize the nqnfs server stuff.
11371541Srgrimes	 */
11381541Srgrimes	if (nqnfsstarttime == 0) {
11391541Srgrimes		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
11401541Srgrimes			+ nqsrv_clockskew + nqsrv_writeslack;
11411541Srgrimes		NQLOADNOVRAM(nqnfsstarttime);
11423664Sphk		CIRCLEQ_INIT(&nqtimerhead);
11433664Sphk		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
11441541Srgrimes	}
11451541Srgrimes
11461541Srgrimes	/*
11471541Srgrimes	 * Initialize reply list and start timer
11481541Srgrimes	 */
11493664Sphk	TAILQ_INIT(&nfs_reqq);
115016365Sphk
11513305Sphk	nfs_timer(0);
11521549Srgrimes
115316365Sphk
11549336Sdfr#ifdef __FreeBSD__
11552997Swollman	/*
11562997Swollman	 * Set up lease_check and lease_updatetime so that other parts
11572997Swollman	 * of the system can call us, if we are loadable.
11582997Swollman	 */
115913416Sphk#ifndef NFS_NOSERVER
11602997Swollman	lease_check = nfs_lease_check;
116113416Sphk#endif
11622997Swollman	lease_updatetime = nfs_lease_updatetime;
11632997Swollman	vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */
11642997Swollman#ifdef VFS_LKM
11652997Swollman	sysent[SYS_nfssvc].sy_narg = 2;
11662997Swollman	sysent[SYS_nfssvc].sy_call = nfssvc;
116713416Sphk#ifndef NFS_NOSERVER
11682997Swollman	sysent[SYS_getfh].sy_narg = 2;
11692997Swollman	sysent[SYS_getfh].sy_call = getfh;
11702997Swollman#endif
11719336Sdfr#endif
117213416Sphk#endif
11732997Swollman
11741549Srgrimes	return (0);
11751541Srgrimes}
11761541Srgrimes
11771541Srgrimes/*
11781541Srgrimes * Attribute cache routines.
11791541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes
11801541Srgrimes *	that are on the mbuf list
11811541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns
11821541Srgrimes *	error otherwise
11831541Srgrimes */
11841541Srgrimes
11851541Srgrimes/*
11861541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with
11871541Srgrimes * the values on the mbuf list and
11881541Srgrimes * Iff vap not NULL
11891541Srgrimes *    copy the attributes to *vaper
11901541Srgrimes */
11911549Srgrimesint
11921541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper)
11931541Srgrimes	struct vnode **vpp;
11941541Srgrimes	struct mbuf **mdp;
11951541Srgrimes	caddr_t *dposp;
11961541Srgrimes	struct vattr *vaper;
11971541Srgrimes{
11981541Srgrimes	register struct vnode *vp = *vpp;
11991541Srgrimes	register struct vattr *vap;
12009336Sdfr	register struct nfs_fattr *fp;
12013664Sphk	register struct nfsnode *np;
12023664Sphk	register struct nfsnodehashhead *nhpp;
12031541Srgrimes	register long t1;
12049336Sdfr	caddr_t cp2;
12059336Sdfr	int error = 0, rdev;
12061541Srgrimes	struct mbuf *md;
12071541Srgrimes	enum vtype vtyp;
12081541Srgrimes	u_short vmode;
12091541Srgrimes	struct timespec mtime;
12101541Srgrimes	struct vnode *nvp;
12119336Sdfr	int v3 = NFS_ISV3(vp);
12121541Srgrimes
12131541Srgrimes	md = *mdp;
12149336Sdfr	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
12159336Sdfr	if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))
12161541Srgrimes		return (error);
12179336Sdfr	fp = (struct nfs_fattr *)cp2;
12189336Sdfr	if (v3) {
12199336Sdfr		vtyp = nfsv3tov_type(fp->fa_type);
12209336Sdfr		vmode = fxdr_unsigned(u_short, fp->fa_mode);
12219336Sdfr		rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
12229336Sdfr			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
12239336Sdfr		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
12241541Srgrimes	} else {
12259336Sdfr		vtyp = nfsv2tov_type(fp->fa_type);
12269336Sdfr		vmode = fxdr_unsigned(u_short, fp->fa_mode);
12279336Sdfr		/*
12289336Sdfr		 * XXX
12299336Sdfr		 *
12309336Sdfr		 * The duplicate information returned in fa_type and fa_mode
12319336Sdfr		 * is an ambiguity in the NFS version 2 protocol.
12329336Sdfr		 *
12339336Sdfr		 * VREG should be taken literally as a regular file.  If a
12349336Sdfr		 * server intents to return some type information differently
12359336Sdfr		 * in the upper bits of the mode field (e.g. for sockets, or
12369336Sdfr		 * FIFOs), NFSv2 mandates fa_type to be VNON.  Anyway, we
12379336Sdfr		 * leave the examination of the mode bits even in the VREG
12389336Sdfr		 * case to avoid breakage for bogus servers, but we make sure
12399336Sdfr		 * that there are actually type bits set in the upper part of
12409336Sdfr		 * fa_mode (and failing that, trust the va_type field).
12419336Sdfr		 *
12429336Sdfr		 * NFSv3 cleared the issue, and requires fa_mode to not
12439336Sdfr		 * contain any type information (while also introduing sockets
12449336Sdfr		 * and FIFOs for fa_type).
12459336Sdfr		 */
12469336Sdfr		if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
12479336Sdfr			vtyp = IFTOVT(vmode);
12489336Sdfr		rdev = fxdr_unsigned(long, fp->fa2_rdev);
12499336Sdfr		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
12509336Sdfr
12519336Sdfr		/*
12529336Sdfr		 * Really ugly NFSv2 kludge.
12539336Sdfr		 */
12549336Sdfr		if (vtyp == VCHR && rdev == 0xffffffff)
12559336Sdfr			vtyp = VFIFO;
12561541Srgrimes	}
12579336Sdfr
12581541Srgrimes	/*
12591541Srgrimes	 * If v_type == VNON it is a new node, so fill in the v_type,
12608876Srgrimes	 * n_mtime fields. Check to see if it represents a special
12611541Srgrimes	 * device, and if so, check for a possible alias. Once the
12621541Srgrimes	 * correct vnode has been obtained, fill in the rest of the
12631541Srgrimes	 * information.
12641541Srgrimes	 */
12651541Srgrimes	np = VTONFS(vp);
126610219Sdfr	if (vp->v_type != vtyp) {
12679336Sdfr		/*
12689336Sdfr		 * If we had a lock and it turns out that the vnode
12699336Sdfr		 * is an object which we don't want to lock (e.g. VDIR)
12709336Sdfr		 * to avoid nasty hanging problems on a server crash,
12719336Sdfr		 * then release it here.
12729336Sdfr		 */
12739336Sdfr		if (vtyp != VREG && VOP_ISLOCKED(vp))
12749336Sdfr			VOP_UNLOCK(vp);
12759336Sdfr		vp->v_type = vtyp;
12761541Srgrimes		if (vp->v_type == VFIFO) {
12771541Srgrimes			vp->v_op = fifo_nfsv2nodeop_p;
12781541Srgrimes		}
12791541Srgrimes		if (vp->v_type == VCHR || vp->v_type == VBLK) {
12801541Srgrimes			vp->v_op = spec_nfsv2nodeop_p;
12813305Sphk			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
12823305Sphk			if (nvp) {
12831541Srgrimes				/*
12841541Srgrimes				 * Discard unneeded vnode, but save its nfsnode.
12851541Srgrimes				 */
12863664Sphk				LIST_REMOVE(np, n_hash);
12871541Srgrimes				nvp->v_data = vp->v_data;
12881541Srgrimes				vp->v_data = NULL;
12891541Srgrimes				vp->v_op = spec_vnodeop_p;
12901541Srgrimes				vrele(vp);
12911541Srgrimes				vgone(vp);
12921541Srgrimes				/*
12931541Srgrimes				 * Reinitialize aliased node.
12941541Srgrimes				 */
12951541Srgrimes				np->n_vnode = nvp;
12969336Sdfr				nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize));
12973664Sphk				LIST_INSERT_HEAD(nhpp, np, n_hash);
12981541Srgrimes				*vpp = vp = nvp;
12991541Srgrimes			}
13001541Srgrimes		}
13011541Srgrimes		np->n_mtime = mtime.ts_sec;
13021541Srgrimes	}
13031541Srgrimes	vap = &np->n_vattr;
13041541Srgrimes	vap->va_type = vtyp;
13051541Srgrimes	vap->va_mode = (vmode & 07777);
13061541Srgrimes	vap->va_rdev = (dev_t)rdev;
13071541Srgrimes	vap->va_mtime = mtime;
13081541Srgrimes	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
13099336Sdfr	if (v3) {
13109336Sdfr		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
13119336Sdfr		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
13129336Sdfr		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
13139336Sdfr		fxdr_hyper(&fp->fa3_size, &vap->va_size);
13149336Sdfr		vap->va_blocksize = NFS_FABLKSIZE;
13159336Sdfr		fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
13169336Sdfr		vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]);
13179336Sdfr		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
13189336Sdfr		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
13199336Sdfr		vap->va_flags = 0;
13209336Sdfr		vap->va_filerev = 0;
13211541Srgrimes	} else {
13229336Sdfr		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
13239336Sdfr		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
13249336Sdfr		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
13259336Sdfr		vap->va_size = fxdr_unsigned(u_long, fp->fa2_size);
13269336Sdfr		vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
13279336Sdfr		vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
13289336Sdfr		vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid);
13299336Sdfr		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
13301541Srgrimes		vap->va_flags = 0;
13319336Sdfr		vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec);
13329336Sdfr		vap->va_ctime.ts_nsec = 0;
13339336Sdfr		vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec);
13341541Srgrimes		vap->va_filerev = 0;
13351541Srgrimes	}
13361541Srgrimes	if (vap->va_size != np->n_size) {
13371541Srgrimes		if (vap->va_type == VREG) {
13381541Srgrimes			if (np->n_flag & NMODIFIED) {
13391541Srgrimes				if (vap->va_size < np->n_size)
13401541Srgrimes					vap->va_size = np->n_size;
13411541Srgrimes				else
13421541Srgrimes					np->n_size = vap->va_size;
13431541Srgrimes			} else
13441541Srgrimes				np->n_size = vap->va_size;
13451541Srgrimes			vnode_pager_setsize(vp, (u_long)np->n_size);
13461541Srgrimes		} else
13471541Srgrimes			np->n_size = vap->va_size;
13481541Srgrimes	}
13491541Srgrimes	np->n_attrstamp = time.tv_sec;
13501541Srgrimes	if (vaper != NULL) {
13511541Srgrimes		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
13521541Srgrimes		if (np->n_flag & NCHG) {
13539336Sdfr			if (np->n_flag & NACC)
13549336Sdfr				vaper->va_atime = np->n_atim;
13559336Sdfr			if (np->n_flag & NUPD)
13569336Sdfr				vaper->va_mtime = np->n_mtim;
13571541Srgrimes		}
13581541Srgrimes	}
13591541Srgrimes	return (0);
13601541Srgrimes}
13611541Srgrimes
13621541Srgrimes/*
13631541Srgrimes * Check the time stamp
13641541Srgrimes * If the cache is valid, copy contents to *vap and return 0
13651541Srgrimes * otherwise return an error
13661541Srgrimes */
13671549Srgrimesint
13681541Srgrimesnfs_getattrcache(vp, vaper)
13691541Srgrimes	register struct vnode *vp;
13701541Srgrimes	struct vattr *vaper;
13711541Srgrimes{
13721541Srgrimes	register struct nfsnode *np = VTONFS(vp);
13731541Srgrimes	register struct vattr *vap;
13741541Srgrimes
13759336Sdfr	if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
13761541Srgrimes		nfsstats.attrcache_misses++;
13771541Srgrimes		return (ENOENT);
13781541Srgrimes	}
13791541Srgrimes	nfsstats.attrcache_hits++;
13801541Srgrimes	vap = &np->n_vattr;
13811541Srgrimes	if (vap->va_size != np->n_size) {
13821541Srgrimes		if (vap->va_type == VREG) {
13831541Srgrimes			if (np->n_flag & NMODIFIED) {
13841541Srgrimes				if (vap->va_size < np->n_size)
13851541Srgrimes					vap->va_size = np->n_size;
13861541Srgrimes				else
13871541Srgrimes					np->n_size = vap->va_size;
13881541Srgrimes			} else
13891541Srgrimes				np->n_size = vap->va_size;
13901541Srgrimes			vnode_pager_setsize(vp, (u_long)np->n_size);
13911541Srgrimes		} else
13921541Srgrimes			np->n_size = vap->va_size;
13931541Srgrimes	}
13941541Srgrimes	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
13951541Srgrimes	if (np->n_flag & NCHG) {
13969336Sdfr		if (np->n_flag & NACC)
13979336Sdfr			vaper->va_atime = np->n_atim;
13989336Sdfr		if (np->n_flag & NUPD)
13999336Sdfr			vaper->va_mtime = np->n_mtim;
14001541Srgrimes	}
14011541Srgrimes	return (0);
14021541Srgrimes}
14031541Srgrimes
140413416Sphk#ifndef NFS_NOSERVER
14051541Srgrimes/*
14061541Srgrimes * Set up nameidata for a lookup() call and do it
14071541Srgrimes */
14081549Srgrimesint
14099336Sdfrnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
14101541Srgrimes	register struct nameidata *ndp;
14111541Srgrimes	fhandle_t *fhp;
14121541Srgrimes	int len;
14131541Srgrimes	struct nfssvc_sock *slp;
14141541Srgrimes	struct mbuf *nam;
14151541Srgrimes	struct mbuf **mdp;
14161541Srgrimes	caddr_t *dposp;
14179336Sdfr	struct vnode **retdirp;
14181541Srgrimes	struct proc *p;
14199336Sdfr	int kerbflag;
14201541Srgrimes{
14211541Srgrimes	register int i, rem;
14221541Srgrimes	register struct mbuf *md;
14231541Srgrimes	register char *fromcp, *tocp;
14241541Srgrimes	struct vnode *dp;
14251541Srgrimes	int error, rdonly;
14261541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
14271541Srgrimes
14289336Sdfr	*retdirp = (struct vnode *)0;
14291541Srgrimes	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
14301541Srgrimes	/*
14311541Srgrimes	 * Copy the name from the mbuf list to ndp->ni_pnbuf
14321541Srgrimes	 * and set the various ndp fields appropriately.
14331541Srgrimes	 */
14341541Srgrimes	fromcp = *dposp;
14351541Srgrimes	tocp = cnp->cn_pnbuf;
14361541Srgrimes	md = *mdp;
14371541Srgrimes	rem = mtod(md, caddr_t) + md->m_len - fromcp;
14381541Srgrimes	cnp->cn_hash = 0;
14391541Srgrimes	for (i = 0; i < len; i++) {
14401541Srgrimes		while (rem == 0) {
14411541Srgrimes			md = md->m_next;
14421541Srgrimes			if (md == NULL) {
14431541Srgrimes				error = EBADRPC;
14441541Srgrimes				goto out;
14451541Srgrimes			}
14461541Srgrimes			fromcp = mtod(md, caddr_t);
14471541Srgrimes			rem = md->m_len;
14481541Srgrimes		}
14491541Srgrimes		if (*fromcp == '\0' || *fromcp == '/') {
14509336Sdfr			error = EACCES;
14511541Srgrimes			goto out;
14521541Srgrimes		}
14531541Srgrimes		cnp->cn_hash += (unsigned char)*fromcp;
14541541Srgrimes		*tocp++ = *fromcp++;
14551541Srgrimes		rem--;
14561541Srgrimes	}
14571541Srgrimes	*tocp = '\0';
14581541Srgrimes	*mdp = md;
14591541Srgrimes	*dposp = fromcp;
14601541Srgrimes	len = nfsm_rndup(len)-len;
14611541Srgrimes	if (len > 0) {
14621541Srgrimes		if (rem >= len)
14631541Srgrimes			*dposp += len;
14649336Sdfr		else if (error = nfs_adv(mdp, dposp, len, rem))
14659336Sdfr			goto out;
14661541Srgrimes	}
14671541Srgrimes	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
14681541Srgrimes	cnp->cn_nameptr = cnp->cn_pnbuf;
14691541Srgrimes	/*
14701541Srgrimes	 * Extract and set starting directory.
14711541Srgrimes	 */
14729336Sdfr	if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
14739336Sdfr	    nam, &rdonly, kerbflag))
14741541Srgrimes		goto out;
14751541Srgrimes	if (dp->v_type != VDIR) {
14766417Sdg		nfsrv_vrele(dp);
14771541Srgrimes		error = ENOTDIR;
14781541Srgrimes		goto out;
14791541Srgrimes	}
14809336Sdfr	VREF(dp);
14819336Sdfr	*retdirp = dp;
14821541Srgrimes	ndp->ni_startdir = dp;
14831541Srgrimes	if (rdonly)
14841541Srgrimes		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
14851541Srgrimes	else
14861541Srgrimes		cnp->cn_flags |= NOCROSSMOUNT;
14871541Srgrimes	/*
14881541Srgrimes	 * And call lookup() to do the real work
14891541Srgrimes	 */
14901541Srgrimes	cnp->cn_proc = p;
14919336Sdfr	if (error = lookup(ndp))
14921541Srgrimes		goto out;
14931541Srgrimes	/*
14941541Srgrimes	 * Check for encountering a symbolic link
14951541Srgrimes	 */
14961541Srgrimes	if (cnp->cn_flags & ISSYMLINK) {
14971541Srgrimes		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
14981541Srgrimes			vput(ndp->ni_dvp);
14991541Srgrimes		else
15001541Srgrimes			vrele(ndp->ni_dvp);
15011541Srgrimes		vput(ndp->ni_vp);
15021541Srgrimes		ndp->ni_vp = NULL;
15031541Srgrimes		error = EINVAL;
15041541Srgrimes		goto out;
15051541Srgrimes	}
15068832Sdg
15078832Sdg	nfsrv_vmio(ndp->ni_vp);
15088832Sdg
15091541Srgrimes	/*
15101541Srgrimes	 * Check for saved name request
15111541Srgrimes	 */
15121541Srgrimes	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
15131541Srgrimes		cnp->cn_flags |= HASBUF;
15141541Srgrimes		return (0);
15151541Srgrimes	}
15161541Srgrimesout:
15171541Srgrimes	FREE(cnp->cn_pnbuf, M_NAMEI);
15181541Srgrimes	return (error);
15191541Srgrimes}
15201541Srgrimes
15211541Srgrimes/*
15221541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long
15231541Srgrimes * boundary and only trims off the back end
15241541Srgrimes */
15251541Srgrimesvoid
15261541Srgrimesnfsm_adj(mp, len, nul)
15271541Srgrimes	struct mbuf *mp;
15281541Srgrimes	register int len;
15291541Srgrimes	int nul;
15301541Srgrimes{
15311541Srgrimes	register struct mbuf *m;
15321541Srgrimes	register int count, i;
15331541Srgrimes	register char *cp;
15341541Srgrimes
15351541Srgrimes	/*
15361541Srgrimes	 * Trim from tail.  Scan the mbuf chain,
15371541Srgrimes	 * calculating its length and finding the last mbuf.
15381541Srgrimes	 * If the adjustment only affects this mbuf, then just
15391541Srgrimes	 * adjust and return.  Otherwise, rescan and truncate
15401541Srgrimes	 * after the remaining size.
15411541Srgrimes	 */
15421541Srgrimes	count = 0;
15431541Srgrimes	m = mp;
15441541Srgrimes	for (;;) {
15451541Srgrimes		count += m->m_len;
15461541Srgrimes		if (m->m_next == (struct mbuf *)0)
15471541Srgrimes			break;
15481541Srgrimes		m = m->m_next;
15491541Srgrimes	}
15501541Srgrimes	if (m->m_len > len) {
15511541Srgrimes		m->m_len -= len;
15521541Srgrimes		if (nul > 0) {
15531541Srgrimes			cp = mtod(m, caddr_t)+m->m_len-nul;
15541541Srgrimes			for (i = 0; i < nul; i++)
15551541Srgrimes				*cp++ = '\0';
15561541Srgrimes		}
15571541Srgrimes		return;
15581541Srgrimes	}
15591541Srgrimes	count -= len;
15601541Srgrimes	if (count < 0)
15611541Srgrimes		count = 0;
15621541Srgrimes	/*
15631541Srgrimes	 * Correct length for chain is "count".
15641541Srgrimes	 * Find the mbuf with last data, adjust its length,
15651541Srgrimes	 * and toss data from remaining mbufs on chain.
15661541Srgrimes	 */
15671541Srgrimes	for (m = mp; m; m = m->m_next) {
15681541Srgrimes		if (m->m_len >= count) {
15691541Srgrimes			m->m_len = count;
15701541Srgrimes			if (nul > 0) {
15711541Srgrimes				cp = mtod(m, caddr_t)+m->m_len-nul;
15721541Srgrimes				for (i = 0; i < nul; i++)
15731541Srgrimes					*cp++ = '\0';
15741541Srgrimes			}
15751541Srgrimes			break;
15761541Srgrimes		}
15771541Srgrimes		count -= m->m_len;
15781541Srgrimes	}
15793305Sphk	for (m = m->m_next;m;m = m->m_next)
15801541Srgrimes		m->m_len = 0;
15811541Srgrimes}
15821541Srgrimes
15831541Srgrimes/*
15849336Sdfr * Make these functions instead of macros, so that the kernel text size
15859336Sdfr * doesn't get too big...
15869336Sdfr */
15879336Sdfrvoid
15889336Sdfrnfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
15899336Sdfr	struct nfsrv_descript *nfsd;
15909336Sdfr	int before_ret;
15919336Sdfr	register struct vattr *before_vap;
15929336Sdfr	int after_ret;
15939336Sdfr	struct vattr *after_vap;
15949336Sdfr	struct mbuf **mbp;
15959336Sdfr	char **bposp;
15969336Sdfr{
15979336Sdfr	register struct mbuf *mb = *mbp, *mb2;
15989336Sdfr	register char *bpos = *bposp;
15999336Sdfr	register u_long *tl;
16009336Sdfr
16019336Sdfr	if (before_ret) {
16029336Sdfr		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
16039336Sdfr		*tl = nfs_false;
16049336Sdfr	} else {
16059336Sdfr		nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
16069336Sdfr		*tl++ = nfs_true;
16079336Sdfr		txdr_hyper(&(before_vap->va_size), tl);
16089336Sdfr		tl += 2;
16099336Sdfr		txdr_nfsv3time(&(before_vap->va_mtime), tl);
16109336Sdfr		tl += 2;
16119336Sdfr		txdr_nfsv3time(&(before_vap->va_ctime), tl);
16129336Sdfr	}
16139336Sdfr	*bposp = bpos;
16149336Sdfr	*mbp = mb;
16159336Sdfr	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
16169336Sdfr}
16179336Sdfr
16189336Sdfrvoid
16199336Sdfrnfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
16209336Sdfr	struct nfsrv_descript *nfsd;
16219336Sdfr	int after_ret;
16229336Sdfr	struct vattr *after_vap;
16239336Sdfr	struct mbuf **mbp;
16249336Sdfr	char **bposp;
16259336Sdfr{
16269336Sdfr	register struct mbuf *mb = *mbp, *mb2;
16279336Sdfr	register char *bpos = *bposp;
16289336Sdfr	register u_long *tl;
16299336Sdfr	register struct nfs_fattr *fp;
16309336Sdfr
16319336Sdfr	if (after_ret) {
16329336Sdfr		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
16339336Sdfr		*tl = nfs_false;
16349336Sdfr	} else {
16359336Sdfr		nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
16369336Sdfr		*tl++ = nfs_true;
16379336Sdfr		fp = (struct nfs_fattr *)tl;
16389336Sdfr		nfsm_srvfattr(nfsd, after_vap, fp);
16399336Sdfr	}
16409336Sdfr	*mbp = mb;
16419336Sdfr	*bposp = bpos;
16429336Sdfr}
16439336Sdfr
16449336Sdfrvoid
16459336Sdfrnfsm_srvfattr(nfsd, vap, fp)
16469336Sdfr	register struct nfsrv_descript *nfsd;
16479336Sdfr	register struct vattr *vap;
16489336Sdfr	register struct nfs_fattr *fp;
16499336Sdfr{
16509336Sdfr
16519336Sdfr	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
16529336Sdfr	fp->fa_uid = txdr_unsigned(vap->va_uid);
16539336Sdfr	fp->fa_gid = txdr_unsigned(vap->va_gid);
16549336Sdfr	if (nfsd->nd_flag & ND_NFSV3) {
16559336Sdfr		fp->fa_type = vtonfsv3_type(vap->va_type);
16569336Sdfr		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
16579336Sdfr		txdr_hyper(&vap->va_size, &fp->fa3_size);
16589336Sdfr		txdr_hyper(&vap->va_bytes, &fp->fa3_used);
16599336Sdfr		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
16609336Sdfr		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
16619336Sdfr		fp->fa3_fsid.nfsuquad[0] = 0;
16629336Sdfr		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
16639336Sdfr		fp->fa3_fileid.nfsuquad[0] = 0;
16649336Sdfr		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
16659336Sdfr		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
16669336Sdfr		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
16679336Sdfr		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
16689336Sdfr	} else {
16699336Sdfr		fp->fa_type = vtonfsv2_type(vap->va_type);
16709336Sdfr		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
16719336Sdfr		fp->fa2_size = txdr_unsigned(vap->va_size);
16729336Sdfr		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
16739336Sdfr		if (vap->va_type == VFIFO)
16749336Sdfr			fp->fa2_rdev = 0xffffffff;
16759336Sdfr		else
16769336Sdfr			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
16779336Sdfr		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
16789336Sdfr		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
16799336Sdfr		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
16809336Sdfr		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
16819336Sdfr		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
16829336Sdfr		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
16839336Sdfr	}
16849336Sdfr}
16859336Sdfr
16869336Sdfr/*
16871541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
16881541Srgrimes * 	- look up fsid in mount list (if not found ret error)
16891541Srgrimes *	- get vp and export rights by calling VFS_FHTOVP()
16901541Srgrimes *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
16911541Srgrimes *	- if not lockflag unlock it with VOP_UNLOCK()
16921541Srgrimes */
16931549Srgrimesint
16949336Sdfrnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
16951541Srgrimes	fhandle_t *fhp;
16961541Srgrimes	int lockflag;
16971541Srgrimes	struct vnode **vpp;
16981541Srgrimes	struct ucred *cred;
16991541Srgrimes	struct nfssvc_sock *slp;
17001541Srgrimes	struct mbuf *nam;
17011541Srgrimes	int *rdonlyp;
17029336Sdfr	int kerbflag;
17031541Srgrimes{
17041541Srgrimes	register struct mount *mp;
17051541Srgrimes	register int i;
17061541Srgrimes	struct ucred *credanon;
17071541Srgrimes	int error, exflags;
17081541Srgrimes
17091541Srgrimes	*vpp = (struct vnode *)0;
17103305Sphk	mp = getvfs(&fhp->fh_fsid);
17113305Sphk	if (!mp)
17121541Srgrimes		return (ESTALE);
17133305Sphk	error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
17143305Sphk	if (error)
17151541Srgrimes		return (error);
17161541Srgrimes	/*
17171541Srgrimes	 * Check/setup credentials.
17181541Srgrimes	 */
17191541Srgrimes	if (exflags & MNT_EXKERB) {
17209336Sdfr		if (!kerbflag) {
17211541Srgrimes			vput(*vpp);
17229336Sdfr			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
17231541Srgrimes		}
17249336Sdfr	} else if (kerbflag) {
17259336Sdfr		vput(*vpp);
17269336Sdfr		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
17271541Srgrimes	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
17281541Srgrimes		cred->cr_uid = credanon->cr_uid;
17291541Srgrimes		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
17301541Srgrimes			cred->cr_groups[i] = credanon->cr_groups[i];
17313664Sphk		cred->cr_ngroups = i;
17321541Srgrimes	}
17331541Srgrimes	if (exflags & MNT_EXRDONLY)
17341541Srgrimes		*rdonlyp = 1;
17351541Srgrimes	else
17361541Srgrimes		*rdonlyp = 0;
17377969Sdyson
17387969Sdyson	nfsrv_vmio(*vpp);
17397969Sdyson
17401541Srgrimes	if (!lockflag)
17411541Srgrimes		VOP_UNLOCK(*vpp);
17421541Srgrimes	return (0);
17431541Srgrimes}
17441541Srgrimes
174513416Sphk#endif /* NFS_NOSERVER */
17461541Srgrimes/*
17471541Srgrimes * This function compares two net addresses by family and returns TRUE
17481541Srgrimes * if they are the same host.
17491541Srgrimes * If there is any doubt, return FALSE.
17501541Srgrimes * The AF_INET family is handled as a special case so that address mbufs
17511541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes.
17521541Srgrimes */
17531549Srgrimesint
17541541Srgrimesnetaddr_match(family, haddr, nam)
17551541Srgrimes	int family;
17561541Srgrimes	union nethostaddr *haddr;
17571541Srgrimes	struct mbuf *nam;
17581541Srgrimes{
17591541Srgrimes	register struct sockaddr_in *inetaddr;
17601541Srgrimes
17611541Srgrimes	switch (family) {
17621541Srgrimes	case AF_INET:
17631541Srgrimes		inetaddr = mtod(nam, struct sockaddr_in *);
17641541Srgrimes		if (inetaddr->sin_family == AF_INET &&
17651541Srgrimes		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
17661541Srgrimes			return (1);
17671541Srgrimes		break;
17681541Srgrimes#ifdef ISO
17691541Srgrimes	case AF_ISO:
17701541Srgrimes	    {
17711541Srgrimes		register struct sockaddr_iso *isoaddr1, *isoaddr2;
17721541Srgrimes
17731541Srgrimes		isoaddr1 = mtod(nam, struct sockaddr_iso *);
17741541Srgrimes		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
17751541Srgrimes		if (isoaddr1->siso_family == AF_ISO &&
17761541Srgrimes		    isoaddr1->siso_nlen > 0 &&
17771541Srgrimes		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
17781541Srgrimes		    SAME_ISOADDR(isoaddr1, isoaddr2))
17791541Srgrimes			return (1);
17801541Srgrimes		break;
17811541Srgrimes	    }
17821541Srgrimes#endif	/* ISO */
17831541Srgrimes	default:
17841541Srgrimes		break;
17851541Srgrimes	};
17861541Srgrimes	return (0);
17871541Srgrimes}
17885455Sdg
17899336Sdfrstatic nfsuint64 nfs_nullcookie = { 0, 0 };
17909336Sdfr/*
17919336Sdfr * This function finds the directory cookie that corresponds to the
17929336Sdfr * logical byte offset given.
17939336Sdfr */
17949336Sdfrnfsuint64 *
17959336Sdfrnfs_getcookie(np, off, add)
17969336Sdfr	register struct nfsnode *np;
17979336Sdfr	off_t off;
17989336Sdfr	int add;
17999336Sdfr{
18009336Sdfr	register struct nfsdmap *dp, *dp2;
18019336Sdfr	register int pos;
18029336Sdfr
18039336Sdfr	pos = off / NFS_DIRBLKSIZ;
18049336Sdfr	if (pos == 0) {
18059336Sdfr#ifdef DIAGNOSTIC
18069336Sdfr		if (add)
18079336Sdfr			panic("nfs getcookie add at 0");
18089336Sdfr#endif
18099336Sdfr		return (&nfs_nullcookie);
18109336Sdfr	}
18119336Sdfr	pos--;
18129336Sdfr	dp = np->n_cookies.lh_first;
18139336Sdfr	if (!dp) {
18149336Sdfr		if (add) {
18159336Sdfr			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
18169336Sdfr				M_NFSDIROFF, M_WAITOK);
18179336Sdfr			dp->ndm_eocookie = 0;
18189336Sdfr			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
18199336Sdfr		} else
18209336Sdfr			return ((nfsuint64 *)0);
18219336Sdfr	}
18229336Sdfr	while (pos >= NFSNUMCOOKIES) {
18239336Sdfr		pos -= NFSNUMCOOKIES;
18249336Sdfr		if (dp->ndm_list.le_next) {
18259336Sdfr			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
18269336Sdfr				pos >= dp->ndm_eocookie)
18279336Sdfr				return ((nfsuint64 *)0);
18289336Sdfr			dp = dp->ndm_list.le_next;
18299336Sdfr		} else if (add) {
18309336Sdfr			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
18319336Sdfr				M_NFSDIROFF, M_WAITOK);
18329336Sdfr			dp2->ndm_eocookie = 0;
18339336Sdfr			LIST_INSERT_AFTER(dp, dp2, ndm_list);
18349336Sdfr			dp = dp2;
18359336Sdfr		} else
18369336Sdfr			return ((nfsuint64 *)0);
18379336Sdfr	}
18389336Sdfr	if (pos >= dp->ndm_eocookie) {
18399336Sdfr		if (add)
18409336Sdfr			dp->ndm_eocookie = pos + 1;
18419336Sdfr		else
18429336Sdfr			return ((nfsuint64 *)0);
18439336Sdfr	}
18449336Sdfr	return (&dp->ndm_cookies[pos]);
18459336Sdfr}
18469336Sdfr
18479336Sdfr/*
18489336Sdfr * Invalidate cached directory information, except for the actual directory
18499336Sdfr * blocks (which are invalidated separately).
18509336Sdfr * Done mainly to avoid the use of stale offset cookies.
18519336Sdfr */
18529336Sdfrvoid
18539336Sdfrnfs_invaldir(vp)
18549336Sdfr	register struct vnode *vp;
18559336Sdfr{
18569336Sdfr	register struct nfsnode *np = VTONFS(vp);
18579336Sdfr
18589336Sdfr#ifdef DIAGNOSTIC
18599336Sdfr	if (vp->v_type != VDIR)
18609336Sdfr		panic("nfs: invaldir not dir");
18619336Sdfr#endif
18629336Sdfr	np->n_direofoffset = 0;
18639336Sdfr	np->n_cookieverf.nfsuquad[0] = 0;
18649336Sdfr	np->n_cookieverf.nfsuquad[1] = 0;
18659336Sdfr	if (np->n_cookies.lh_first)
18669336Sdfr		np->n_cookies.lh_first->ndm_eocookie = 0;
18679336Sdfr}
18689336Sdfr
18699336Sdfr/*
18709336Sdfr * The write verifier has changed (probably due to a server reboot), so all
18719336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
18729336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
18739336Sdfr * flag. Once done the new write verifier can be set for the mount point.
18749336Sdfr */
18759336Sdfrvoid
18769336Sdfrnfs_clearcommit(mp)
18779336Sdfr	struct mount *mp;
18789336Sdfr{
18799336Sdfr	register struct vnode *vp, *nvp;
18809336Sdfr	register struct buf *bp, *nbp;
18819336Sdfr	int s;
18829336Sdfr
18839336Sdfr	s = splbio();
18849336Sdfrloop:
18859336Sdfr	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
18869336Sdfr		if (vp->v_mount != mp)	/* Paranoia */
18879336Sdfr			goto loop;
18889336Sdfr		nvp = vp->v_mntvnodes.le_next;
18899336Sdfr		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
18909336Sdfr			nbp = bp->b_vnbufs.le_next;
18919336Sdfr			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
18929336Sdfr				== (B_DELWRI | B_NEEDCOMMIT))
18939336Sdfr				bp->b_flags &= ~B_NEEDCOMMIT;
18949336Sdfr		}
18959336Sdfr	}
18969336Sdfr	splx(s);
18979336Sdfr}
18989336Sdfr
189913416Sphk#ifndef NFS_NOSERVER
19009336Sdfr/*
19019336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error
19029336Sdfr * numbers not specified for the associated procedure.
19039336Sdfr */
19045455Sdgint
19059336Sdfrnfsrv_errmap(nd, err)
19069336Sdfr	struct nfsrv_descript *nd;
19079336Sdfr	register int err;
19089336Sdfr{
19099336Sdfr	register short *defaulterrp, *errp;
19109336Sdfr
19119336Sdfr	if (nd->nd_flag & ND_NFSV3) {
19129336Sdfr	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
19139336Sdfr		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
19149336Sdfr		while (*++errp) {
19159336Sdfr			if (*errp == err)
19169336Sdfr				return (err);
19179336Sdfr			else if (*errp > err)
19189336Sdfr				break;
19199336Sdfr		}
19209336Sdfr		return ((int)*defaulterrp);
19219336Sdfr	    } else
19229336Sdfr		return (err & 0xffff);
19239336Sdfr	}
19249336Sdfr	if (err <= ELAST)
19259336Sdfr		return ((int)nfsrv_v2errmap[err - 1]);
19269336Sdfr	return (NFSERR_IO);
19279336Sdfr}
19289336Sdfr
19299336Sdfrint
19309356Sdgnfsrv_vmio(struct vnode *vp) {
19315455Sdg	vm_object_t object;
19325455Sdg
19339356Sdg	if ((vp == NULL) || (vp->v_type != VREG))
19345455Sdg		return 1;
19355455Sdg
19365455Sdgretry:
19379356Sdg	if ((vp->v_flag & VVMIO) == 0) {
19389456Sdg		struct vattr vat;
19399456Sdg		struct proc *p = curproc;
19409456Sdg
19419456Sdg		if (VOP_GETATTR(vp, &vat, p->p_ucred, p) != 0)
19429456Sdg			panic("nfsrv_vmio: VOP_GETATTR failed");
19439456Sdg
194413490Sdyson		(void) vnode_pager_alloc(vp, OFF_TO_IDX(round_page(vat.va_size)), 0, 0);
19459456Sdg
19465455Sdg		vp->v_flag |= VVMIO;
19475455Sdg	} else {
19489356Sdg		if ((object = vp->v_object) &&
19495455Sdg			(object->flags & OBJ_DEAD)) {
19509356Sdg			tsleep(object, PVM, "nfdead", 0);
19515455Sdg			goto retry;
19525455Sdg		}
19539356Sdg		if (!object)
19545455Sdg			panic("nfsrv_vmio: VMIO object missing");
19559507Sdg		vm_object_reference(object);
19565455Sdg	}
19575455Sdg	return 0;
19585455Sdg}
19595455Sdgint
19609356Sdgnfsrv_vput(struct vnode *vp) {
19619356Sdg	if ((vp->v_flag & VVMIO) && vp->v_object) {
19629356Sdg		vput(vp);
19639356Sdg		vm_object_deallocate(vp->v_object);
19646210Sdg	} else {
19659356Sdg		vput(vp);
19665455Sdg	}
19675455Sdg	return 0;
19685455Sdg}
19695455Sdgint
19709356Sdgnfsrv_vrele(struct vnode *vp) {
19719356Sdg	if ((vp->v_flag & VVMIO) && vp->v_object) {
19729356Sdg		vrele(vp);
19739356Sdg		vm_object_deallocate(vp->v_object);
19746210Sdg	} else {
19759356Sdg		vrele(vp);
19765455Sdg	}
19775455Sdg	return 0;
19785455Sdg}
197913416Sphk#endif /* NFS_NOSERVER */
1980