nfs_srvsubs.c revision 31886
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
3731886Sbde * $Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk 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>
4631886Sbde#include <sys/buf.h>
471541Srgrimes#include <sys/proc.h>
481541Srgrimes#include <sys/systm.h>
491541Srgrimes#include <sys/kernel.h>
501541Srgrimes#include <sys/mount.h>
511541Srgrimes#include <sys/vnode.h>
521541Srgrimes#include <sys/namei.h>
531541Srgrimes#include <sys/mbuf.h>
541541Srgrimes#include <sys/socket.h>
551541Srgrimes#include <sys/stat.h>
569336Sdfr#include <sys/malloc.h>
572997Swollman#include <sys/sysent.h>
582997Swollman#include <sys/syscall.h>
591541Srgrimes
603305Sphk#include <vm/vm.h>
6112662Sdg#include <vm/vm_object.h>
6212662Sdg#include <vm/vm_extern.h>
633305Sphk
641541Srgrimes#include <nfs/rpcv2.h>
659336Sdfr#include <nfs/nfsproto.h>
6630808Sbde#include <nfs/nfs.h>
671541Srgrimes#include <nfs/nfsnode.h>
681541Srgrimes#include <nfs/xdr_subs.h>
691541Srgrimes#include <nfs/nfsm_subs.h>
701541Srgrimes#include <nfs/nfsmount.h>
711541Srgrimes#include <nfs/nqnfs.h>
721541Srgrimes#include <nfs/nfsrtt.h>
731541Srgrimes
741541Srgrimes#include <miscfs/specfs/specdev.h>
751541Srgrimes
761541Srgrimes#include <netinet/in.h>
771541Srgrimes#ifdef ISO
781541Srgrimes#include <netiso/iso.h>
791541Srgrimes#endif
801541Srgrimes
811541Srgrimes/*
821541Srgrimes * Data items converted to xdr at startup, since they are constant
831541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps
841541Srgrimes */
851541Srgrimesu_long nfs_xdrneg1;
861541Srgrimesu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
879336Sdfr	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
881541Srgrimes	rpc_auth_kerb;
899336Sdfru_long nfs_prog, nqnfs_prog, nfs_true, nfs_false;
901541Srgrimes
911541Srgrimes/* And other global data */
921541Srgrimesstatic u_long nfs_xid = 0;
9312911Sphkstatic enum vtype nv2tov_type[8]= {
9412911Sphk	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON,  VNON
9512911Sphk};
9612911Sphkenum vtype nv3tov_type[8]= {
9712911Sphk	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
9812911Sphk};
9912911Sphk
10022521Sdysonint nfs_mount_type;
1019336Sdfrint nfs_ticks;
1029336Sdfr
1039759Sbdestruct nfs_reqq nfs_reqq;
1049759Sbdestruct nfssvc_sockhead nfssvc_sockhead;
1059759Sbdeint nfssvc_sockhead_flag;
1069759Sbdestruct nfsd_head nfsd_head;
1079759Sbdeint nfsd_head_flag;
1089759Sbdestruct nfs_bufq nfs_bufq;
1099759Sbdestruct nqtimerhead nqtimerhead;
1109759Sbdestruct nqfhhashhead *nqfhhashtbl;
1119759Sbdeu_long nqfhhash;
1129759Sbde
11313416Sphk#ifndef NFS_NOSERVER
1149336Sdfr/*
1159336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers.
1169336Sdfr */
1179336Sdfrint nfsv3_procid[NFS_NPROCS] = {
1189336Sdfr	NFSPROC_NULL,
1199336Sdfr	NFSPROC_GETATTR,
1209336Sdfr	NFSPROC_SETATTR,
1219336Sdfr	NFSPROC_NOOP,
1229336Sdfr	NFSPROC_LOOKUP,
1239336Sdfr	NFSPROC_READLINK,
1249336Sdfr	NFSPROC_READ,
1259336Sdfr	NFSPROC_NOOP,
1269336Sdfr	NFSPROC_WRITE,
1279336Sdfr	NFSPROC_CREATE,
1289336Sdfr	NFSPROC_REMOVE,
1299336Sdfr	NFSPROC_RENAME,
1309336Sdfr	NFSPROC_LINK,
1319336Sdfr	NFSPROC_SYMLINK,
1329336Sdfr	NFSPROC_MKDIR,
1339336Sdfr	NFSPROC_RMDIR,
1349336Sdfr	NFSPROC_READDIR,
1359336Sdfr	NFSPROC_FSSTAT,
1369336Sdfr	NFSPROC_NOOP,
1379336Sdfr	NFSPROC_NOOP,
1389336Sdfr	NFSPROC_NOOP,
1399336Sdfr	NFSPROC_NOOP,
1409336Sdfr	NFSPROC_NOOP,
1419336Sdfr	NFSPROC_NOOP,
1429336Sdfr	NFSPROC_NOOP,
1439336Sdfr	NFSPROC_NOOP
1449336Sdfr};
1459336Sdfr
14613416Sphk#endif /* NFS_NOSERVER */
1479336Sdfr/*
1489336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers
1499336Sdfr */
1509336Sdfrint nfsv2_procid[NFS_NPROCS] = {
1519336Sdfr	NFSV2PROC_NULL,
1529336Sdfr	NFSV2PROC_GETATTR,
1539336Sdfr	NFSV2PROC_SETATTR,
1549336Sdfr	NFSV2PROC_LOOKUP,
1559336Sdfr	NFSV2PROC_NOOP,
1569336Sdfr	NFSV2PROC_READLINK,
1579336Sdfr	NFSV2PROC_READ,
1589336Sdfr	NFSV2PROC_WRITE,
1599336Sdfr	NFSV2PROC_CREATE,
1609336Sdfr	NFSV2PROC_MKDIR,
1619336Sdfr	NFSV2PROC_SYMLINK,
1629336Sdfr	NFSV2PROC_CREATE,
1639336Sdfr	NFSV2PROC_REMOVE,
1649336Sdfr	NFSV2PROC_RMDIR,
1659336Sdfr	NFSV2PROC_RENAME,
1669336Sdfr	NFSV2PROC_LINK,
1679336Sdfr	NFSV2PROC_READDIR,
1689336Sdfr	NFSV2PROC_NOOP,
1699336Sdfr	NFSV2PROC_STATFS,
1709336Sdfr	NFSV2PROC_NOOP,
1719336Sdfr	NFSV2PROC_NOOP,
1729336Sdfr	NFSV2PROC_NOOP,
1739336Sdfr	NFSV2PROC_NOOP,
1749336Sdfr	NFSV2PROC_NOOP,
1759336Sdfr	NFSV2PROC_NOOP,
1769336Sdfr	NFSV2PROC_NOOP,
1779336Sdfr};
1789336Sdfr
17913416Sphk#ifndef NFS_NOSERVER
1809336Sdfr/*
1819336Sdfr * Maps errno values to nfs error numbers.
1829336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in
1839336Sdfr * RFC 1094.
1849336Sdfr */
1859336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = {
1869336Sdfr  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1879336Sdfr  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1889336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
1899336Sdfr  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
1909336Sdfr  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1919336Sdfr  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
1929336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1939336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
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_NAMETOL,	NFSERR_IO,	NFSERR_IO,
1999336Sdfr  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
2009336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
2019336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
2029336Sdfr  NFSERR_IO,
2039336Sdfr};
2049336Sdfr
2059336Sdfr/*
2069336Sdfr * Maps errno values to nfs error numbers.
2079336Sdfr * Although it is not obvious whether or not NFS clients really care if
2089336Sdfr * a returned error value is in the specified list for the procedure, the
2099336Sdfr * safest thing to do is filter them appropriately. For Version 2, the
2109336Sdfr * X/Open XNFS document is the only specification that defines error values
2119336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs),
2129336Sdfr * so I have decided to not do this for Version 2.
2139336Sdfr * The first entry is the default error return and the rest are the valid
2149336Sdfr * errors for that RPC in increasing numeric order.
2159336Sdfr */
2169336Sdfrstatic short nfsv3err_null[] = {
2179336Sdfr	0,
2189336Sdfr	0,
2199336Sdfr};
2209336Sdfr
2219336Sdfrstatic short nfsv3err_getattr[] = {
2229336Sdfr	NFSERR_IO,
2239336Sdfr	NFSERR_IO,
2249336Sdfr	NFSERR_STALE,
2259336Sdfr	NFSERR_BADHANDLE,
2269336Sdfr	NFSERR_SERVERFAULT,
2279336Sdfr	0,
2289336Sdfr};
2299336Sdfr
2309336Sdfrstatic short nfsv3err_setattr[] = {
2319336Sdfr	NFSERR_IO,
2329336Sdfr	NFSERR_PERM,
2339336Sdfr	NFSERR_IO,
2349336Sdfr	NFSERR_ACCES,
2359336Sdfr	NFSERR_INVAL,
2369336Sdfr	NFSERR_NOSPC,
2379336Sdfr	NFSERR_ROFS,
2389336Sdfr	NFSERR_DQUOT,
2399336Sdfr	NFSERR_STALE,
2409336Sdfr	NFSERR_BADHANDLE,
2419336Sdfr	NFSERR_NOT_SYNC,
2429336Sdfr	NFSERR_SERVERFAULT,
2439336Sdfr	0,
2449336Sdfr};
2459336Sdfr
2469336Sdfrstatic short nfsv3err_lookup[] = {
2479336Sdfr	NFSERR_IO,
2489336Sdfr	NFSERR_NOENT,
2499336Sdfr	NFSERR_IO,
2509336Sdfr	NFSERR_ACCES,
2519336Sdfr	NFSERR_NOTDIR,
2529336Sdfr	NFSERR_NAMETOL,
2539336Sdfr	NFSERR_STALE,
2549336Sdfr	NFSERR_BADHANDLE,
2559336Sdfr	NFSERR_SERVERFAULT,
2569336Sdfr	0,
2579336Sdfr};
2589336Sdfr
2599336Sdfrstatic short nfsv3err_access[] = {
2609336Sdfr	NFSERR_IO,
2619336Sdfr	NFSERR_IO,
2629336Sdfr	NFSERR_STALE,
2639336Sdfr	NFSERR_BADHANDLE,
2649336Sdfr	NFSERR_SERVERFAULT,
2659336Sdfr	0,
2669336Sdfr};
2679336Sdfr
2689336Sdfrstatic short nfsv3err_readlink[] = {
2699336Sdfr	NFSERR_IO,
2709336Sdfr	NFSERR_IO,
2719336Sdfr	NFSERR_ACCES,
2729336Sdfr	NFSERR_INVAL,
2739336Sdfr	NFSERR_STALE,
2749336Sdfr	NFSERR_BADHANDLE,
2759336Sdfr	NFSERR_NOTSUPP,
2769336Sdfr	NFSERR_SERVERFAULT,
2779336Sdfr	0,
2789336Sdfr};
2799336Sdfr
2809336Sdfrstatic short nfsv3err_read[] = {
2819336Sdfr	NFSERR_IO,
2829336Sdfr	NFSERR_IO,
2839336Sdfr	NFSERR_NXIO,
2849336Sdfr	NFSERR_ACCES,
2859336Sdfr	NFSERR_INVAL,
2869336Sdfr	NFSERR_STALE,
2879336Sdfr	NFSERR_BADHANDLE,
2889336Sdfr	NFSERR_SERVERFAULT,
2899336Sdfr	0,
2909336Sdfr};
2919336Sdfr
2929336Sdfrstatic short nfsv3err_write[] = {
2939336Sdfr	NFSERR_IO,
2949336Sdfr	NFSERR_IO,
2959336Sdfr	NFSERR_ACCES,
2969336Sdfr	NFSERR_INVAL,
2979336Sdfr	NFSERR_FBIG,
2989336Sdfr	NFSERR_NOSPC,
2999336Sdfr	NFSERR_ROFS,
3009336Sdfr	NFSERR_DQUOT,
3019336Sdfr	NFSERR_STALE,
3029336Sdfr	NFSERR_BADHANDLE,
3039336Sdfr	NFSERR_SERVERFAULT,
3049336Sdfr	0,
3059336Sdfr};
3069336Sdfr
3079336Sdfrstatic short nfsv3err_create[] = {
3089336Sdfr	NFSERR_IO,
3099336Sdfr	NFSERR_IO,
3109336Sdfr	NFSERR_ACCES,
3119336Sdfr	NFSERR_EXIST,
3129336Sdfr	NFSERR_NOTDIR,
3139336Sdfr	NFSERR_NOSPC,
3149336Sdfr	NFSERR_ROFS,
3159336Sdfr	NFSERR_NAMETOL,
3169336Sdfr	NFSERR_DQUOT,
3179336Sdfr	NFSERR_STALE,
3189336Sdfr	NFSERR_BADHANDLE,
3199336Sdfr	NFSERR_NOTSUPP,
3209336Sdfr	NFSERR_SERVERFAULT,
3219336Sdfr	0,
3229336Sdfr};
3239336Sdfr
3249336Sdfrstatic short nfsv3err_mkdir[] = {
3259336Sdfr	NFSERR_IO,
3269336Sdfr	NFSERR_IO,
3279336Sdfr	NFSERR_ACCES,
3289336Sdfr	NFSERR_EXIST,
3299336Sdfr	NFSERR_NOTDIR,
3309336Sdfr	NFSERR_NOSPC,
3319336Sdfr	NFSERR_ROFS,
3329336Sdfr	NFSERR_NAMETOL,
3339336Sdfr	NFSERR_DQUOT,
3349336Sdfr	NFSERR_STALE,
3359336Sdfr	NFSERR_BADHANDLE,
3369336Sdfr	NFSERR_NOTSUPP,
3379336Sdfr	NFSERR_SERVERFAULT,
3389336Sdfr	0,
3399336Sdfr};
3409336Sdfr
3419336Sdfrstatic short nfsv3err_symlink[] = {
3429336Sdfr	NFSERR_IO,
3439336Sdfr	NFSERR_IO,
3449336Sdfr	NFSERR_ACCES,
3459336Sdfr	NFSERR_EXIST,
3469336Sdfr	NFSERR_NOTDIR,
3479336Sdfr	NFSERR_NOSPC,
3489336Sdfr	NFSERR_ROFS,
3499336Sdfr	NFSERR_NAMETOL,
3509336Sdfr	NFSERR_DQUOT,
3519336Sdfr	NFSERR_STALE,
3529336Sdfr	NFSERR_BADHANDLE,
3539336Sdfr	NFSERR_NOTSUPP,
3549336Sdfr	NFSERR_SERVERFAULT,
3559336Sdfr	0,
3569336Sdfr};
3579336Sdfr
3589336Sdfrstatic short nfsv3err_mknod[] = {
3599336Sdfr	NFSERR_IO,
3609336Sdfr	NFSERR_IO,
3619336Sdfr	NFSERR_ACCES,
3629336Sdfr	NFSERR_EXIST,
3639336Sdfr	NFSERR_NOTDIR,
3649336Sdfr	NFSERR_NOSPC,
3659336Sdfr	NFSERR_ROFS,
3669336Sdfr	NFSERR_NAMETOL,
3679336Sdfr	NFSERR_DQUOT,
3689336Sdfr	NFSERR_STALE,
3699336Sdfr	NFSERR_BADHANDLE,
3709336Sdfr	NFSERR_NOTSUPP,
3719336Sdfr	NFSERR_SERVERFAULT,
3729336Sdfr	NFSERR_BADTYPE,
3739336Sdfr	0,
3749336Sdfr};
3759336Sdfr
3769336Sdfrstatic short nfsv3err_remove[] = {
3779336Sdfr	NFSERR_IO,
3789336Sdfr	NFSERR_NOENT,
3799336Sdfr	NFSERR_IO,
3809336Sdfr	NFSERR_ACCES,
3819336Sdfr	NFSERR_NOTDIR,
3829336Sdfr	NFSERR_ROFS,
3839336Sdfr	NFSERR_NAMETOL,
3849336Sdfr	NFSERR_STALE,
3859336Sdfr	NFSERR_BADHANDLE,
3869336Sdfr	NFSERR_SERVERFAULT,
3879336Sdfr	0,
3889336Sdfr};
3899336Sdfr
3909336Sdfrstatic short nfsv3err_rmdir[] = {
3919336Sdfr	NFSERR_IO,
3929336Sdfr	NFSERR_NOENT,
3939336Sdfr	NFSERR_IO,
3949336Sdfr	NFSERR_ACCES,
3959336Sdfr	NFSERR_EXIST,
3969336Sdfr	NFSERR_NOTDIR,
3979336Sdfr	NFSERR_INVAL,
3989336Sdfr	NFSERR_ROFS,
3999336Sdfr	NFSERR_NAMETOL,
4009336Sdfr	NFSERR_NOTEMPTY,
4019336Sdfr	NFSERR_STALE,
4029336Sdfr	NFSERR_BADHANDLE,
4039336Sdfr	NFSERR_NOTSUPP,
4049336Sdfr	NFSERR_SERVERFAULT,
4059336Sdfr	0,
4069336Sdfr};
4079336Sdfr
4089336Sdfrstatic short nfsv3err_rename[] = {
4099336Sdfr	NFSERR_IO,
4109336Sdfr	NFSERR_NOENT,
4119336Sdfr	NFSERR_IO,
4129336Sdfr	NFSERR_ACCES,
4139336Sdfr	NFSERR_EXIST,
4149336Sdfr	NFSERR_XDEV,
4159336Sdfr	NFSERR_NOTDIR,
4169336Sdfr	NFSERR_ISDIR,
4179336Sdfr	NFSERR_INVAL,
4189336Sdfr	NFSERR_NOSPC,
4199336Sdfr	NFSERR_ROFS,
4209336Sdfr	NFSERR_MLINK,
4219336Sdfr	NFSERR_NAMETOL,
4229336Sdfr	NFSERR_NOTEMPTY,
4239336Sdfr	NFSERR_DQUOT,
4249336Sdfr	NFSERR_STALE,
4259336Sdfr	NFSERR_BADHANDLE,
4269336Sdfr	NFSERR_NOTSUPP,
4279336Sdfr	NFSERR_SERVERFAULT,
4289336Sdfr	0,
4299336Sdfr};
4309336Sdfr
4319336Sdfrstatic short nfsv3err_link[] = {
4329336Sdfr	NFSERR_IO,
4339336Sdfr	NFSERR_IO,
4349336Sdfr	NFSERR_ACCES,
4359336Sdfr	NFSERR_EXIST,
4369336Sdfr	NFSERR_XDEV,
4379336Sdfr	NFSERR_NOTDIR,
4389336Sdfr	NFSERR_INVAL,
4399336Sdfr	NFSERR_NOSPC,
4409336Sdfr	NFSERR_ROFS,
4419336Sdfr	NFSERR_MLINK,
4429336Sdfr	NFSERR_NAMETOL,
4439336Sdfr	NFSERR_DQUOT,
4449336Sdfr	NFSERR_STALE,
4459336Sdfr	NFSERR_BADHANDLE,
4469336Sdfr	NFSERR_NOTSUPP,
4479336Sdfr	NFSERR_SERVERFAULT,
4489336Sdfr	0,
4499336Sdfr};
4509336Sdfr
4519336Sdfrstatic short nfsv3err_readdir[] = {
4529336Sdfr	NFSERR_IO,
4539336Sdfr	NFSERR_IO,
4549336Sdfr	NFSERR_ACCES,
4559336Sdfr	NFSERR_NOTDIR,
4569336Sdfr	NFSERR_STALE,
4579336Sdfr	NFSERR_BADHANDLE,
4589336Sdfr	NFSERR_BAD_COOKIE,
4599336Sdfr	NFSERR_TOOSMALL,
4609336Sdfr	NFSERR_SERVERFAULT,
4619336Sdfr	0,
4629336Sdfr};
4639336Sdfr
4649336Sdfrstatic short nfsv3err_readdirplus[] = {
4659336Sdfr	NFSERR_IO,
4669336Sdfr	NFSERR_IO,
4679336Sdfr	NFSERR_ACCES,
4689336Sdfr	NFSERR_NOTDIR,
4699336Sdfr	NFSERR_STALE,
4709336Sdfr	NFSERR_BADHANDLE,
4719336Sdfr	NFSERR_BAD_COOKIE,
4729336Sdfr	NFSERR_NOTSUPP,
4739336Sdfr	NFSERR_TOOSMALL,
4749336Sdfr	NFSERR_SERVERFAULT,
4759336Sdfr	0,
4769336Sdfr};
4779336Sdfr
4789336Sdfrstatic short nfsv3err_fsstat[] = {
4799336Sdfr	NFSERR_IO,
4809336Sdfr	NFSERR_IO,
4819336Sdfr	NFSERR_STALE,
4829336Sdfr	NFSERR_BADHANDLE,
4839336Sdfr	NFSERR_SERVERFAULT,
4849336Sdfr	0,
4859336Sdfr};
4869336Sdfr
4879336Sdfrstatic short nfsv3err_fsinfo[] = {
4889336Sdfr	NFSERR_STALE,
4899336Sdfr	NFSERR_STALE,
4909336Sdfr	NFSERR_BADHANDLE,
4919336Sdfr	NFSERR_SERVERFAULT,
4929336Sdfr	0,
4939336Sdfr};
4949336Sdfr
4959336Sdfrstatic short nfsv3err_pathconf[] = {
4969336Sdfr	NFSERR_STALE,
4979336Sdfr	NFSERR_STALE,
4989336Sdfr	NFSERR_BADHANDLE,
4999336Sdfr	NFSERR_SERVERFAULT,
5009336Sdfr	0,
5019336Sdfr};
5029336Sdfr
5039336Sdfrstatic short nfsv3err_commit[] = {
5049336Sdfr	NFSERR_IO,
5059336Sdfr	NFSERR_IO,
5069336Sdfr	NFSERR_STALE,
5079336Sdfr	NFSERR_BADHANDLE,
5089336Sdfr	NFSERR_SERVERFAULT,
5099336Sdfr	0,
5109336Sdfr};
5119336Sdfr
5129336Sdfrstatic short *nfsrv_v3errmap[] = {
5139336Sdfr	nfsv3err_null,
5149336Sdfr	nfsv3err_getattr,
5159336Sdfr	nfsv3err_setattr,
5169336Sdfr	nfsv3err_lookup,
5179336Sdfr	nfsv3err_access,
5189336Sdfr	nfsv3err_readlink,
5199336Sdfr	nfsv3err_read,
5209336Sdfr	nfsv3err_write,
5219336Sdfr	nfsv3err_create,
5229336Sdfr	nfsv3err_mkdir,
5239336Sdfr	nfsv3err_symlink,
5249336Sdfr	nfsv3err_mknod,
5259336Sdfr	nfsv3err_remove,
5269336Sdfr	nfsv3err_rmdir,
5279336Sdfr	nfsv3err_rename,
5289336Sdfr	nfsv3err_link,
5299336Sdfr	nfsv3err_readdir,
5309336Sdfr	nfsv3err_readdirplus,
5319336Sdfr	nfsv3err_fsstat,
5329336Sdfr	nfsv3err_fsinfo,
5339336Sdfr	nfsv3err_pathconf,
5349336Sdfr	nfsv3err_commit,
5359336Sdfr};
5369336Sdfr
53713416Sphk#endif /* NFS_NOSERVER */
53813416Sphk
5391541Srgrimesextern struct nfsrtt nfsrtt;
5401541Srgrimesextern time_t nqnfsstarttime;
5411541Srgrimesextern int nqsrv_clockskew;
5421541Srgrimesextern int nqsrv_writeslack;
5431541Srgrimesextern int nqsrv_maxlease;
5449336Sdfrextern struct nfsstats nfsstats;
5459336Sdfrextern int nqnfs_piggy[NFS_NPROCS];
5469336Sdfrextern nfstype nfsv2_type[9];
5479336Sdfrextern nfstype nfsv3_type[9];
5489336Sdfrextern struct nfsnodehashhead *nfsnodehashtbl;
5499336Sdfrextern u_long nfsnodehash;
5501541Srgrimes
5512997Swollmanstruct getfh_args;
5522997Swollmanextern int getfh(struct proc *, struct getfh_args *, int *);
5532997Swollmanstruct nfssvc_args;
5542997Swollmanextern int nfssvc(struct proc *, struct nfssvc_args *, int *);
5552997Swollman
5563664SphkLIST_HEAD(nfsnodehashhead, nfsnode);
5573664Sphk
55827446Sdfrint nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
55927446Sdfr
5601541Srgrimes/*
5611541Srgrimes * Create the header for an rpc request packet
5621541Srgrimes * The hsiz is the size of the rest of the nfs request header.
5631541Srgrimes * (just used to decide if a cluster is a good idea)
5641541Srgrimes */
5651541Srgrimesstruct mbuf *
5661541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp)
5671541Srgrimes	struct vnode *vp;
5681541Srgrimes	u_long procid;
5691541Srgrimes	int hsiz;
5701541Srgrimes	caddr_t *bposp;
5711541Srgrimes{
5721541Srgrimes	register struct mbuf *mb;
5731541Srgrimes	register u_long *tl;
5741541Srgrimes	register caddr_t bpos;
5751541Srgrimes	struct mbuf *mb2;
5761541Srgrimes	struct nfsmount *nmp;
5771541Srgrimes	int nqflag;
5781541Srgrimes
5791541Srgrimes	MGET(mb, M_WAIT, MT_DATA);
5801541Srgrimes	if (hsiz >= MINCLSIZE)
5811541Srgrimes		MCLGET(mb, M_WAIT);
5821541Srgrimes	mb->m_len = 0;
5831541Srgrimes	bpos = mtod(mb, caddr_t);
5848876Srgrimes
5851541Srgrimes	/*
5861541Srgrimes	 * For NQNFS, add lease request.
5871541Srgrimes	 */
5881541Srgrimes	if (vp) {
5891541Srgrimes		nmp = VFSTONFS(vp->v_mount);
5901541Srgrimes		if (nmp->nm_flag & NFSMNT_NQNFS) {
5911541Srgrimes			nqflag = NQNFS_NEEDLEASE(vp, procid);
5921541Srgrimes			if (nqflag) {
5931541Srgrimes				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
5941541Srgrimes				*tl++ = txdr_unsigned(nqflag);
5951541Srgrimes				*tl = txdr_unsigned(nmp->nm_leaseterm);
5961541Srgrimes			} else {
5971541Srgrimes				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
5981541Srgrimes				*tl = 0;
5991541Srgrimes			}
6001541Srgrimes		}
6011541Srgrimes	}
6021541Srgrimes	/* Finally, return values */
6031541Srgrimes	*bposp = bpos;
6041541Srgrimes	return (mb);
6051541Srgrimes}
6061541Srgrimes
6071541Srgrimes/*
6081541Srgrimes * Build the RPC header and fill in the authorization info.
6091541Srgrimes * The authorization string argument is only used when the credentials
6101541Srgrimes * come from outside of the kernel.
6111541Srgrimes * Returns the head of the mbuf list.
6121541Srgrimes */
6131541Srgrimesstruct mbuf *
6149336Sdfrnfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
6159336Sdfr	verf_str, mrest, mrest_len, mbp, xidp)
6161541Srgrimes	register struct ucred *cr;
6179336Sdfr	int nmflag;
6181541Srgrimes	int procid;
6191541Srgrimes	int auth_type;
6201541Srgrimes	int auth_len;
6211541Srgrimes	char *auth_str;
6229336Sdfr	int verf_len;
6239336Sdfr	char *verf_str;
6241541Srgrimes	struct mbuf *mrest;
6251541Srgrimes	int mrest_len;
6261541Srgrimes	struct mbuf **mbp;
6271541Srgrimes	u_long *xidp;
6281541Srgrimes{
6291541Srgrimes	register struct mbuf *mb;
6301541Srgrimes	register u_long *tl;
6311541Srgrimes	register caddr_t bpos;
6321541Srgrimes	register int i;
6331541Srgrimes	struct mbuf *mreq, *mb2;
6341541Srgrimes	int siz, grpsiz, authsiz;
63517186Sdfr	struct timeval tv;
63617186Sdfr	static u_long base;
6371541Srgrimes
6381541Srgrimes	authsiz = nfsm_rndup(auth_len);
6391541Srgrimes	MGETHDR(mb, M_WAIT, MT_DATA);
6409336Sdfr	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
6411541Srgrimes		MCLGET(mb, M_WAIT);
6429336Sdfr	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
6439336Sdfr		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
6441541Srgrimes	} else {
6459336Sdfr		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
6461541Srgrimes	}
6471541Srgrimes	mb->m_len = 0;
6481541Srgrimes	mreq = mb;
6491541Srgrimes	bpos = mtod(mb, caddr_t);
6501541Srgrimes
6511541Srgrimes	/*
6521541Srgrimes	 * First the RPC header.
6531541Srgrimes	 */
6549336Sdfr	nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
65517186Sdfr
65617186Sdfr	/*
65717186Sdfr	 * derive initial xid from system time
65817186Sdfr	 * XXX time is invalid if root not yet mounted
65917186Sdfr	 */
66017186Sdfr	if (!base && (rootvp)) {
66117186Sdfr		microtime(&tv);
66217186Sdfr		base = tv.tv_sec << 12;
66317186Sdfr		nfs_xid = base;
66417186Sdfr	}
66517186Sdfr	/*
66617186Sdfr	 * Skip zero xid if it should ever happen.
66717186Sdfr	 */
6681541Srgrimes	if (++nfs_xid == 0)
6691541Srgrimes		nfs_xid++;
67017186Sdfr
6711541Srgrimes	*tl++ = *xidp = txdr_unsigned(nfs_xid);
6721541Srgrimes	*tl++ = rpc_call;
6731541Srgrimes	*tl++ = rpc_vers;
6749336Sdfr	if (nmflag & NFSMNT_NQNFS) {
6751541Srgrimes		*tl++ = txdr_unsigned(NQNFS_PROG);
6769336Sdfr		*tl++ = txdr_unsigned(NQNFS_VER3);
6771541Srgrimes	} else {
6781541Srgrimes		*tl++ = txdr_unsigned(NFS_PROG);
6799336Sdfr		if (nmflag & NFSMNT_NFSV3)
6809336Sdfr			*tl++ = txdr_unsigned(NFS_VER3);
6819336Sdfr		else
6829336Sdfr			*tl++ = txdr_unsigned(NFS_VER2);
6831541Srgrimes	}
6849336Sdfr	if (nmflag & NFSMNT_NFSV3)
6859336Sdfr		*tl++ = txdr_unsigned(procid);
6869336Sdfr	else
6879336Sdfr		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
6881541Srgrimes
6891541Srgrimes	/*
6901541Srgrimes	 * And then the authorization cred.
6911541Srgrimes	 */
6921541Srgrimes	*tl++ = txdr_unsigned(auth_type);
6931541Srgrimes	*tl = txdr_unsigned(authsiz);
6941541Srgrimes	switch (auth_type) {
6951541Srgrimes	case RPCAUTH_UNIX:
6961541Srgrimes		nfsm_build(tl, u_long *, auth_len);
6971541Srgrimes		*tl++ = 0;		/* stamp ?? */
6981541Srgrimes		*tl++ = 0;		/* NULL hostname */
6991541Srgrimes		*tl++ = txdr_unsigned(cr->cr_uid);
7001541Srgrimes		*tl++ = txdr_unsigned(cr->cr_groups[0]);
7011541Srgrimes		grpsiz = (auth_len >> 2) - 5;
7021541Srgrimes		*tl++ = txdr_unsigned(grpsiz);
7031541Srgrimes		for (i = 1; i <= grpsiz; i++)
7041541Srgrimes			*tl++ = txdr_unsigned(cr->cr_groups[i]);
7051541Srgrimes		break;
7069336Sdfr	case RPCAUTH_KERB4:
7071541Srgrimes		siz = auth_len;
7081541Srgrimes		while (siz > 0) {
7091541Srgrimes			if (M_TRAILINGSPACE(mb) == 0) {
7101541Srgrimes				MGET(mb2, M_WAIT, MT_DATA);
7111541Srgrimes				if (siz >= MINCLSIZE)
7121541Srgrimes					MCLGET(mb2, M_WAIT);
7131541Srgrimes				mb->m_next = mb2;
7141541Srgrimes				mb = mb2;
7151541Srgrimes				mb->m_len = 0;
7161541Srgrimes				bpos = mtod(mb, caddr_t);
7171541Srgrimes			}
7181541Srgrimes			i = min(siz, M_TRAILINGSPACE(mb));
7191541Srgrimes			bcopy(auth_str, bpos, i);
7201541Srgrimes			mb->m_len += i;
7211541Srgrimes			auth_str += i;
7221541Srgrimes			bpos += i;
7231541Srgrimes			siz -= i;
7241541Srgrimes		}
7251541Srgrimes		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
7261541Srgrimes			for (i = 0; i < siz; i++)
7271541Srgrimes				*bpos++ = '\0';
7281541Srgrimes			mb->m_len += siz;
7291541Srgrimes		}
7301541Srgrimes		break;
7311541Srgrimes	};
7329336Sdfr
7339336Sdfr	/*
7349336Sdfr	 * And the verifier...
7359336Sdfr	 */
7369336Sdfr	nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
7379336Sdfr	if (verf_str) {
7389336Sdfr		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
7399336Sdfr		*tl = txdr_unsigned(verf_len);
7409336Sdfr		siz = verf_len;
7419336Sdfr		while (siz > 0) {
7429336Sdfr			if (M_TRAILINGSPACE(mb) == 0) {
7439336Sdfr				MGET(mb2, M_WAIT, MT_DATA);
7449336Sdfr				if (siz >= MINCLSIZE)
7459336Sdfr					MCLGET(mb2, M_WAIT);
7469336Sdfr				mb->m_next = mb2;
7479336Sdfr				mb = mb2;
7489336Sdfr				mb->m_len = 0;
7499336Sdfr				bpos = mtod(mb, caddr_t);
7509336Sdfr			}
7519336Sdfr			i = min(siz, M_TRAILINGSPACE(mb));
7529336Sdfr			bcopy(verf_str, bpos, i);
7539336Sdfr			mb->m_len += i;
7549336Sdfr			verf_str += i;
7559336Sdfr			bpos += i;
7569336Sdfr			siz -= i;
7579336Sdfr		}
7589336Sdfr		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
7599336Sdfr			for (i = 0; i < siz; i++)
7609336Sdfr				*bpos++ = '\0';
7619336Sdfr			mb->m_len += siz;
7629336Sdfr		}
7639336Sdfr	} else {
7649336Sdfr		*tl++ = txdr_unsigned(RPCAUTH_NULL);
7659336Sdfr		*tl = 0;
7669336Sdfr	}
7671541Srgrimes	mb->m_next = mrest;
7689336Sdfr	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
7691541Srgrimes	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
7701541Srgrimes	*mbp = mb;
7711541Srgrimes	return (mreq);
7721541Srgrimes}
7731541Srgrimes
7741541Srgrimes/*
7751541Srgrimes * copies mbuf chain to the uio scatter/gather list
7761541Srgrimes */
7771549Srgrimesint
7781541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos)
7791541Srgrimes	struct mbuf **mrep;
7801541Srgrimes	register struct uio *uiop;
7811541Srgrimes	int siz;
7821541Srgrimes	caddr_t *dpos;
7831541Srgrimes{
7841541Srgrimes	register char *mbufcp, *uiocp;
7851541Srgrimes	register int xfer, left, len;
7861541Srgrimes	register struct mbuf *mp;
7871541Srgrimes	long uiosiz, rem;
7881541Srgrimes	int error = 0;
7891541Srgrimes
7901541Srgrimes	mp = *mrep;
7911541Srgrimes	mbufcp = *dpos;
7921541Srgrimes	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
7931541Srgrimes	rem = nfsm_rndup(siz)-siz;
7941541Srgrimes	while (siz > 0) {
7951541Srgrimes		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
7961541Srgrimes			return (EFBIG);
7971541Srgrimes		left = uiop->uio_iov->iov_len;
7981541Srgrimes		uiocp = uiop->uio_iov->iov_base;
7991541Srgrimes		if (left > siz)
8001541Srgrimes			left = siz;
8011541Srgrimes		uiosiz = left;
8021541Srgrimes		while (left > 0) {
8031541Srgrimes			while (len == 0) {
8041541Srgrimes				mp = mp->m_next;
8051541Srgrimes				if (mp == NULL)
8061541Srgrimes					return (EBADRPC);
8071541Srgrimes				mbufcp = mtod(mp, caddr_t);
8081541Srgrimes				len = mp->m_len;
8091541Srgrimes			}
8101541Srgrimes			xfer = (left > len) ? len : left;
8111541Srgrimes#ifdef notdef
8121541Srgrimes			/* Not Yet.. */
8131541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
8141541Srgrimes				(*(uiop->uio_iov->iov_op))
8151541Srgrimes				(mbufcp, uiocp, xfer);
8161541Srgrimes			else
8171541Srgrimes#endif
8181541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
8191541Srgrimes				bcopy(mbufcp, uiocp, xfer);
8201541Srgrimes			else
8211541Srgrimes				copyout(mbufcp, uiocp, xfer);
8221541Srgrimes			left -= xfer;
8231541Srgrimes			len -= xfer;
8241541Srgrimes			mbufcp += xfer;
8251541Srgrimes			uiocp += xfer;
8261541Srgrimes			uiop->uio_offset += xfer;
8271541Srgrimes			uiop->uio_resid -= xfer;
8281541Srgrimes		}
8291541Srgrimes		if (uiop->uio_iov->iov_len <= siz) {
8301541Srgrimes			uiop->uio_iovcnt--;
8311541Srgrimes			uiop->uio_iov++;
8321541Srgrimes		} else {
8331541Srgrimes			uiop->uio_iov->iov_base += uiosiz;
8341541Srgrimes			uiop->uio_iov->iov_len -= uiosiz;
8351541Srgrimes		}
8361541Srgrimes		siz -= uiosiz;
8371541Srgrimes	}
8381541Srgrimes	*dpos = mbufcp;
8391541Srgrimes	*mrep = mp;
8401541Srgrimes	if (rem > 0) {
8411541Srgrimes		if (len < rem)
8421541Srgrimes			error = nfs_adv(mrep, dpos, rem, len);
8431541Srgrimes		else
8441541Srgrimes			*dpos += rem;
8451541Srgrimes	}
8461541Srgrimes	return (error);
8471541Srgrimes}
8481541Srgrimes
8491541Srgrimes/*
85017186Sdfr * copies a uio scatter/gather list to an mbuf chain.
85117186Sdfr * NOTE: can ony handle iovcnt == 1
8521541Srgrimes */
8531549Srgrimesint
8541541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos)
8551541Srgrimes	register struct uio *uiop;
8561541Srgrimes	struct mbuf **mq;
8571541Srgrimes	int siz;
8581541Srgrimes	caddr_t *bpos;
8591541Srgrimes{
8601541Srgrimes	register char *uiocp;
8611541Srgrimes	register struct mbuf *mp, *mp2;
8621541Srgrimes	register int xfer, left, mlen;
8631541Srgrimes	int uiosiz, clflg, rem;
8641541Srgrimes	char *cp;
8651541Srgrimes
86617186Sdfr	if (uiop->uio_iovcnt != 1)
86717186Sdfr		panic("nfsm_uiotombuf: iovcnt != 1");
86817186Sdfr
8691541Srgrimes	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
8701541Srgrimes		clflg = 1;
8711541Srgrimes	else
8721541Srgrimes		clflg = 0;
8731541Srgrimes	rem = nfsm_rndup(siz)-siz;
8741541Srgrimes	mp = mp2 = *mq;
8751541Srgrimes	while (siz > 0) {
8761541Srgrimes		left = uiop->uio_iov->iov_len;
8771541Srgrimes		uiocp = uiop->uio_iov->iov_base;
8781541Srgrimes		if (left > siz)
8791541Srgrimes			left = siz;
8801541Srgrimes		uiosiz = left;
8811541Srgrimes		while (left > 0) {
8821541Srgrimes			mlen = M_TRAILINGSPACE(mp);
8831541Srgrimes			if (mlen == 0) {
8841541Srgrimes				MGET(mp, M_WAIT, MT_DATA);
8851541Srgrimes				if (clflg)
8861541Srgrimes					MCLGET(mp, M_WAIT);
8871541Srgrimes				mp->m_len = 0;
8881541Srgrimes				mp2->m_next = mp;
8891541Srgrimes				mp2 = mp;
8901541Srgrimes				mlen = M_TRAILINGSPACE(mp);
8911541Srgrimes			}
8921541Srgrimes			xfer = (left > mlen) ? mlen : left;
8931541Srgrimes#ifdef notdef
8941541Srgrimes			/* Not Yet.. */
8951541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
8961541Srgrimes				(*(uiop->uio_iov->iov_op))
8971541Srgrimes				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
8981541Srgrimes			else
8991541Srgrimes#endif
9001541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
9011541Srgrimes				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
9021541Srgrimes			else
9031541Srgrimes				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
9041541Srgrimes			mp->m_len += xfer;
9051541Srgrimes			left -= xfer;
9061541Srgrimes			uiocp += xfer;
9071541Srgrimes			uiop->uio_offset += xfer;
9081541Srgrimes			uiop->uio_resid -= xfer;
9091541Srgrimes		}
91017186Sdfr		uiop->uio_iov->iov_base += uiosiz;
91117186Sdfr		uiop->uio_iov->iov_len -= uiosiz;
9121541Srgrimes		siz -= uiosiz;
9131541Srgrimes	}
9141541Srgrimes	if (rem > 0) {
9151541Srgrimes		if (rem > M_TRAILINGSPACE(mp)) {
9161541Srgrimes			MGET(mp, M_WAIT, MT_DATA);
9171541Srgrimes			mp->m_len = 0;
9181541Srgrimes			mp2->m_next = mp;
9191541Srgrimes		}
9201541Srgrimes		cp = mtod(mp, caddr_t)+mp->m_len;
9211541Srgrimes		for (left = 0; left < rem; left++)
9221541Srgrimes			*cp++ = '\0';
9231541Srgrimes		mp->m_len += rem;
9241541Srgrimes		*bpos = cp;
9251541Srgrimes	} else
9261541Srgrimes		*bpos = mtod(mp, caddr_t)+mp->m_len;
9271541Srgrimes	*mq = mp;
9281541Srgrimes	return (0);
9291541Srgrimes}
9301541Srgrimes
9311541Srgrimes/*
9321541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous
9331541Srgrimes * pointed to by returned val.
9341541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
9351541Srgrimes * cases. (The macros use the vars. dpos and dpos2)
9361541Srgrimes */
9371549Srgrimesint
9381541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2)
9391541Srgrimes	struct mbuf **mdp;
9401541Srgrimes	caddr_t *dposp;
9411541Srgrimes	int siz;
9421541Srgrimes	int left;
9431541Srgrimes	caddr_t *cp2;
9441541Srgrimes{
9451541Srgrimes	register struct mbuf *mp, *mp2;
9461541Srgrimes	register int siz2, xfer;
9471541Srgrimes	register caddr_t p;
9481541Srgrimes
9491541Srgrimes	mp = *mdp;
9501541Srgrimes	while (left == 0) {
9511541Srgrimes		*mdp = mp = mp->m_next;
9521541Srgrimes		if (mp == NULL)
9531541Srgrimes			return (EBADRPC);
9541541Srgrimes		left = mp->m_len;
9551541Srgrimes		*dposp = mtod(mp, caddr_t);
9561541Srgrimes	}
9571541Srgrimes	if (left >= siz) {
9581541Srgrimes		*cp2 = *dposp;
9591541Srgrimes		*dposp += siz;
9601541Srgrimes	} else if (mp->m_next == NULL) {
9611541Srgrimes		return (EBADRPC);
9621541Srgrimes	} else if (siz > MHLEN) {
9631541Srgrimes		panic("nfs S too big");
9641541Srgrimes	} else {
9651541Srgrimes		MGET(mp2, M_WAIT, MT_DATA);
9661541Srgrimes		mp2->m_next = mp->m_next;
9671541Srgrimes		mp->m_next = mp2;
9681541Srgrimes		mp->m_len -= left;
9691541Srgrimes		mp = mp2;
9701541Srgrimes		*cp2 = p = mtod(mp, caddr_t);
9711541Srgrimes		bcopy(*dposp, p, left);		/* Copy what was left */
9721541Srgrimes		siz2 = siz-left;
9731541Srgrimes		p += left;
9741541Srgrimes		mp2 = mp->m_next;
9751541Srgrimes		/* Loop around copying up the siz2 bytes */
9761541Srgrimes		while (siz2 > 0) {
9771541Srgrimes			if (mp2 == NULL)
9781541Srgrimes				return (EBADRPC);
9791541Srgrimes			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
9801541Srgrimes			if (xfer > 0) {
9811541Srgrimes				bcopy(mtod(mp2, caddr_t), p, xfer);
9821541Srgrimes				NFSMADV(mp2, xfer);
9831541Srgrimes				mp2->m_len -= xfer;
9841541Srgrimes				p += xfer;
9851541Srgrimes				siz2 -= xfer;
9861541Srgrimes			}
9871541Srgrimes			if (siz2 > 0)
9881541Srgrimes				mp2 = mp2->m_next;
9891541Srgrimes		}
9901541Srgrimes		mp->m_len = siz;
9911541Srgrimes		*mdp = mp2;
9921541Srgrimes		*dposp = mtod(mp2, caddr_t);
9931541Srgrimes	}
9941541Srgrimes	return (0);
9951541Srgrimes}
9961541Srgrimes
9971541Srgrimes/*
9981541Srgrimes * Advance the position in the mbuf chain.
9991541Srgrimes */
10001549Srgrimesint
10011541Srgrimesnfs_adv(mdp, dposp, offs, left)
10021541Srgrimes	struct mbuf **mdp;
10031541Srgrimes	caddr_t *dposp;
10041541Srgrimes	int offs;
10051541Srgrimes	int left;
10061541Srgrimes{
10071541Srgrimes	register struct mbuf *m;
10081541Srgrimes	register int s;
10091541Srgrimes
10101541Srgrimes	m = *mdp;
10111541Srgrimes	s = left;
10121541Srgrimes	while (s < offs) {
10131541Srgrimes		offs -= s;
10141541Srgrimes		m = m->m_next;
10151541Srgrimes		if (m == NULL)
10161541Srgrimes			return (EBADRPC);
10171541Srgrimes		s = m->m_len;
10181541Srgrimes	}
10191541Srgrimes	*mdp = m;
10201541Srgrimes	*dposp = mtod(m, caddr_t)+offs;
10211541Srgrimes	return (0);
10221541Srgrimes}
10231541Srgrimes
10241541Srgrimes/*
10251541Srgrimes * Copy a string into mbufs for the hard cases...
10261541Srgrimes */
10271549Srgrimesint
10281541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz)
10291541Srgrimes	struct mbuf **mb;
10301541Srgrimes	char **bpos;
10311541Srgrimes	char *cp;
10321541Srgrimes	long siz;
10331541Srgrimes{
10341549Srgrimes	register struct mbuf *m1 = 0, *m2;
10351541Srgrimes	long left, xfer, len, tlen;
10361541Srgrimes	u_long *tl;
10371541Srgrimes	int putsize;
10381541Srgrimes
10391541Srgrimes	putsize = 1;
10401541Srgrimes	m2 = *mb;
10411541Srgrimes	left = M_TRAILINGSPACE(m2);
10421541Srgrimes	if (left > 0) {
10431541Srgrimes		tl = ((u_long *)(*bpos));
10441541Srgrimes		*tl++ = txdr_unsigned(siz);
10451541Srgrimes		putsize = 0;
10461541Srgrimes		left -= NFSX_UNSIGNED;
10471541Srgrimes		m2->m_len += NFSX_UNSIGNED;
10481541Srgrimes		if (left > 0) {
10491541Srgrimes			bcopy(cp, (caddr_t) tl, left);
10501541Srgrimes			siz -= left;
10511541Srgrimes			cp += left;
10521541Srgrimes			m2->m_len += left;
10531541Srgrimes			left = 0;
10541541Srgrimes		}
10551541Srgrimes	}
10561541Srgrimes	/* Loop around adding mbufs */
10571541Srgrimes	while (siz > 0) {
10581541Srgrimes		MGET(m1, M_WAIT, MT_DATA);
10591541Srgrimes		if (siz > MLEN)
10601541Srgrimes			MCLGET(m1, M_WAIT);
10611541Srgrimes		m1->m_len = NFSMSIZ(m1);
10621541Srgrimes		m2->m_next = m1;
10631541Srgrimes		m2 = m1;
10641541Srgrimes		tl = mtod(m1, u_long *);
10651541Srgrimes		tlen = 0;
10661541Srgrimes		if (putsize) {
10671541Srgrimes			*tl++ = txdr_unsigned(siz);
10681541Srgrimes			m1->m_len -= NFSX_UNSIGNED;
10691541Srgrimes			tlen = NFSX_UNSIGNED;
10701541Srgrimes			putsize = 0;
10711541Srgrimes		}
10721541Srgrimes		if (siz < m1->m_len) {
10731541Srgrimes			len = nfsm_rndup(siz);
10741541Srgrimes			xfer = siz;
10751541Srgrimes			if (xfer < len)
10761541Srgrimes				*(tl+(xfer>>2)) = 0;
10771541Srgrimes		} else {
10781541Srgrimes			xfer = len = m1->m_len;
10791541Srgrimes		}
10801541Srgrimes		bcopy(cp, (caddr_t) tl, xfer);
10811541Srgrimes		m1->m_len = len+tlen;
10821541Srgrimes		siz -= xfer;
10831541Srgrimes		cp += xfer;
10841541Srgrimes	}
10851541Srgrimes	*mb = m1;
10861541Srgrimes	*bpos = mtod(m1, caddr_t)+m1->m_len;
10871541Srgrimes	return (0);
10881541Srgrimes}
10891541Srgrimes
10901541Srgrimes/*
10911541Srgrimes * Called once to initialize data structures...
10921541Srgrimes */
10931549Srgrimesint
109422521Sdysonnfs_init(vfsp)
109522521Sdyson	struct vfsconf *vfsp;
10961541Srgrimes{
10971541Srgrimes	register int i;
10981541Srgrimes
10999336Sdfr	/*
11009336Sdfr	 * Check to see if major data structures haven't bloated.
11019336Sdfr	 */
11029336Sdfr	if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
11039336Sdfr		printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
11049336Sdfr		printf("Try reducing NFS_SMALLFH\n");
11059336Sdfr	}
11069336Sdfr	if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
11079336Sdfr		printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
11089336Sdfr		printf("Try reducing NFS_MUIDHASHSIZ\n");
11099336Sdfr	}
11109336Sdfr	if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
11119336Sdfr		printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
11129336Sdfr		printf("Try reducing NFS_UIDHASHSIZ\n");
11139336Sdfr	}
11149336Sdfr	if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
11159336Sdfr		printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
11169336Sdfr		printf("Try unionizing the nu_nickname and nu_flag fields\n");
11179336Sdfr	}
111822521Sdyson	nfs_mount_type = vfsp->vfc_typenum;
11191541Srgrimes	nfsrtt.pos = 0;
11201541Srgrimes	rpc_vers = txdr_unsigned(RPC_VER2);
11211541Srgrimes	rpc_call = txdr_unsigned(RPC_CALL);
11221541Srgrimes	rpc_reply = txdr_unsigned(RPC_REPLY);
11231541Srgrimes	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
11241541Srgrimes	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
11251541Srgrimes	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
11261541Srgrimes	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
11271541Srgrimes	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
11289336Sdfr	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
11291541Srgrimes	nfs_prog = txdr_unsigned(NFS_PROG);
11309336Sdfr	nqnfs_prog = txdr_unsigned(NQNFS_PROG);
11311541Srgrimes	nfs_true = txdr_unsigned(TRUE);
11321541Srgrimes	nfs_false = txdr_unsigned(FALSE);
11333664Sphk	nfs_xdrneg1 = txdr_unsigned(-1);
11349336Sdfr	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
11359336Sdfr	if (nfs_ticks < 1)
11369336Sdfr		nfs_ticks = 1;
11371541Srgrimes	/* Ensure async daemons disabled */
113819449Sdfr	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
11391541Srgrimes		nfs_iodwant[i] = (struct proc *)0;
114019449Sdfr		nfs_iodmount[i] = (struct nfsmount *)0;
114119449Sdfr	}
11421541Srgrimes	nfs_nhinit();			/* Init the nfsnode table */
114313416Sphk#ifndef NFS_NOSERVER
11441541Srgrimes	nfsrv_init(0);			/* Init server data structures */
11451541Srgrimes	nfsrv_initcache();		/* Init the server request cache */
114613416Sphk#endif
11471541Srgrimes
11481541Srgrimes	/*
11491541Srgrimes	 * Initialize the nqnfs server stuff.
11501541Srgrimes	 */
11511541Srgrimes	if (nqnfsstarttime == 0) {
11521541Srgrimes		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
11531541Srgrimes			+ nqsrv_clockskew + nqsrv_writeslack;
11541541Srgrimes		NQLOADNOVRAM(nqnfsstarttime);
11553664Sphk		CIRCLEQ_INIT(&nqtimerhead);
11563664Sphk		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
11571541Srgrimes	}
11581541Srgrimes
11591541Srgrimes	/*
11601541Srgrimes	 * Initialize reply list and start timer
11611541Srgrimes	 */
11623664Sphk	TAILQ_INIT(&nfs_reqq);
116316365Sphk
11643305Sphk	nfs_timer(0);
11651549Srgrimes
116616365Sphk
11672997Swollman	/*
11682997Swollman	 * Set up lease_check and lease_updatetime so that other parts
11692997Swollman	 * of the system can call us, if we are loadable.
11702997Swollman	 */
117113416Sphk#ifndef NFS_NOSERVER
117230738Sphk	default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check;
117313416Sphk#endif
11742997Swollman	lease_updatetime = nfs_lease_updatetime;
117522521Sdyson	vfsp->vfc_refcount++; /* make us non-unloadable */
11762997Swollman	sysent[SYS_nfssvc].sy_narg = 2;
117730738Sphk	sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
117813416Sphk#ifndef NFS_NOSERVER
11792997Swollman	sysent[SYS_getfh].sy_narg = 2;
118030738Sphk	sysent[SYS_getfh].sy_call = (sy_call_t *)getfh;
11812997Swollman#endif
11822997Swollman
11831549Srgrimes	return (0);
11841541Srgrimes}
11851541Srgrimes
11861541Srgrimes/*
11871541Srgrimes * Attribute cache routines.
11881541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes
11891541Srgrimes *	that are on the mbuf list
11901541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns
11911541Srgrimes *	error otherwise
11921541Srgrimes */
11931541Srgrimes
11941541Srgrimes/*
11951541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with
11961541Srgrimes * the values on the mbuf list and
11971541Srgrimes * Iff vap not NULL
11981541Srgrimes *    copy the attributes to *vaper
11991541Srgrimes */
12001549Srgrimesint
12011541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper)
12021541Srgrimes	struct vnode **vpp;
12031541Srgrimes	struct mbuf **mdp;
12041541Srgrimes	caddr_t *dposp;
12051541Srgrimes	struct vattr *vaper;
12061541Srgrimes{
12071541Srgrimes	register struct vnode *vp = *vpp;
12081541Srgrimes	register struct vattr *vap;
12099336Sdfr	register struct nfs_fattr *fp;
12103664Sphk	register struct nfsnode *np;
12111541Srgrimes	register long t1;
12129336Sdfr	caddr_t cp2;
12139336Sdfr	int error = 0, rdev;
12141541Srgrimes	struct mbuf *md;
12151541Srgrimes	enum vtype vtyp;
12161541Srgrimes	u_short vmode;
12171541Srgrimes	struct timespec mtime;
12181541Srgrimes	struct vnode *nvp;
12199336Sdfr	int v3 = NFS_ISV3(vp);
12201541Srgrimes
12211541Srgrimes	md = *mdp;
12229336Sdfr	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
12239336Sdfr	if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))
12241541Srgrimes		return (error);
12259336Sdfr	fp = (struct nfs_fattr *)cp2;
12269336Sdfr	if (v3) {
12279336Sdfr		vtyp = nfsv3tov_type(fp->fa_type);
12289336Sdfr		vmode = fxdr_unsigned(u_short, fp->fa_mode);
122916634Sbde		rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
123016634Sbde			fxdr_unsigned(int, fp->fa3_rdev.specdata2));
12319336Sdfr		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
12321541Srgrimes	} else {
12339336Sdfr		vtyp = nfsv2tov_type(fp->fa_type);
12349336Sdfr		vmode = fxdr_unsigned(u_short, fp->fa_mode);
12359336Sdfr		/*
12369336Sdfr		 * XXX
12379336Sdfr		 *
12389336Sdfr		 * The duplicate information returned in fa_type and fa_mode
12399336Sdfr		 * is an ambiguity in the NFS version 2 protocol.
12409336Sdfr		 *
12419336Sdfr		 * VREG should be taken literally as a regular file.  If a
12429336Sdfr		 * server intents to return some type information differently
12439336Sdfr		 * in the upper bits of the mode field (e.g. for sockets, or
12449336Sdfr		 * FIFOs), NFSv2 mandates fa_type to be VNON.  Anyway, we
12459336Sdfr		 * leave the examination of the mode bits even in the VREG
12469336Sdfr		 * case to avoid breakage for bogus servers, but we make sure
12479336Sdfr		 * that there are actually type bits set in the upper part of
12489336Sdfr		 * fa_mode (and failing that, trust the va_type field).
12499336Sdfr		 *
12509336Sdfr		 * NFSv3 cleared the issue, and requires fa_mode to not
12519336Sdfr		 * contain any type information (while also introduing sockets
12529336Sdfr		 * and FIFOs for fa_type).
12539336Sdfr		 */
12549336Sdfr		if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
12559336Sdfr			vtyp = IFTOVT(vmode);
12569336Sdfr		rdev = fxdr_unsigned(long, fp->fa2_rdev);
12579336Sdfr		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
12589336Sdfr
12599336Sdfr		/*
12609336Sdfr		 * Really ugly NFSv2 kludge.
12619336Sdfr		 */
12629336Sdfr		if (vtyp == VCHR && rdev == 0xffffffff)
12639336Sdfr			vtyp = VFIFO;
12641541Srgrimes	}
12659336Sdfr
12661541Srgrimes	/*
12671541Srgrimes	 * If v_type == VNON it is a new node, so fill in the v_type,
12688876Srgrimes	 * n_mtime fields. Check to see if it represents a special
12691541Srgrimes	 * device, and if so, check for a possible alias. Once the
12701541Srgrimes	 * correct vnode has been obtained, fill in the rest of the
12711541Srgrimes	 * information.
12721541Srgrimes	 */
12731541Srgrimes	np = VTONFS(vp);
127410219Sdfr	if (vp->v_type != vtyp) {
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.
128522521Sdyson				 * Since the nfsnode does not have a lock, its
128622521Sdyson				 * vnode lock has to be carried over.
12871541Srgrimes				 */
128822521Sdyson				nvp->v_vnlock = vp->v_vnlock;
128922521Sdyson				vp->v_vnlock = NULL;
12901541Srgrimes				nvp->v_data = vp->v_data;
12911541Srgrimes				vp->v_data = NULL;
12921541Srgrimes				vp->v_op = spec_vnodeop_p;
12931541Srgrimes				vrele(vp);
12941541Srgrimes				vgone(vp);
12951541Srgrimes				/*
12961541Srgrimes				 * Reinitialize aliased node.
12971541Srgrimes				 */
12981541Srgrimes				np->n_vnode = nvp;
12991541Srgrimes				*vpp = vp = nvp;
13001541Srgrimes			}
13011541Srgrimes		}
130218397Snate		np->n_mtime = mtime.tv_sec;
13031541Srgrimes	}
13041541Srgrimes	vap = &np->n_vattr;
13051541Srgrimes	vap->va_type = vtyp;
13061541Srgrimes	vap->va_mode = (vmode & 07777);
13071541Srgrimes	vap->va_rdev = (dev_t)rdev;
13081541Srgrimes	vap->va_mtime = mtime;
13091541Srgrimes	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
13109336Sdfr	if (v3) {
13119336Sdfr		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
13129336Sdfr		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
13139336Sdfr		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
13149336Sdfr		fxdr_hyper(&fp->fa3_size, &vap->va_size);
13159336Sdfr		vap->va_blocksize = NFS_FABLKSIZE;
13169336Sdfr		fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
13179336Sdfr		vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]);
13189336Sdfr		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
13199336Sdfr		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
13209336Sdfr		vap->va_flags = 0;
13219336Sdfr		vap->va_filerev = 0;
13221541Srgrimes	} else {
13239336Sdfr		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
13249336Sdfr		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
13259336Sdfr		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
13269336Sdfr		vap->va_size = fxdr_unsigned(u_long, fp->fa2_size);
13279336Sdfr		vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
13289336Sdfr		vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
13299336Sdfr		vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid);
13309336Sdfr		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
13311541Srgrimes		vap->va_flags = 0;
133218397Snate		vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec);
133318397Snate		vap->va_ctime.tv_nsec = 0;
13349336Sdfr		vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec);
13351541Srgrimes		vap->va_filerev = 0;
13361541Srgrimes	}
13371541Srgrimes	if (vap->va_size != np->n_size) {
13381541Srgrimes		if (vap->va_type == VREG) {
13391541Srgrimes			if (np->n_flag & NMODIFIED) {
13401541Srgrimes				if (vap->va_size < np->n_size)
13411541Srgrimes					vap->va_size = np->n_size;
13421541Srgrimes				else
13431541Srgrimes					np->n_size = vap->va_size;
13441541Srgrimes			} else
13451541Srgrimes				np->n_size = vap->va_size;
13461541Srgrimes			vnode_pager_setsize(vp, (u_long)np->n_size);
13471541Srgrimes		} else
13481541Srgrimes			np->n_size = vap->va_size;
13491541Srgrimes	}
13501541Srgrimes	np->n_attrstamp = time.tv_sec;
13511541Srgrimes	if (vaper != NULL) {
13521541Srgrimes		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
13531541Srgrimes		if (np->n_flag & NCHG) {
13549336Sdfr			if (np->n_flag & NACC)
13559336Sdfr				vaper->va_atime = np->n_atim;
13569336Sdfr			if (np->n_flag & NUPD)
13579336Sdfr				vaper->va_mtime = np->n_mtim;
13581541Srgrimes		}
13591541Srgrimes	}
13601541Srgrimes	return (0);
13611541Srgrimes}
13621541Srgrimes
13631541Srgrimes/*
13641541Srgrimes * Check the time stamp
13651541Srgrimes * If the cache is valid, copy contents to *vap and return 0
13661541Srgrimes * otherwise return an error
13671541Srgrimes */
13681549Srgrimesint
13691541Srgrimesnfs_getattrcache(vp, vaper)
13701541Srgrimes	register struct vnode *vp;
13711541Srgrimes	struct vattr *vaper;
13721541Srgrimes{
13731541Srgrimes	register struct nfsnode *np = VTONFS(vp);
13741541Srgrimes	register struct vattr *vap;
13751541Srgrimes
13769336Sdfr	if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
13771541Srgrimes		nfsstats.attrcache_misses++;
13781541Srgrimes		return (ENOENT);
13791541Srgrimes	}
13801541Srgrimes	nfsstats.attrcache_hits++;
13811541Srgrimes	vap = &np->n_vattr;
13821541Srgrimes	if (vap->va_size != np->n_size) {
13831541Srgrimes		if (vap->va_type == VREG) {
13841541Srgrimes			if (np->n_flag & NMODIFIED) {
13851541Srgrimes				if (vap->va_size < np->n_size)
13861541Srgrimes					vap->va_size = np->n_size;
13871541Srgrimes				else
13881541Srgrimes					np->n_size = vap->va_size;
13891541Srgrimes			} else
13901541Srgrimes				np->n_size = vap->va_size;
13911541Srgrimes			vnode_pager_setsize(vp, (u_long)np->n_size);
13921541Srgrimes		} else
13931541Srgrimes			np->n_size = vap->va_size;
13941541Srgrimes	}
13951541Srgrimes	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
13961541Srgrimes	if (np->n_flag & NCHG) {
13979336Sdfr		if (np->n_flag & NACC)
13989336Sdfr			vaper->va_atime = np->n_atim;
13999336Sdfr		if (np->n_flag & NUPD)
14009336Sdfr			vaper->va_mtime = np->n_mtim;
14011541Srgrimes	}
14021541Srgrimes	return (0);
14031541Srgrimes}
14041541Srgrimes
140513416Sphk#ifndef NFS_NOSERVER
14061541Srgrimes/*
140727446Sdfr * Set up nameidata for a lookup() call and do it.
140827446Sdfr *
140927446Sdfr * If pubflag is set, this call is done for a lookup operation on the
141027446Sdfr * public filehandle. In that case we allow crossing mountpoints and
141127446Sdfr * absolute pathnames. However, the caller is expected to check that
141227446Sdfr * the lookup result is within the public fs, and deny access if
141327446Sdfr * it is not.
14141541Srgrimes */
14151549Srgrimesint
141627446Sdfrnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
14171541Srgrimes	register struct nameidata *ndp;
14181541Srgrimes	fhandle_t *fhp;
14191541Srgrimes	int len;
14201541Srgrimes	struct nfssvc_sock *slp;
142128270Swollman	struct sockaddr *nam;
14221541Srgrimes	struct mbuf **mdp;
14231541Srgrimes	caddr_t *dposp;
14249336Sdfr	struct vnode **retdirp;
14251541Srgrimes	struct proc *p;
142627446Sdfr	int kerbflag, pubflag;
14271541Srgrimes{
14281541Srgrimes	register int i, rem;
14291541Srgrimes	register struct mbuf *md;
143027446Sdfr	register char *fromcp, *tocp, *cp;
143127446Sdfr	struct iovec aiov;
143227446Sdfr	struct uio auio;
14331541Srgrimes	struct vnode *dp;
143427446Sdfr	int error, rdonly, linklen;
14351541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
14361541Srgrimes
14379336Sdfr	*retdirp = (struct vnode *)0;
143829653Sdyson	cnp->cn_pnbuf = zalloc(namei_zone);
143929653Sdyson
14401541Srgrimes	/*
14411541Srgrimes	 * Copy the name from the mbuf list to ndp->ni_pnbuf
14421541Srgrimes	 * and set the various ndp fields appropriately.
14431541Srgrimes	 */
14441541Srgrimes	fromcp = *dposp;
14451541Srgrimes	tocp = cnp->cn_pnbuf;
14461541Srgrimes	md = *mdp;
14471541Srgrimes	rem = mtod(md, caddr_t) + md->m_len - fromcp;
14481541Srgrimes	cnp->cn_hash = 0;
14491541Srgrimes	for (i = 0; i < len; i++) {
14501541Srgrimes		while (rem == 0) {
14511541Srgrimes			md = md->m_next;
14521541Srgrimes			if (md == NULL) {
14531541Srgrimes				error = EBADRPC;
14541541Srgrimes				goto out;
14551541Srgrimes			}
14561541Srgrimes			fromcp = mtod(md, caddr_t);
14571541Srgrimes			rem = md->m_len;
14581541Srgrimes		}
145927446Sdfr		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
14609336Sdfr			error = EACCES;
14611541Srgrimes			goto out;
14621541Srgrimes		}
14631541Srgrimes		cnp->cn_hash += (unsigned char)*fromcp;
14641541Srgrimes		*tocp++ = *fromcp++;
14651541Srgrimes		rem--;
14661541Srgrimes	}
14671541Srgrimes	*tocp = '\0';
14681541Srgrimes	*mdp = md;
14691541Srgrimes	*dposp = fromcp;
14701541Srgrimes	len = nfsm_rndup(len)-len;
14711541Srgrimes	if (len > 0) {
14721541Srgrimes		if (rem >= len)
14731541Srgrimes			*dposp += len;
147427609Sdfr		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
14759336Sdfr			goto out;
14761541Srgrimes	}
147727446Sdfr
14781541Srgrimes	/*
14791541Srgrimes	 * Extract and set starting directory.
14801541Srgrimes	 */
148127446Sdfr	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
148227446Sdfr	    nam, &rdonly, kerbflag, pubflag);
148327446Sdfr	if (error)
14841541Srgrimes		goto out;
14851541Srgrimes	if (dp->v_type != VDIR) {
148617761Sdyson		vrele(dp);
14871541Srgrimes		error = ENOTDIR;
14881541Srgrimes		goto out;
14891541Srgrimes	}
149027446Sdfr
149127446Sdfr	if (rdonly)
149227446Sdfr		cnp->cn_flags |= RDONLY;
149327446Sdfr
149427609Sdfr	*retdirp = dp;
149527609Sdfr
149627446Sdfr	if (pubflag) {
149727446Sdfr		/*
149827446Sdfr		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
149927446Sdfr		 * and the 'native path' indicator.
150027446Sdfr		 */
150129653Sdyson		cp = zalloc(namei_zone);
150227446Sdfr		fromcp = cnp->cn_pnbuf;
150327446Sdfr		tocp = cp;
150427446Sdfr		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
150527446Sdfr			switch ((unsigned char)*fromcp) {
150627446Sdfr			case WEBNFS_NATIVE_CHAR:
150727446Sdfr				/*
150827446Sdfr				 * 'Native' path for us is the same
150927446Sdfr				 * as a path according to the NFS spec,
151027446Sdfr				 * just skip the escape char.
151127446Sdfr				 */
151227446Sdfr				fromcp++;
151327446Sdfr				break;
151427446Sdfr			/*
151527446Sdfr			 * More may be added in the future, range 0x80-0xff
151627446Sdfr			 */
151727446Sdfr			default:
151827446Sdfr				error = EIO;
151929653Sdyson				zfree(namei_zone, cp);
152027446Sdfr				goto out;
152127446Sdfr			}
152227446Sdfr		}
152327446Sdfr		/*
152427446Sdfr		 * Translate the '%' escapes, URL-style.
152527446Sdfr		 */
152627446Sdfr		while (*fromcp != '\0') {
152727446Sdfr			if (*fromcp == WEBNFS_ESC_CHAR) {
152827446Sdfr				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
152927446Sdfr					fromcp++;
153027446Sdfr					*tocp++ = HEXSTRTOI(fromcp);
153127446Sdfr					fromcp += 2;
153227446Sdfr					continue;
153327446Sdfr				} else {
153427446Sdfr					error = ENOENT;
153529653Sdyson					zfree(namei_zone, cp);
153627446Sdfr					goto out;
153727446Sdfr				}
153827446Sdfr			} else
153927446Sdfr				*tocp++ = *fromcp++;
154027446Sdfr		}
154127446Sdfr		*tocp = '\0';
154229653Sdyson		zfree(namei_zone, cnp->cn_pnbuf);
154327446Sdfr		cnp->cn_pnbuf = cp;
154427446Sdfr	}
154527446Sdfr
154627446Sdfr	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
154727446Sdfr	ndp->ni_segflg = UIO_SYSSPACE;
154827446Sdfr
154927446Sdfr	if (pubflag) {
155027446Sdfr		ndp->ni_rootdir = rootvnode;
155127446Sdfr		ndp->ni_loopcnt = 0;
155227446Sdfr		if (cnp->cn_pnbuf[0] == '/')
155327446Sdfr			dp = rootvnode;
155427446Sdfr	} else {
155527609Sdfr		cnp->cn_flags |= NOCROSSMOUNT;
155627446Sdfr	}
155727446Sdfr
155827446Sdfr	cnp->cn_proc = p;
15599336Sdfr	VREF(dp);
156027446Sdfr
156127609Sdfr    for (;;) {
156227446Sdfr	cnp->cn_nameptr = cnp->cn_pnbuf;
15631541Srgrimes	ndp->ni_startdir = dp;
15641541Srgrimes	/*
15651541Srgrimes	 * And call lookup() to do the real work
15661541Srgrimes	 */
156727609Sdfr	error = lookup(ndp);
156827609Sdfr	if (error)
156927446Sdfr		break;
15701541Srgrimes	/*
15711541Srgrimes	 * Check for encountering a symbolic link
15721541Srgrimes	 */
157327446Sdfr	if ((cnp->cn_flags & ISSYMLINK) == 0) {
157427446Sdfr		nfsrv_object_create(ndp->ni_vp);
157527446Sdfr		if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
157627446Sdfr			cnp->cn_flags |= HASBUF;
157727446Sdfr			return (0);
157827446Sdfr		}
157927446Sdfr		break;
158027446Sdfr	} else {
15811541Srgrimes		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
158227446Sdfr			VOP_UNLOCK(ndp->ni_dvp, 0, p);
158327446Sdfr		if (!pubflag) {
158427446Sdfr			vrele(ndp->ni_dvp);
158527446Sdfr			vput(ndp->ni_vp);
158627446Sdfr			ndp->ni_vp = NULL;
158727446Sdfr			error = EINVAL;
158827446Sdfr			break;
158927446Sdfr		}
159027446Sdfr
159127446Sdfr		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
159227446Sdfr			error = ELOOP;
159327446Sdfr			break;
159427446Sdfr		}
159527609Sdfr		if (ndp->ni_pathlen > 1)
159629653Sdyson			cp = zalloc(namei_zone);
15971541Srgrimes		else
159827446Sdfr			cp = cnp->cn_pnbuf;
159927446Sdfr		aiov.iov_base = cp;
160027446Sdfr		aiov.iov_len = MAXPATHLEN;
160127446Sdfr		auio.uio_iov = &aiov;
160227446Sdfr		auio.uio_iovcnt = 1;
160327446Sdfr		auio.uio_offset = 0;
160427446Sdfr		auio.uio_rw = UIO_READ;
160527446Sdfr		auio.uio_segflg = UIO_SYSSPACE;
160627446Sdfr		auio.uio_procp = (struct proc *)0;
160727446Sdfr		auio.uio_resid = MAXPATHLEN;
160827446Sdfr		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
160927446Sdfr		if (error) {
161027446Sdfr		badlink:
161127446Sdfr			if (ndp->ni_pathlen > 1)
161229653Sdyson				zfree(namei_zone, cp);
161327446Sdfr			break;
161427446Sdfr		}
161527446Sdfr		linklen = MAXPATHLEN - auio.uio_resid;
161627446Sdfr		if (linklen == 0) {
161727446Sdfr			error = ENOENT;
161827446Sdfr			goto badlink;
161927446Sdfr		}
162027446Sdfr		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
162127446Sdfr			error = ENAMETOOLONG;
162227446Sdfr			goto badlink;
162327446Sdfr		}
162427446Sdfr		if (ndp->ni_pathlen > 1) {
162527446Sdfr			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
162629653Sdyson			zfree(namei_zone, cnp->cn_pnbuf);
162727446Sdfr			cnp->cn_pnbuf = cp;
162827446Sdfr		} else
162927446Sdfr			cnp->cn_pnbuf[linklen] = '\0';
163027446Sdfr		ndp->ni_pathlen += linklen;
16311541Srgrimes		vput(ndp->ni_vp);
163227446Sdfr		dp = ndp->ni_dvp;
163327446Sdfr		/*
163427446Sdfr		 * Check if root directory should replace current directory.
163527446Sdfr		 */
163627446Sdfr		if (cnp->cn_pnbuf[0] == '/') {
163727446Sdfr			vrele(dp);
163827446Sdfr			dp = ndp->ni_rootdir;
163927446Sdfr			VREF(dp);
164027446Sdfr		}
16411541Srgrimes	}
164227609Sdfr   }
16431541Srgrimesout:
164429653Sdyson	zfree(namei_zone, cnp->cn_pnbuf);
16451541Srgrimes	return (error);
16461541Srgrimes}
16471541Srgrimes
16481541Srgrimes/*
16491541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long
16501541Srgrimes * boundary and only trims off the back end
16511541Srgrimes */
16521541Srgrimesvoid
16531541Srgrimesnfsm_adj(mp, len, nul)
16541541Srgrimes	struct mbuf *mp;
16551541Srgrimes	register int len;
16561541Srgrimes	int nul;
16571541Srgrimes{
16581541Srgrimes	register struct mbuf *m;
16591541Srgrimes	register int count, i;
16601541Srgrimes	register char *cp;
16611541Srgrimes
16621541Srgrimes	/*
16631541Srgrimes	 * Trim from tail.  Scan the mbuf chain,
16641541Srgrimes	 * calculating its length and finding the last mbuf.
16651541Srgrimes	 * If the adjustment only affects this mbuf, then just
16661541Srgrimes	 * adjust and return.  Otherwise, rescan and truncate
16671541Srgrimes	 * after the remaining size.
16681541Srgrimes	 */
16691541Srgrimes	count = 0;
16701541Srgrimes	m = mp;
16711541Srgrimes	for (;;) {
16721541Srgrimes		count += m->m_len;
16731541Srgrimes		if (m->m_next == (struct mbuf *)0)
16741541Srgrimes			break;
16751541Srgrimes		m = m->m_next;
16761541Srgrimes	}
16771541Srgrimes	if (m->m_len > len) {
16781541Srgrimes		m->m_len -= len;
16791541Srgrimes		if (nul > 0) {
16801541Srgrimes			cp = mtod(m, caddr_t)+m->m_len-nul;
16811541Srgrimes			for (i = 0; i < nul; i++)
16821541Srgrimes				*cp++ = '\0';
16831541Srgrimes		}
16841541Srgrimes		return;
16851541Srgrimes	}
16861541Srgrimes	count -= len;
16871541Srgrimes	if (count < 0)
16881541Srgrimes		count = 0;
16891541Srgrimes	/*
16901541Srgrimes	 * Correct length for chain is "count".
16911541Srgrimes	 * Find the mbuf with last data, adjust its length,
16921541Srgrimes	 * and toss data from remaining mbufs on chain.
16931541Srgrimes	 */
16941541Srgrimes	for (m = mp; m; m = m->m_next) {
16951541Srgrimes		if (m->m_len >= count) {
16961541Srgrimes			m->m_len = count;
16971541Srgrimes			if (nul > 0) {
16981541Srgrimes				cp = mtod(m, caddr_t)+m->m_len-nul;
16991541Srgrimes				for (i = 0; i < nul; i++)
17001541Srgrimes					*cp++ = '\0';
17011541Srgrimes			}
17021541Srgrimes			break;
17031541Srgrimes		}
17041541Srgrimes		count -= m->m_len;
17051541Srgrimes	}
17063305Sphk	for (m = m->m_next;m;m = m->m_next)
17071541Srgrimes		m->m_len = 0;
17081541Srgrimes}
17091541Srgrimes
17101541Srgrimes/*
17119336Sdfr * Make these functions instead of macros, so that the kernel text size
17129336Sdfr * doesn't get too big...
17139336Sdfr */
17149336Sdfrvoid
17159336Sdfrnfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
17169336Sdfr	struct nfsrv_descript *nfsd;
17179336Sdfr	int before_ret;
17189336Sdfr	register struct vattr *before_vap;
17199336Sdfr	int after_ret;
17209336Sdfr	struct vattr *after_vap;
17219336Sdfr	struct mbuf **mbp;
17229336Sdfr	char **bposp;
17239336Sdfr{
17249336Sdfr	register struct mbuf *mb = *mbp, *mb2;
17259336Sdfr	register char *bpos = *bposp;
17269336Sdfr	register u_long *tl;
17279336Sdfr
17289336Sdfr	if (before_ret) {
17299336Sdfr		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
17309336Sdfr		*tl = nfs_false;
17319336Sdfr	} else {
17329336Sdfr		nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
17339336Sdfr		*tl++ = nfs_true;
17349336Sdfr		txdr_hyper(&(before_vap->va_size), tl);
17359336Sdfr		tl += 2;
17369336Sdfr		txdr_nfsv3time(&(before_vap->va_mtime), tl);
17379336Sdfr		tl += 2;
17389336Sdfr		txdr_nfsv3time(&(before_vap->va_ctime), tl);
17399336Sdfr	}
17409336Sdfr	*bposp = bpos;
17419336Sdfr	*mbp = mb;
17429336Sdfr	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
17439336Sdfr}
17449336Sdfr
17459336Sdfrvoid
17469336Sdfrnfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
17479336Sdfr	struct nfsrv_descript *nfsd;
17489336Sdfr	int after_ret;
17499336Sdfr	struct vattr *after_vap;
17509336Sdfr	struct mbuf **mbp;
17519336Sdfr	char **bposp;
17529336Sdfr{
17539336Sdfr	register struct mbuf *mb = *mbp, *mb2;
17549336Sdfr	register char *bpos = *bposp;
17559336Sdfr	register u_long *tl;
17569336Sdfr	register struct nfs_fattr *fp;
17579336Sdfr
17589336Sdfr	if (after_ret) {
17599336Sdfr		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
17609336Sdfr		*tl = nfs_false;
17619336Sdfr	} else {
17629336Sdfr		nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
17639336Sdfr		*tl++ = nfs_true;
17649336Sdfr		fp = (struct nfs_fattr *)tl;
17659336Sdfr		nfsm_srvfattr(nfsd, after_vap, fp);
17669336Sdfr	}
17679336Sdfr	*mbp = mb;
17689336Sdfr	*bposp = bpos;
17699336Sdfr}
17709336Sdfr
17719336Sdfrvoid
17729336Sdfrnfsm_srvfattr(nfsd, vap, fp)
17739336Sdfr	register struct nfsrv_descript *nfsd;
17749336Sdfr	register struct vattr *vap;
17759336Sdfr	register struct nfs_fattr *fp;
17769336Sdfr{
17779336Sdfr
17789336Sdfr	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
17799336Sdfr	fp->fa_uid = txdr_unsigned(vap->va_uid);
17809336Sdfr	fp->fa_gid = txdr_unsigned(vap->va_gid);
17819336Sdfr	if (nfsd->nd_flag & ND_NFSV3) {
17829336Sdfr		fp->fa_type = vtonfsv3_type(vap->va_type);
17839336Sdfr		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
17849336Sdfr		txdr_hyper(&vap->va_size, &fp->fa3_size);
17859336Sdfr		txdr_hyper(&vap->va_bytes, &fp->fa3_used);
17869336Sdfr		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
17879336Sdfr		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
17889336Sdfr		fp->fa3_fsid.nfsuquad[0] = 0;
17899336Sdfr		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
17909336Sdfr		fp->fa3_fileid.nfsuquad[0] = 0;
17919336Sdfr		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
17929336Sdfr		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
17939336Sdfr		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
17949336Sdfr		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
17959336Sdfr	} else {
17969336Sdfr		fp->fa_type = vtonfsv2_type(vap->va_type);
17979336Sdfr		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
17989336Sdfr		fp->fa2_size = txdr_unsigned(vap->va_size);
17999336Sdfr		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
18009336Sdfr		if (vap->va_type == VFIFO)
18019336Sdfr			fp->fa2_rdev = 0xffffffff;
18029336Sdfr		else
18039336Sdfr			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
18049336Sdfr		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
18059336Sdfr		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
18069336Sdfr		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
18079336Sdfr		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
18089336Sdfr		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
18099336Sdfr		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
18109336Sdfr	}
18119336Sdfr}
18129336Sdfr
18139336Sdfr/*
18141541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
18151541Srgrimes * 	- look up fsid in mount list (if not found ret error)
18161541Srgrimes *	- get vp and export rights by calling VFS_FHTOVP()
18171541Srgrimes *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
18181541Srgrimes *	- if not lockflag unlock it with VOP_UNLOCK()
18191541Srgrimes */
18201549Srgrimesint
182127446Sdfrnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
18221541Srgrimes	fhandle_t *fhp;
18231541Srgrimes	int lockflag;
18241541Srgrimes	struct vnode **vpp;
18251541Srgrimes	struct ucred *cred;
18261541Srgrimes	struct nfssvc_sock *slp;
182728270Swollman	struct sockaddr *nam;
18281541Srgrimes	int *rdonlyp;
18299336Sdfr	int kerbflag;
183027446Sdfr	int pubflag;
18311541Srgrimes{
183222521Sdyson	struct proc *p = curproc; /* XXX */
18331541Srgrimes	register struct mount *mp;
18341541Srgrimes	register int i;
18351541Srgrimes	struct ucred *credanon;
18361541Srgrimes	int error, exflags;
18371541Srgrimes
18381541Srgrimes	*vpp = (struct vnode *)0;
183927446Sdfr
184027446Sdfr	if (nfs_ispublicfh(fhp)) {
184127446Sdfr		if (!pubflag || !nfs_pub.np_valid)
184227446Sdfr			return (ESTALE);
184327446Sdfr		fhp = &nfs_pub.np_handle;
184427446Sdfr	}
184527446Sdfr
184622521Sdyson	mp = vfs_getvfs(&fhp->fh_fsid);
18473305Sphk	if (!mp)
18481541Srgrimes		return (ESTALE);
18493305Sphk	error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
18503305Sphk	if (error)
18511541Srgrimes		return (error);
18521541Srgrimes	/*
18531541Srgrimes	 * Check/setup credentials.
18541541Srgrimes	 */
18551541Srgrimes	if (exflags & MNT_EXKERB) {
18569336Sdfr		if (!kerbflag) {
18571541Srgrimes			vput(*vpp);
18589336Sdfr			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
18591541Srgrimes		}
18609336Sdfr	} else if (kerbflag) {
18619336Sdfr		vput(*vpp);
18629336Sdfr		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
18631541Srgrimes	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
18641541Srgrimes		cred->cr_uid = credanon->cr_uid;
18651541Srgrimes		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
18661541Srgrimes			cred->cr_groups[i] = credanon->cr_groups[i];
18673664Sphk		cred->cr_ngroups = i;
18681541Srgrimes	}
18691541Srgrimes	if (exflags & MNT_EXRDONLY)
18701541Srgrimes		*rdonlyp = 1;
18711541Srgrimes	else
18721541Srgrimes		*rdonlyp = 0;
18737969Sdyson
187417761Sdyson	nfsrv_object_create(*vpp);
18757969Sdyson
18761541Srgrimes	if (!lockflag)
187722521Sdyson		VOP_UNLOCK(*vpp, 0, p);
18781541Srgrimes	return (0);
18791541Srgrimes}
18801541Srgrimes
188127446Sdfr
188227446Sdfr/*
188327446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this
188427446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
188527446Sdfr * transformed this to all zeroes in both cases, so check for it.
188627446Sdfr */
188727446Sdfrint
188827446Sdfrnfs_ispublicfh(fhp)
188927446Sdfr	fhandle_t *fhp;
189027446Sdfr{
189127446Sdfr	char *cp = (char *)fhp;
189227446Sdfr	int i;
189327446Sdfr
189427446Sdfr	for (i = 0; i < NFSX_V3FH; i++)
189527446Sdfr		if (*cp++ != 0)
189627446Sdfr			return (FALSE);
189727446Sdfr	return (TRUE);
189827446Sdfr}
189927446Sdfr
190013416Sphk#endif /* NFS_NOSERVER */
19011541Srgrimes/*
19021541Srgrimes * This function compares two net addresses by family and returns TRUE
19031541Srgrimes * if they are the same host.
19041541Srgrimes * If there is any doubt, return FALSE.
19051541Srgrimes * The AF_INET family is handled as a special case so that address mbufs
19061541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes.
19071541Srgrimes */
19081549Srgrimesint
19091541Srgrimesnetaddr_match(family, haddr, nam)
19101541Srgrimes	int family;
19111541Srgrimes	union nethostaddr *haddr;
191228270Swollman	struct sockaddr *nam;
19131541Srgrimes{
19141541Srgrimes	register struct sockaddr_in *inetaddr;
19151541Srgrimes
19161541Srgrimes	switch (family) {
19171541Srgrimes	case AF_INET:
191828270Swollman		inetaddr = (struct sockaddr_in *)nam;
19191541Srgrimes		if (inetaddr->sin_family == AF_INET &&
19201541Srgrimes		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
19211541Srgrimes			return (1);
19221541Srgrimes		break;
19231541Srgrimes#ifdef ISO
19241541Srgrimes	case AF_ISO:
19251541Srgrimes	    {
19261541Srgrimes		register struct sockaddr_iso *isoaddr1, *isoaddr2;
19271541Srgrimes
192828270Swollman		isoaddr1 = (struct sockaddr_iso *)nam;
192928270Swollman		isoaddr2 = (struct sockaddr_iso *)haddr->had_nam;
19301541Srgrimes		if (isoaddr1->siso_family == AF_ISO &&
19311541Srgrimes		    isoaddr1->siso_nlen > 0 &&
19321541Srgrimes		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
19331541Srgrimes		    SAME_ISOADDR(isoaddr1, isoaddr2))
19341541Srgrimes			return (1);
19351541Srgrimes		break;
19361541Srgrimes	    }
19371541Srgrimes#endif	/* ISO */
19381541Srgrimes	default:
19391541Srgrimes		break;
19401541Srgrimes	};
19411541Srgrimes	return (0);
19421541Srgrimes}
19435455Sdg
19449336Sdfrstatic nfsuint64 nfs_nullcookie = { 0, 0 };
19459336Sdfr/*
19469336Sdfr * This function finds the directory cookie that corresponds to the
19479336Sdfr * logical byte offset given.
19489336Sdfr */
19499336Sdfrnfsuint64 *
19509336Sdfrnfs_getcookie(np, off, add)
19519336Sdfr	register struct nfsnode *np;
19529336Sdfr	off_t off;
19539336Sdfr	int add;
19549336Sdfr{
19559336Sdfr	register struct nfsdmap *dp, *dp2;
19569336Sdfr	register int pos;
19579336Sdfr
19589336Sdfr	pos = off / NFS_DIRBLKSIZ;
19599336Sdfr	if (pos == 0) {
19609336Sdfr#ifdef DIAGNOSTIC
19619336Sdfr		if (add)
19629336Sdfr			panic("nfs getcookie add at 0");
19639336Sdfr#endif
19649336Sdfr		return (&nfs_nullcookie);
19659336Sdfr	}
19669336Sdfr	pos--;
19679336Sdfr	dp = np->n_cookies.lh_first;
19689336Sdfr	if (!dp) {
19699336Sdfr		if (add) {
19709336Sdfr			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
19719336Sdfr				M_NFSDIROFF, M_WAITOK);
19729336Sdfr			dp->ndm_eocookie = 0;
19739336Sdfr			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
19749336Sdfr		} else
19759336Sdfr			return ((nfsuint64 *)0);
19769336Sdfr	}
19779336Sdfr	while (pos >= NFSNUMCOOKIES) {
19789336Sdfr		pos -= NFSNUMCOOKIES;
19799336Sdfr		if (dp->ndm_list.le_next) {
19809336Sdfr			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
19819336Sdfr				pos >= dp->ndm_eocookie)
19829336Sdfr				return ((nfsuint64 *)0);
19839336Sdfr			dp = dp->ndm_list.le_next;
19849336Sdfr		} else if (add) {
19859336Sdfr			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
19869336Sdfr				M_NFSDIROFF, M_WAITOK);
19879336Sdfr			dp2->ndm_eocookie = 0;
19889336Sdfr			LIST_INSERT_AFTER(dp, dp2, ndm_list);
19899336Sdfr			dp = dp2;
19909336Sdfr		} else
19919336Sdfr			return ((nfsuint64 *)0);
19929336Sdfr	}
19939336Sdfr	if (pos >= dp->ndm_eocookie) {
19949336Sdfr		if (add)
19959336Sdfr			dp->ndm_eocookie = pos + 1;
19969336Sdfr		else
19979336Sdfr			return ((nfsuint64 *)0);
19989336Sdfr	}
19999336Sdfr	return (&dp->ndm_cookies[pos]);
20009336Sdfr}
20019336Sdfr
20029336Sdfr/*
20039336Sdfr * Invalidate cached directory information, except for the actual directory
20049336Sdfr * blocks (which are invalidated separately).
20059336Sdfr * Done mainly to avoid the use of stale offset cookies.
20069336Sdfr */
20079336Sdfrvoid
20089336Sdfrnfs_invaldir(vp)
20099336Sdfr	register struct vnode *vp;
20109336Sdfr{
20119336Sdfr	register struct nfsnode *np = VTONFS(vp);
20129336Sdfr
20139336Sdfr#ifdef DIAGNOSTIC
20149336Sdfr	if (vp->v_type != VDIR)
20159336Sdfr		panic("nfs: invaldir not dir");
20169336Sdfr#endif
20179336Sdfr	np->n_direofoffset = 0;
20189336Sdfr	np->n_cookieverf.nfsuquad[0] = 0;
20199336Sdfr	np->n_cookieverf.nfsuquad[1] = 0;
20209336Sdfr	if (np->n_cookies.lh_first)
20219336Sdfr		np->n_cookies.lh_first->ndm_eocookie = 0;
20229336Sdfr}
20239336Sdfr
20249336Sdfr/*
20259336Sdfr * The write verifier has changed (probably due to a server reboot), so all
20269336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
20279336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
20289336Sdfr * flag. Once done the new write verifier can be set for the mount point.
20299336Sdfr */
20309336Sdfrvoid
20319336Sdfrnfs_clearcommit(mp)
20329336Sdfr	struct mount *mp;
20339336Sdfr{
20349336Sdfr	register struct vnode *vp, *nvp;
20359336Sdfr	register struct buf *bp, *nbp;
20369336Sdfr	int s;
20379336Sdfr
20389336Sdfr	s = splbio();
20399336Sdfrloop:
20409336Sdfr	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
20419336Sdfr		if (vp->v_mount != mp)	/* Paranoia */
20429336Sdfr			goto loop;
20439336Sdfr		nvp = vp->v_mntvnodes.le_next;
20449336Sdfr		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
20459336Sdfr			nbp = bp->b_vnbufs.le_next;
20469336Sdfr			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
20479336Sdfr				== (B_DELWRI | B_NEEDCOMMIT))
20489336Sdfr				bp->b_flags &= ~B_NEEDCOMMIT;
20499336Sdfr		}
20509336Sdfr	}
20519336Sdfr	splx(s);
20529336Sdfr}
20539336Sdfr
205413416Sphk#ifndef NFS_NOSERVER
20559336Sdfr/*
20569336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error
20579336Sdfr * numbers not specified for the associated procedure.
20589336Sdfr */
20595455Sdgint
20609336Sdfrnfsrv_errmap(nd, err)
20619336Sdfr	struct nfsrv_descript *nd;
20629336Sdfr	register int err;
20639336Sdfr{
20649336Sdfr	register short *defaulterrp, *errp;
20659336Sdfr
20669336Sdfr	if (nd->nd_flag & ND_NFSV3) {
20679336Sdfr	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
20689336Sdfr		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
20699336Sdfr		while (*++errp) {
20709336Sdfr			if (*errp == err)
20719336Sdfr				return (err);
20729336Sdfr			else if (*errp > err)
20739336Sdfr				break;
20749336Sdfr		}
20759336Sdfr		return ((int)*defaulterrp);
20769336Sdfr	    } else
20779336Sdfr		return (err & 0xffff);
20789336Sdfr	}
20799336Sdfr	if (err <= ELAST)
20809336Sdfr		return ((int)nfsrv_v2errmap[err - 1]);
20819336Sdfr	return (NFSERR_IO);
20829336Sdfr}
20839336Sdfr
20849336Sdfrint
208531886Sbdenfsrv_object_create(vp)
208631886Sbde	struct vnode *vp;
208731886Sbde{
20885455Sdg
208931886Sbde	if (vp == NULL || vp->v_type != VREG)
209031886Sbde		return (1);
209131886Sbde	return (vfs_object_create(vp, curproc,
209231886Sbde				  curproc ? curproc->p_ucred : NULL, 1));
20935455Sdg}
209413416Sphk#endif /* NFS_NOSERVER */
2095