nfs_subs.c revision 60041
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 *
3636503Speter *	@(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
3750477Speter * $FreeBSD: head/sys/nfsclient/nfs_subs.c 60041 2000-05-05 09:59:14Z phk $
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>
4648274Speter#include <sys/systm.h>
4748274Speter#include <sys/kernel.h>
4860041Sphk#include <sys/bio.h>
4931886Sbde#include <sys/buf.h>
501541Srgrimes#include <sys/proc.h>
511541Srgrimes#include <sys/mount.h>
521541Srgrimes#include <sys/vnode.h>
531541Srgrimes#include <sys/namei.h>
541541Srgrimes#include <sys/mbuf.h>
551541Srgrimes#include <sys/socket.h>
561541Srgrimes#include <sys/stat.h>
579336Sdfr#include <sys/malloc.h>
582997Swollman#include <sys/sysent.h>
592997Swollman#include <sys/syscall.h>
601541Srgrimes
613305Sphk#include <vm/vm.h>
6212662Sdg#include <vm/vm_object.h>
6312662Sdg#include <vm/vm_extern.h>
6432011Sbde#include <vm/vm_zone.h>
653305Sphk
661541Srgrimes#include <nfs/rpcv2.h>
679336Sdfr#include <nfs/nfsproto.h>
6830808Sbde#include <nfs/nfs.h>
691541Srgrimes#include <nfs/nfsnode.h>
701541Srgrimes#include <nfs/xdr_subs.h>
711541Srgrimes#include <nfs/nfsm_subs.h>
721541Srgrimes#include <nfs/nfsmount.h>
731541Srgrimes#include <nfs/nqnfs.h>
741541Srgrimes#include <nfs/nfsrtt.h>
751541Srgrimes
761541Srgrimes#include <netinet/in.h>
771541Srgrimes
781541Srgrimes/*
791541Srgrimes * Data items converted to xdr at startup, since they are constant
801541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps
811541Srgrimes */
8236541Speteru_int32_t nfs_xdrneg1;
8336541Speteru_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
849336Sdfr	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
851541Srgrimes	rpc_auth_kerb;
8636541Speteru_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false;
871541Srgrimes
881541Srgrimes/* And other global data */
8936541Speterstatic u_int32_t nfs_xid = 0;
9012911Sphkstatic enum vtype nv2tov_type[8]= {
9112911Sphk	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON,  VNON
9212911Sphk};
9312911Sphkenum vtype nv3tov_type[8]= {
9412911Sphk	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
9512911Sphk};
9612911Sphk
979336Sdfrint nfs_ticks;
9842957Sdillonint nfs_pbuf_freecnt = -1;	/* start out unlimited */
999336Sdfr
1009759Sbdestruct nfs_reqq nfs_reqq;
1019759Sbdestruct nfssvc_sockhead nfssvc_sockhead;
1029759Sbdeint nfssvc_sockhead_flag;
1039759Sbdestruct nfsd_head nfsd_head;
1049759Sbdeint nfsd_head_flag;
1059759Sbdestruct nfs_bufq nfs_bufq;
1069759Sbdestruct nqtimerhead nqtimerhead;
1079759Sbdestruct nqfhhashhead *nqfhhashtbl;
1089759Sbdeu_long nqfhhash;
1099759Sbde
11038894Sbdestatic void (*nfs_prev_lease_updatetime) __P((int));
11138894Sbdestatic int nfs_prev_nfssvc_sy_narg;
11238894Sbdestatic sy_call_t *nfs_prev_nfssvc_sy_call;
11338894Sbde
11413416Sphk#ifndef NFS_NOSERVER
11538894Sbde
11638894Sbdestatic vop_t *nfs_prev_vop_lease_check;
11738894Sbde
1189336Sdfr/*
1199336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers.
1209336Sdfr */
1219336Sdfrint nfsv3_procid[NFS_NPROCS] = {
1229336Sdfr	NFSPROC_NULL,
1239336Sdfr	NFSPROC_GETATTR,
1249336Sdfr	NFSPROC_SETATTR,
1259336Sdfr	NFSPROC_NOOP,
1269336Sdfr	NFSPROC_LOOKUP,
1279336Sdfr	NFSPROC_READLINK,
1289336Sdfr	NFSPROC_READ,
1299336Sdfr	NFSPROC_NOOP,
1309336Sdfr	NFSPROC_WRITE,
1319336Sdfr	NFSPROC_CREATE,
1329336Sdfr	NFSPROC_REMOVE,
1339336Sdfr	NFSPROC_RENAME,
1349336Sdfr	NFSPROC_LINK,
1359336Sdfr	NFSPROC_SYMLINK,
1369336Sdfr	NFSPROC_MKDIR,
1379336Sdfr	NFSPROC_RMDIR,
1389336Sdfr	NFSPROC_READDIR,
1399336Sdfr	NFSPROC_FSSTAT,
1409336Sdfr	NFSPROC_NOOP,
1419336Sdfr	NFSPROC_NOOP,
1429336Sdfr	NFSPROC_NOOP,
1439336Sdfr	NFSPROC_NOOP,
1449336Sdfr	NFSPROC_NOOP,
1459336Sdfr	NFSPROC_NOOP,
1469336Sdfr	NFSPROC_NOOP,
1479336Sdfr	NFSPROC_NOOP
1489336Sdfr};
1499336Sdfr
15013416Sphk#endif /* NFS_NOSERVER */
1519336Sdfr/*
1529336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers
1539336Sdfr */
1549336Sdfrint nfsv2_procid[NFS_NPROCS] = {
1559336Sdfr	NFSV2PROC_NULL,
1569336Sdfr	NFSV2PROC_GETATTR,
1579336Sdfr	NFSV2PROC_SETATTR,
1589336Sdfr	NFSV2PROC_LOOKUP,
1599336Sdfr	NFSV2PROC_NOOP,
1609336Sdfr	NFSV2PROC_READLINK,
1619336Sdfr	NFSV2PROC_READ,
1629336Sdfr	NFSV2PROC_WRITE,
1639336Sdfr	NFSV2PROC_CREATE,
1649336Sdfr	NFSV2PROC_MKDIR,
1659336Sdfr	NFSV2PROC_SYMLINK,
1669336Sdfr	NFSV2PROC_CREATE,
1679336Sdfr	NFSV2PROC_REMOVE,
1689336Sdfr	NFSV2PROC_RMDIR,
1699336Sdfr	NFSV2PROC_RENAME,
1709336Sdfr	NFSV2PROC_LINK,
1719336Sdfr	NFSV2PROC_READDIR,
1729336Sdfr	NFSV2PROC_NOOP,
1739336Sdfr	NFSV2PROC_STATFS,
1749336Sdfr	NFSV2PROC_NOOP,
1759336Sdfr	NFSV2PROC_NOOP,
1769336Sdfr	NFSV2PROC_NOOP,
1779336Sdfr	NFSV2PROC_NOOP,
1789336Sdfr	NFSV2PROC_NOOP,
1799336Sdfr	NFSV2PROC_NOOP,
1809336Sdfr	NFSV2PROC_NOOP,
1819336Sdfr};
1829336Sdfr
18313416Sphk#ifndef NFS_NOSERVER
1849336Sdfr/*
1859336Sdfr * Maps errno values to nfs error numbers.
1869336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in
1879336Sdfr * RFC 1094.
1889336Sdfr */
1899336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = {
1909336Sdfr  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1919336Sdfr  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1929336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
1939336Sdfr  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
1949336Sdfr  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1959336Sdfr  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
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_IO,	NFSERR_IO,	NFSERR_IO,
2019336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
2029336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
2039336Sdfr  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
2049336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
2059336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
20641796Sdt  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
20741796Sdt  NFSERR_IO /* << Last is 86 */
2089336Sdfr};
2099336Sdfr
2109336Sdfr/*
2119336Sdfr * Maps errno values to nfs error numbers.
2129336Sdfr * Although it is not obvious whether or not NFS clients really care if
2139336Sdfr * a returned error value is in the specified list for the procedure, the
2149336Sdfr * safest thing to do is filter them appropriately. For Version 2, the
2159336Sdfr * X/Open XNFS document is the only specification that defines error values
2169336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs),
2179336Sdfr * so I have decided to not do this for Version 2.
2189336Sdfr * The first entry is the default error return and the rest are the valid
2199336Sdfr * errors for that RPC in increasing numeric order.
2209336Sdfr */
2219336Sdfrstatic short nfsv3err_null[] = {
2229336Sdfr	0,
2239336Sdfr	0,
2249336Sdfr};
2259336Sdfr
2269336Sdfrstatic short nfsv3err_getattr[] = {
2279336Sdfr	NFSERR_IO,
2289336Sdfr	NFSERR_IO,
2299336Sdfr	NFSERR_STALE,
2309336Sdfr	NFSERR_BADHANDLE,
2319336Sdfr	NFSERR_SERVERFAULT,
2329336Sdfr	0,
2339336Sdfr};
2349336Sdfr
2359336Sdfrstatic short nfsv3err_setattr[] = {
2369336Sdfr	NFSERR_IO,
2379336Sdfr	NFSERR_PERM,
2389336Sdfr	NFSERR_IO,
2399336Sdfr	NFSERR_ACCES,
2409336Sdfr	NFSERR_INVAL,
2419336Sdfr	NFSERR_NOSPC,
2429336Sdfr	NFSERR_ROFS,
2439336Sdfr	NFSERR_DQUOT,
2449336Sdfr	NFSERR_STALE,
2459336Sdfr	NFSERR_BADHANDLE,
2469336Sdfr	NFSERR_NOT_SYNC,
2479336Sdfr	NFSERR_SERVERFAULT,
2489336Sdfr	0,
2499336Sdfr};
2509336Sdfr
2519336Sdfrstatic short nfsv3err_lookup[] = {
2529336Sdfr	NFSERR_IO,
2539336Sdfr	NFSERR_NOENT,
2549336Sdfr	NFSERR_IO,
2559336Sdfr	NFSERR_ACCES,
2569336Sdfr	NFSERR_NOTDIR,
2579336Sdfr	NFSERR_NAMETOL,
2589336Sdfr	NFSERR_STALE,
2599336Sdfr	NFSERR_BADHANDLE,
2609336Sdfr	NFSERR_SERVERFAULT,
2619336Sdfr	0,
2629336Sdfr};
2639336Sdfr
2649336Sdfrstatic short nfsv3err_access[] = {
2659336Sdfr	NFSERR_IO,
2669336Sdfr	NFSERR_IO,
2679336Sdfr	NFSERR_STALE,
2689336Sdfr	NFSERR_BADHANDLE,
2699336Sdfr	NFSERR_SERVERFAULT,
2709336Sdfr	0,
2719336Sdfr};
2729336Sdfr
2739336Sdfrstatic short nfsv3err_readlink[] = {
2749336Sdfr	NFSERR_IO,
2759336Sdfr	NFSERR_IO,
2769336Sdfr	NFSERR_ACCES,
2779336Sdfr	NFSERR_INVAL,
2789336Sdfr	NFSERR_STALE,
2799336Sdfr	NFSERR_BADHANDLE,
2809336Sdfr	NFSERR_NOTSUPP,
2819336Sdfr	NFSERR_SERVERFAULT,
2829336Sdfr	0,
2839336Sdfr};
2849336Sdfr
2859336Sdfrstatic short nfsv3err_read[] = {
2869336Sdfr	NFSERR_IO,
2879336Sdfr	NFSERR_IO,
2889336Sdfr	NFSERR_NXIO,
2899336Sdfr	NFSERR_ACCES,
2909336Sdfr	NFSERR_INVAL,
2919336Sdfr	NFSERR_STALE,
2929336Sdfr	NFSERR_BADHANDLE,
2939336Sdfr	NFSERR_SERVERFAULT,
2949336Sdfr	0,
2959336Sdfr};
2969336Sdfr
2979336Sdfrstatic short nfsv3err_write[] = {
2989336Sdfr	NFSERR_IO,
2999336Sdfr	NFSERR_IO,
3009336Sdfr	NFSERR_ACCES,
3019336Sdfr	NFSERR_INVAL,
3029336Sdfr	NFSERR_FBIG,
3039336Sdfr	NFSERR_NOSPC,
3049336Sdfr	NFSERR_ROFS,
3059336Sdfr	NFSERR_DQUOT,
3069336Sdfr	NFSERR_STALE,
3079336Sdfr	NFSERR_BADHANDLE,
3089336Sdfr	NFSERR_SERVERFAULT,
3099336Sdfr	0,
3109336Sdfr};
3119336Sdfr
3129336Sdfrstatic short nfsv3err_create[] = {
3139336Sdfr	NFSERR_IO,
3149336Sdfr	NFSERR_IO,
3159336Sdfr	NFSERR_ACCES,
3169336Sdfr	NFSERR_EXIST,
3179336Sdfr	NFSERR_NOTDIR,
3189336Sdfr	NFSERR_NOSPC,
3199336Sdfr	NFSERR_ROFS,
3209336Sdfr	NFSERR_NAMETOL,
3219336Sdfr	NFSERR_DQUOT,
3229336Sdfr	NFSERR_STALE,
3239336Sdfr	NFSERR_BADHANDLE,
3249336Sdfr	NFSERR_NOTSUPP,
3259336Sdfr	NFSERR_SERVERFAULT,
3269336Sdfr	0,
3279336Sdfr};
3289336Sdfr
3299336Sdfrstatic short nfsv3err_mkdir[] = {
3309336Sdfr	NFSERR_IO,
3319336Sdfr	NFSERR_IO,
3329336Sdfr	NFSERR_ACCES,
3339336Sdfr	NFSERR_EXIST,
3349336Sdfr	NFSERR_NOTDIR,
3359336Sdfr	NFSERR_NOSPC,
3369336Sdfr	NFSERR_ROFS,
3379336Sdfr	NFSERR_NAMETOL,
3389336Sdfr	NFSERR_DQUOT,
3399336Sdfr	NFSERR_STALE,
3409336Sdfr	NFSERR_BADHANDLE,
3419336Sdfr	NFSERR_NOTSUPP,
3429336Sdfr	NFSERR_SERVERFAULT,
3439336Sdfr	0,
3449336Sdfr};
3459336Sdfr
3469336Sdfrstatic short nfsv3err_symlink[] = {
3479336Sdfr	NFSERR_IO,
3489336Sdfr	NFSERR_IO,
3499336Sdfr	NFSERR_ACCES,
3509336Sdfr	NFSERR_EXIST,
3519336Sdfr	NFSERR_NOTDIR,
3529336Sdfr	NFSERR_NOSPC,
3539336Sdfr	NFSERR_ROFS,
3549336Sdfr	NFSERR_NAMETOL,
3559336Sdfr	NFSERR_DQUOT,
3569336Sdfr	NFSERR_STALE,
3579336Sdfr	NFSERR_BADHANDLE,
3589336Sdfr	NFSERR_NOTSUPP,
3599336Sdfr	NFSERR_SERVERFAULT,
3609336Sdfr	0,
3619336Sdfr};
3629336Sdfr
3639336Sdfrstatic short nfsv3err_mknod[] = {
3649336Sdfr	NFSERR_IO,
3659336Sdfr	NFSERR_IO,
3669336Sdfr	NFSERR_ACCES,
3679336Sdfr	NFSERR_EXIST,
3689336Sdfr	NFSERR_NOTDIR,
3699336Sdfr	NFSERR_NOSPC,
3709336Sdfr	NFSERR_ROFS,
3719336Sdfr	NFSERR_NAMETOL,
3729336Sdfr	NFSERR_DQUOT,
3739336Sdfr	NFSERR_STALE,
3749336Sdfr	NFSERR_BADHANDLE,
3759336Sdfr	NFSERR_NOTSUPP,
3769336Sdfr	NFSERR_SERVERFAULT,
3779336Sdfr	NFSERR_BADTYPE,
3789336Sdfr	0,
3799336Sdfr};
3809336Sdfr
3819336Sdfrstatic short nfsv3err_remove[] = {
3829336Sdfr	NFSERR_IO,
3839336Sdfr	NFSERR_NOENT,
3849336Sdfr	NFSERR_IO,
3859336Sdfr	NFSERR_ACCES,
3869336Sdfr	NFSERR_NOTDIR,
3879336Sdfr	NFSERR_ROFS,
3889336Sdfr	NFSERR_NAMETOL,
3899336Sdfr	NFSERR_STALE,
3909336Sdfr	NFSERR_BADHANDLE,
3919336Sdfr	NFSERR_SERVERFAULT,
3929336Sdfr	0,
3939336Sdfr};
3949336Sdfr
3959336Sdfrstatic short nfsv3err_rmdir[] = {
3969336Sdfr	NFSERR_IO,
3979336Sdfr	NFSERR_NOENT,
3989336Sdfr	NFSERR_IO,
3999336Sdfr	NFSERR_ACCES,
4009336Sdfr	NFSERR_EXIST,
4019336Sdfr	NFSERR_NOTDIR,
4029336Sdfr	NFSERR_INVAL,
4039336Sdfr	NFSERR_ROFS,
4049336Sdfr	NFSERR_NAMETOL,
4059336Sdfr	NFSERR_NOTEMPTY,
4069336Sdfr	NFSERR_STALE,
4079336Sdfr	NFSERR_BADHANDLE,
4089336Sdfr	NFSERR_NOTSUPP,
4099336Sdfr	NFSERR_SERVERFAULT,
4109336Sdfr	0,
4119336Sdfr};
4129336Sdfr
4139336Sdfrstatic short nfsv3err_rename[] = {
4149336Sdfr	NFSERR_IO,
4159336Sdfr	NFSERR_NOENT,
4169336Sdfr	NFSERR_IO,
4179336Sdfr	NFSERR_ACCES,
4189336Sdfr	NFSERR_EXIST,
4199336Sdfr	NFSERR_XDEV,
4209336Sdfr	NFSERR_NOTDIR,
4219336Sdfr	NFSERR_ISDIR,
4229336Sdfr	NFSERR_INVAL,
4239336Sdfr	NFSERR_NOSPC,
4249336Sdfr	NFSERR_ROFS,
4259336Sdfr	NFSERR_MLINK,
4269336Sdfr	NFSERR_NAMETOL,
4279336Sdfr	NFSERR_NOTEMPTY,
4289336Sdfr	NFSERR_DQUOT,
4299336Sdfr	NFSERR_STALE,
4309336Sdfr	NFSERR_BADHANDLE,
4319336Sdfr	NFSERR_NOTSUPP,
4329336Sdfr	NFSERR_SERVERFAULT,
4339336Sdfr	0,
4349336Sdfr};
4359336Sdfr
4369336Sdfrstatic short nfsv3err_link[] = {
4379336Sdfr	NFSERR_IO,
4389336Sdfr	NFSERR_IO,
4399336Sdfr	NFSERR_ACCES,
4409336Sdfr	NFSERR_EXIST,
4419336Sdfr	NFSERR_XDEV,
4429336Sdfr	NFSERR_NOTDIR,
4439336Sdfr	NFSERR_INVAL,
4449336Sdfr	NFSERR_NOSPC,
4459336Sdfr	NFSERR_ROFS,
4469336Sdfr	NFSERR_MLINK,
4479336Sdfr	NFSERR_NAMETOL,
4489336Sdfr	NFSERR_DQUOT,
4499336Sdfr	NFSERR_STALE,
4509336Sdfr	NFSERR_BADHANDLE,
4519336Sdfr	NFSERR_NOTSUPP,
4529336Sdfr	NFSERR_SERVERFAULT,
4539336Sdfr	0,
4549336Sdfr};
4559336Sdfr
4569336Sdfrstatic short nfsv3err_readdir[] = {
4579336Sdfr	NFSERR_IO,
4589336Sdfr	NFSERR_IO,
4599336Sdfr	NFSERR_ACCES,
4609336Sdfr	NFSERR_NOTDIR,
4619336Sdfr	NFSERR_STALE,
4629336Sdfr	NFSERR_BADHANDLE,
4639336Sdfr	NFSERR_BAD_COOKIE,
4649336Sdfr	NFSERR_TOOSMALL,
4659336Sdfr	NFSERR_SERVERFAULT,
4669336Sdfr	0,
4679336Sdfr};
4689336Sdfr
4699336Sdfrstatic short nfsv3err_readdirplus[] = {
4709336Sdfr	NFSERR_IO,
4719336Sdfr	NFSERR_IO,
4729336Sdfr	NFSERR_ACCES,
4739336Sdfr	NFSERR_NOTDIR,
4749336Sdfr	NFSERR_STALE,
4759336Sdfr	NFSERR_BADHANDLE,
4769336Sdfr	NFSERR_BAD_COOKIE,
4779336Sdfr	NFSERR_NOTSUPP,
4789336Sdfr	NFSERR_TOOSMALL,
4799336Sdfr	NFSERR_SERVERFAULT,
4809336Sdfr	0,
4819336Sdfr};
4829336Sdfr
4839336Sdfrstatic short nfsv3err_fsstat[] = {
4849336Sdfr	NFSERR_IO,
4859336Sdfr	NFSERR_IO,
4869336Sdfr	NFSERR_STALE,
4879336Sdfr	NFSERR_BADHANDLE,
4889336Sdfr	NFSERR_SERVERFAULT,
4899336Sdfr	0,
4909336Sdfr};
4919336Sdfr
4929336Sdfrstatic short nfsv3err_fsinfo[] = {
4939336Sdfr	NFSERR_STALE,
4949336Sdfr	NFSERR_STALE,
4959336Sdfr	NFSERR_BADHANDLE,
4969336Sdfr	NFSERR_SERVERFAULT,
4979336Sdfr	0,
4989336Sdfr};
4999336Sdfr
5009336Sdfrstatic short nfsv3err_pathconf[] = {
5019336Sdfr	NFSERR_STALE,
5029336Sdfr	NFSERR_STALE,
5039336Sdfr	NFSERR_BADHANDLE,
5049336Sdfr	NFSERR_SERVERFAULT,
5059336Sdfr	0,
5069336Sdfr};
5079336Sdfr
5089336Sdfrstatic short nfsv3err_commit[] = {
5099336Sdfr	NFSERR_IO,
5109336Sdfr	NFSERR_IO,
5119336Sdfr	NFSERR_STALE,
5129336Sdfr	NFSERR_BADHANDLE,
5139336Sdfr	NFSERR_SERVERFAULT,
5149336Sdfr	0,
5159336Sdfr};
5169336Sdfr
5179336Sdfrstatic short *nfsrv_v3errmap[] = {
5189336Sdfr	nfsv3err_null,
5199336Sdfr	nfsv3err_getattr,
5209336Sdfr	nfsv3err_setattr,
5219336Sdfr	nfsv3err_lookup,
5229336Sdfr	nfsv3err_access,
5239336Sdfr	nfsv3err_readlink,
5249336Sdfr	nfsv3err_read,
5259336Sdfr	nfsv3err_write,
5269336Sdfr	nfsv3err_create,
5279336Sdfr	nfsv3err_mkdir,
5289336Sdfr	nfsv3err_symlink,
5299336Sdfr	nfsv3err_mknod,
5309336Sdfr	nfsv3err_remove,
5319336Sdfr	nfsv3err_rmdir,
5329336Sdfr	nfsv3err_rename,
5339336Sdfr	nfsv3err_link,
5349336Sdfr	nfsv3err_readdir,
5359336Sdfr	nfsv3err_readdirplus,
5369336Sdfr	nfsv3err_fsstat,
5379336Sdfr	nfsv3err_fsinfo,
5389336Sdfr	nfsv3err_pathconf,
5399336Sdfr	nfsv3err_commit,
5409336Sdfr};
5419336Sdfr
54213416Sphk#endif /* NFS_NOSERVER */
54313416Sphk
5441541Srgrimesextern struct nfsrtt nfsrtt;
5451541Srgrimesextern time_t nqnfsstarttime;
5461541Srgrimesextern int nqsrv_clockskew;
5471541Srgrimesextern int nqsrv_writeslack;
5481541Srgrimesextern int nqsrv_maxlease;
5499336Sdfrextern struct nfsstats nfsstats;
5509336Sdfrextern int nqnfs_piggy[NFS_NPROCS];
5519336Sdfrextern nfstype nfsv2_type[9];
5529336Sdfrextern nfstype nfsv3_type[9];
5539336Sdfrextern struct nfsnodehashhead *nfsnodehashtbl;
5549336Sdfrextern u_long nfsnodehash;
5551541Srgrimes
5562997Swollmanstruct nfssvc_args;
5572997Swollmanextern int nfssvc(struct proc *, struct nfssvc_args *, int *);
5582997Swollman
5593664SphkLIST_HEAD(nfsnodehashhead, nfsnode);
5603664Sphk
56127446Sdfrint nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
56227446Sdfr
56334961Sphku_quad_t
56434961Sphknfs_curusec()
56534961Sphk{
56634961Sphk	struct timeval tv;
56734961Sphk
56834961Sphk	getmicrotime(&tv);
56934961Sphk	return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec);
57034961Sphk}
57134961Sphk
5721541Srgrimes/*
5731541Srgrimes * Create the header for an rpc request packet
5741541Srgrimes * The hsiz is the size of the rest of the nfs request header.
5751541Srgrimes * (just used to decide if a cluster is a good idea)
5761541Srgrimes */
5771541Srgrimesstruct mbuf *
5781541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp)
5791541Srgrimes	struct vnode *vp;
5801541Srgrimes	u_long procid;
5811541Srgrimes	int hsiz;
5821541Srgrimes	caddr_t *bposp;
5831541Srgrimes{
5841541Srgrimes	register struct mbuf *mb;
58536541Speter	register u_int32_t *tl;
5861541Srgrimes	register caddr_t bpos;
5871541Srgrimes	struct mbuf *mb2;
5881541Srgrimes	struct nfsmount *nmp;
5891541Srgrimes	int nqflag;
5901541Srgrimes
5911541Srgrimes	MGET(mb, M_WAIT, MT_DATA);
5921541Srgrimes	if (hsiz >= MINCLSIZE)
5931541Srgrimes		MCLGET(mb, M_WAIT);
5941541Srgrimes	mb->m_len = 0;
5951541Srgrimes	bpos = mtod(mb, caddr_t);
5968876Srgrimes
5971541Srgrimes	/*
5981541Srgrimes	 * For NQNFS, add lease request.
5991541Srgrimes	 */
6001541Srgrimes	if (vp) {
6011541Srgrimes		nmp = VFSTONFS(vp->v_mount);
6021541Srgrimes		if (nmp->nm_flag & NFSMNT_NQNFS) {
6031541Srgrimes			nqflag = NQNFS_NEEDLEASE(vp, procid);
6041541Srgrimes			if (nqflag) {
60536541Speter				nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED);
6061541Srgrimes				*tl++ = txdr_unsigned(nqflag);
6071541Srgrimes				*tl = txdr_unsigned(nmp->nm_leaseterm);
6081541Srgrimes			} else {
60936541Speter				nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
6101541Srgrimes				*tl = 0;
6111541Srgrimes			}
6121541Srgrimes		}
6131541Srgrimes	}
6141541Srgrimes	/* Finally, return values */
6151541Srgrimes	*bposp = bpos;
6161541Srgrimes	return (mb);
6171541Srgrimes}
6181541Srgrimes
6191541Srgrimes/*
6201541Srgrimes * Build the RPC header and fill in the authorization info.
6211541Srgrimes * The authorization string argument is only used when the credentials
6221541Srgrimes * come from outside of the kernel.
6231541Srgrimes * Returns the head of the mbuf list.
6241541Srgrimes */
6251541Srgrimesstruct mbuf *
6269336Sdfrnfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
6279336Sdfr	verf_str, mrest, mrest_len, mbp, xidp)
6281541Srgrimes	register struct ucred *cr;
6299336Sdfr	int nmflag;
6301541Srgrimes	int procid;
6311541Srgrimes	int auth_type;
6321541Srgrimes	int auth_len;
6331541Srgrimes	char *auth_str;
6349336Sdfr	int verf_len;
6359336Sdfr	char *verf_str;
6361541Srgrimes	struct mbuf *mrest;
6371541Srgrimes	int mrest_len;
6381541Srgrimes	struct mbuf **mbp;
63936541Speter	u_int32_t *xidp;
6401541Srgrimes{
6411541Srgrimes	register struct mbuf *mb;
64236541Speter	register u_int32_t *tl;
6431541Srgrimes	register caddr_t bpos;
6441541Srgrimes	register int i;
6451541Srgrimes	struct mbuf *mreq, *mb2;
6461541Srgrimes	int siz, grpsiz, authsiz;
6471541Srgrimes
6481541Srgrimes	authsiz = nfsm_rndup(auth_len);
6491541Srgrimes	MGETHDR(mb, M_WAIT, MT_DATA);
6509336Sdfr	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
6511541Srgrimes		MCLGET(mb, M_WAIT);
6529336Sdfr	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
6539336Sdfr		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
6541541Srgrimes	} else {
6559336Sdfr		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
6561541Srgrimes	}
6571541Srgrimes	mb->m_len = 0;
6581541Srgrimes	mreq = mb;
6591541Srgrimes	bpos = mtod(mb, caddr_t);
6601541Srgrimes
6611541Srgrimes	/*
6621541Srgrimes	 * First the RPC header.
6631541Srgrimes	 */
66436541Speter	nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
66517186Sdfr
66635066Sphk	/* Get a pretty random xid to start with */
66735066Sphk	if (!nfs_xid)
66835066Sphk		nfs_xid = random();
66917186Sdfr	/*
67017186Sdfr	 * Skip zero xid if it should ever happen.
67117186Sdfr	 */
6721541Srgrimes	if (++nfs_xid == 0)
6731541Srgrimes		nfs_xid++;
67417186Sdfr
6751541Srgrimes	*tl++ = *xidp = txdr_unsigned(nfs_xid);
6761541Srgrimes	*tl++ = rpc_call;
6771541Srgrimes	*tl++ = rpc_vers;
6789336Sdfr	if (nmflag & NFSMNT_NQNFS) {
6791541Srgrimes		*tl++ = txdr_unsigned(NQNFS_PROG);
6809336Sdfr		*tl++ = txdr_unsigned(NQNFS_VER3);
6811541Srgrimes	} else {
6821541Srgrimes		*tl++ = txdr_unsigned(NFS_PROG);
6839336Sdfr		if (nmflag & NFSMNT_NFSV3)
6849336Sdfr			*tl++ = txdr_unsigned(NFS_VER3);
6859336Sdfr		else
6869336Sdfr			*tl++ = txdr_unsigned(NFS_VER2);
6871541Srgrimes	}
6889336Sdfr	if (nmflag & NFSMNT_NFSV3)
6899336Sdfr		*tl++ = txdr_unsigned(procid);
6909336Sdfr	else
6919336Sdfr		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
6921541Srgrimes
6931541Srgrimes	/*
6941541Srgrimes	 * And then the authorization cred.
6951541Srgrimes	 */
6961541Srgrimes	*tl++ = txdr_unsigned(auth_type);
6971541Srgrimes	*tl = txdr_unsigned(authsiz);
6981541Srgrimes	switch (auth_type) {
6991541Srgrimes	case RPCAUTH_UNIX:
70036541Speter		nfsm_build(tl, u_int32_t *, auth_len);
7011541Srgrimes		*tl++ = 0;		/* stamp ?? */
7021541Srgrimes		*tl++ = 0;		/* NULL hostname */
7031541Srgrimes		*tl++ = txdr_unsigned(cr->cr_uid);
7041541Srgrimes		*tl++ = txdr_unsigned(cr->cr_groups[0]);
7051541Srgrimes		grpsiz = (auth_len >> 2) - 5;
7061541Srgrimes		*tl++ = txdr_unsigned(grpsiz);
7071541Srgrimes		for (i = 1; i <= grpsiz; i++)
7081541Srgrimes			*tl++ = txdr_unsigned(cr->cr_groups[i]);
7091541Srgrimes		break;
7109336Sdfr	case RPCAUTH_KERB4:
7111541Srgrimes		siz = auth_len;
7121541Srgrimes		while (siz > 0) {
7131541Srgrimes			if (M_TRAILINGSPACE(mb) == 0) {
7141541Srgrimes				MGET(mb2, M_WAIT, MT_DATA);
7151541Srgrimes				if (siz >= MINCLSIZE)
7161541Srgrimes					MCLGET(mb2, M_WAIT);
7171541Srgrimes				mb->m_next = mb2;
7181541Srgrimes				mb = mb2;
7191541Srgrimes				mb->m_len = 0;
7201541Srgrimes				bpos = mtod(mb, caddr_t);
7211541Srgrimes			}
7221541Srgrimes			i = min(siz, M_TRAILINGSPACE(mb));
7231541Srgrimes			bcopy(auth_str, bpos, i);
7241541Srgrimes			mb->m_len += i;
7251541Srgrimes			auth_str += i;
7261541Srgrimes			bpos += i;
7271541Srgrimes			siz -= i;
7281541Srgrimes		}
7291541Srgrimes		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
7301541Srgrimes			for (i = 0; i < siz; i++)
7311541Srgrimes				*bpos++ = '\0';
7321541Srgrimes			mb->m_len += siz;
7331541Srgrimes		}
7341541Srgrimes		break;
7351541Srgrimes	};
7369336Sdfr
7379336Sdfr	/*
7389336Sdfr	 * And the verifier...
7399336Sdfr	 */
74036541Speter	nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
7419336Sdfr	if (verf_str) {
7429336Sdfr		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
7439336Sdfr		*tl = txdr_unsigned(verf_len);
7449336Sdfr		siz = verf_len;
7459336Sdfr		while (siz > 0) {
7469336Sdfr			if (M_TRAILINGSPACE(mb) == 0) {
7479336Sdfr				MGET(mb2, M_WAIT, MT_DATA);
7489336Sdfr				if (siz >= MINCLSIZE)
7499336Sdfr					MCLGET(mb2, M_WAIT);
7509336Sdfr				mb->m_next = mb2;
7519336Sdfr				mb = mb2;
7529336Sdfr				mb->m_len = 0;
7539336Sdfr				bpos = mtod(mb, caddr_t);
7549336Sdfr			}
7559336Sdfr			i = min(siz, M_TRAILINGSPACE(mb));
7569336Sdfr			bcopy(verf_str, bpos, i);
7579336Sdfr			mb->m_len += i;
7589336Sdfr			verf_str += i;
7599336Sdfr			bpos += i;
7609336Sdfr			siz -= i;
7619336Sdfr		}
7629336Sdfr		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
7639336Sdfr			for (i = 0; i < siz; i++)
7649336Sdfr				*bpos++ = '\0';
7659336Sdfr			mb->m_len += siz;
7669336Sdfr		}
7679336Sdfr	} else {
7689336Sdfr		*tl++ = txdr_unsigned(RPCAUTH_NULL);
7699336Sdfr		*tl = 0;
7709336Sdfr	}
7711541Srgrimes	mb->m_next = mrest;
7729336Sdfr	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
7731541Srgrimes	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
7741541Srgrimes	*mbp = mb;
7751541Srgrimes	return (mreq);
7761541Srgrimes}
7771541Srgrimes
7781541Srgrimes/*
7791541Srgrimes * copies mbuf chain to the uio scatter/gather list
7801541Srgrimes */
7811549Srgrimesint
7821541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos)
7831541Srgrimes	struct mbuf **mrep;
7841541Srgrimes	register struct uio *uiop;
7851541Srgrimes	int siz;
7861541Srgrimes	caddr_t *dpos;
7871541Srgrimes{
7881541Srgrimes	register char *mbufcp, *uiocp;
7891541Srgrimes	register int xfer, left, len;
7901541Srgrimes	register struct mbuf *mp;
7911541Srgrimes	long uiosiz, rem;
7921541Srgrimes	int error = 0;
7931541Srgrimes
7941541Srgrimes	mp = *mrep;
7951541Srgrimes	mbufcp = *dpos;
7961541Srgrimes	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
7971541Srgrimes	rem = nfsm_rndup(siz)-siz;
7981541Srgrimes	while (siz > 0) {
7991541Srgrimes		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
8001541Srgrimes			return (EFBIG);
8011541Srgrimes		left = uiop->uio_iov->iov_len;
8021541Srgrimes		uiocp = uiop->uio_iov->iov_base;
8031541Srgrimes		if (left > siz)
8041541Srgrimes			left = siz;
8051541Srgrimes		uiosiz = left;
8061541Srgrimes		while (left > 0) {
8071541Srgrimes			while (len == 0) {
8081541Srgrimes				mp = mp->m_next;
8091541Srgrimes				if (mp == NULL)
8101541Srgrimes					return (EBADRPC);
8111541Srgrimes				mbufcp = mtod(mp, caddr_t);
8121541Srgrimes				len = mp->m_len;
8131541Srgrimes			}
8141541Srgrimes			xfer = (left > len) ? len : left;
8151541Srgrimes#ifdef notdef
8161541Srgrimes			/* Not Yet.. */
8171541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
8181541Srgrimes				(*(uiop->uio_iov->iov_op))
8191541Srgrimes				(mbufcp, uiocp, xfer);
8201541Srgrimes			else
8211541Srgrimes#endif
8221541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
8231541Srgrimes				bcopy(mbufcp, uiocp, xfer);
8241541Srgrimes			else
8251541Srgrimes				copyout(mbufcp, uiocp, xfer);
8261541Srgrimes			left -= xfer;
8271541Srgrimes			len -= xfer;
8281541Srgrimes			mbufcp += xfer;
8291541Srgrimes			uiocp += xfer;
8301541Srgrimes			uiop->uio_offset += xfer;
8311541Srgrimes			uiop->uio_resid -= xfer;
8321541Srgrimes		}
8331541Srgrimes		if (uiop->uio_iov->iov_len <= siz) {
8341541Srgrimes			uiop->uio_iovcnt--;
8351541Srgrimes			uiop->uio_iov++;
8361541Srgrimes		} else {
8371541Srgrimes			uiop->uio_iov->iov_base += uiosiz;
8381541Srgrimes			uiop->uio_iov->iov_len -= uiosiz;
8391541Srgrimes		}
8401541Srgrimes		siz -= uiosiz;
8411541Srgrimes	}
8421541Srgrimes	*dpos = mbufcp;
8431541Srgrimes	*mrep = mp;
8441541Srgrimes	if (rem > 0) {
8451541Srgrimes		if (len < rem)
8461541Srgrimes			error = nfs_adv(mrep, dpos, rem, len);
8471541Srgrimes		else
8481541Srgrimes			*dpos += rem;
8491541Srgrimes	}
8501541Srgrimes	return (error);
8511541Srgrimes}
8521541Srgrimes
8531541Srgrimes/*
85417186Sdfr * copies a uio scatter/gather list to an mbuf chain.
85517186Sdfr * NOTE: can ony handle iovcnt == 1
8561541Srgrimes */
8571549Srgrimesint
8581541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos)
8591541Srgrimes	register struct uio *uiop;
8601541Srgrimes	struct mbuf **mq;
8611541Srgrimes	int siz;
8621541Srgrimes	caddr_t *bpos;
8631541Srgrimes{
8641541Srgrimes	register char *uiocp;
8651541Srgrimes	register struct mbuf *mp, *mp2;
8661541Srgrimes	register int xfer, left, mlen;
8671541Srgrimes	int uiosiz, clflg, rem;
8681541Srgrimes	char *cp;
8691541Srgrimes
87036519Speter#ifdef DIAGNOSTIC
87117186Sdfr	if (uiop->uio_iovcnt != 1)
87217186Sdfr		panic("nfsm_uiotombuf: iovcnt != 1");
87336519Speter#endif
87417186Sdfr
8751541Srgrimes	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
8761541Srgrimes		clflg = 1;
8771541Srgrimes	else
8781541Srgrimes		clflg = 0;
8791541Srgrimes	rem = nfsm_rndup(siz)-siz;
8801541Srgrimes	mp = mp2 = *mq;
8811541Srgrimes	while (siz > 0) {
8821541Srgrimes		left = uiop->uio_iov->iov_len;
8831541Srgrimes		uiocp = uiop->uio_iov->iov_base;
8841541Srgrimes		if (left > siz)
8851541Srgrimes			left = siz;
8861541Srgrimes		uiosiz = left;
8871541Srgrimes		while (left > 0) {
8881541Srgrimes			mlen = M_TRAILINGSPACE(mp);
8891541Srgrimes			if (mlen == 0) {
8901541Srgrimes				MGET(mp, M_WAIT, MT_DATA);
8911541Srgrimes				if (clflg)
8921541Srgrimes					MCLGET(mp, M_WAIT);
8931541Srgrimes				mp->m_len = 0;
8941541Srgrimes				mp2->m_next = mp;
8951541Srgrimes				mp2 = mp;
8961541Srgrimes				mlen = M_TRAILINGSPACE(mp);
8971541Srgrimes			}
8981541Srgrimes			xfer = (left > mlen) ? mlen : left;
8991541Srgrimes#ifdef notdef
9001541Srgrimes			/* Not Yet.. */
9011541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
9021541Srgrimes				(*(uiop->uio_iov->iov_op))
9031541Srgrimes				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
9041541Srgrimes			else
9051541Srgrimes#endif
9061541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
9071541Srgrimes				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
9081541Srgrimes			else
9091541Srgrimes				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
9101541Srgrimes			mp->m_len += xfer;
9111541Srgrimes			left -= xfer;
9121541Srgrimes			uiocp += xfer;
9131541Srgrimes			uiop->uio_offset += xfer;
9141541Srgrimes			uiop->uio_resid -= xfer;
9151541Srgrimes		}
91617186Sdfr		uiop->uio_iov->iov_base += uiosiz;
91717186Sdfr		uiop->uio_iov->iov_len -= uiosiz;
9181541Srgrimes		siz -= uiosiz;
9191541Srgrimes	}
9201541Srgrimes	if (rem > 0) {
9211541Srgrimes		if (rem > M_TRAILINGSPACE(mp)) {
9221541Srgrimes			MGET(mp, M_WAIT, MT_DATA);
9231541Srgrimes			mp->m_len = 0;
9241541Srgrimes			mp2->m_next = mp;
9251541Srgrimes		}
9261541Srgrimes		cp = mtod(mp, caddr_t)+mp->m_len;
9271541Srgrimes		for (left = 0; left < rem; left++)
9281541Srgrimes			*cp++ = '\0';
9291541Srgrimes		mp->m_len += rem;
9301541Srgrimes		*bpos = cp;
9311541Srgrimes	} else
9321541Srgrimes		*bpos = mtod(mp, caddr_t)+mp->m_len;
9331541Srgrimes	*mq = mp;
9341541Srgrimes	return (0);
9351541Srgrimes}
9361541Srgrimes
9371541Srgrimes/*
9381541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous
9391541Srgrimes * pointed to by returned val.
9401541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
9411541Srgrimes * cases. (The macros use the vars. dpos and dpos2)
9421541Srgrimes */
9431549Srgrimesint
9441541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2)
9451541Srgrimes	struct mbuf **mdp;
9461541Srgrimes	caddr_t *dposp;
9471541Srgrimes	int siz;
9481541Srgrimes	int left;
9491541Srgrimes	caddr_t *cp2;
9501541Srgrimes{
9511541Srgrimes	register struct mbuf *mp, *mp2;
9521541Srgrimes	register int siz2, xfer;
9531541Srgrimes	register caddr_t p;
9541541Srgrimes
9551541Srgrimes	mp = *mdp;
9561541Srgrimes	while (left == 0) {
9571541Srgrimes		*mdp = mp = mp->m_next;
9581541Srgrimes		if (mp == NULL)
9591541Srgrimes			return (EBADRPC);
9601541Srgrimes		left = mp->m_len;
9611541Srgrimes		*dposp = mtod(mp, caddr_t);
9621541Srgrimes	}
9631541Srgrimes	if (left >= siz) {
9641541Srgrimes		*cp2 = *dposp;
9651541Srgrimes		*dposp += siz;
9661541Srgrimes	} else if (mp->m_next == NULL) {
9671541Srgrimes		return (EBADRPC);
9681541Srgrimes	} else if (siz > MHLEN) {
9691541Srgrimes		panic("nfs S too big");
9701541Srgrimes	} else {
9711541Srgrimes		MGET(mp2, M_WAIT, MT_DATA);
9721541Srgrimes		mp2->m_next = mp->m_next;
9731541Srgrimes		mp->m_next = mp2;
9741541Srgrimes		mp->m_len -= left;
9751541Srgrimes		mp = mp2;
9761541Srgrimes		*cp2 = p = mtod(mp, caddr_t);
9771541Srgrimes		bcopy(*dposp, p, left);		/* Copy what was left */
9781541Srgrimes		siz2 = siz-left;
9791541Srgrimes		p += left;
9801541Srgrimes		mp2 = mp->m_next;
9811541Srgrimes		/* Loop around copying up the siz2 bytes */
9821541Srgrimes		while (siz2 > 0) {
9831541Srgrimes			if (mp2 == NULL)
9841541Srgrimes				return (EBADRPC);
9851541Srgrimes			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
9861541Srgrimes			if (xfer > 0) {
9871541Srgrimes				bcopy(mtod(mp2, caddr_t), p, xfer);
9881541Srgrimes				NFSMADV(mp2, xfer);
9891541Srgrimes				mp2->m_len -= xfer;
9901541Srgrimes				p += xfer;
9911541Srgrimes				siz2 -= xfer;
9921541Srgrimes			}
9931541Srgrimes			if (siz2 > 0)
9941541Srgrimes				mp2 = mp2->m_next;
9951541Srgrimes		}
9961541Srgrimes		mp->m_len = siz;
9971541Srgrimes		*mdp = mp2;
9981541Srgrimes		*dposp = mtod(mp2, caddr_t);
9991541Srgrimes	}
10001541Srgrimes	return (0);
10011541Srgrimes}
10021541Srgrimes
10031541Srgrimes/*
10041541Srgrimes * Advance the position in the mbuf chain.
10051541Srgrimes */
10061549Srgrimesint
10071541Srgrimesnfs_adv(mdp, dposp, offs, left)
10081541Srgrimes	struct mbuf **mdp;
10091541Srgrimes	caddr_t *dposp;
10101541Srgrimes	int offs;
10111541Srgrimes	int left;
10121541Srgrimes{
10131541Srgrimes	register struct mbuf *m;
10141541Srgrimes	register int s;
10151541Srgrimes
10161541Srgrimes	m = *mdp;
10171541Srgrimes	s = left;
10181541Srgrimes	while (s < offs) {
10191541Srgrimes		offs -= s;
10201541Srgrimes		m = m->m_next;
10211541Srgrimes		if (m == NULL)
10221541Srgrimes			return (EBADRPC);
10231541Srgrimes		s = m->m_len;
10241541Srgrimes	}
10251541Srgrimes	*mdp = m;
10261541Srgrimes	*dposp = mtod(m, caddr_t)+offs;
10271541Srgrimes	return (0);
10281541Srgrimes}
10291541Srgrimes
10301541Srgrimes/*
10311541Srgrimes * Copy a string into mbufs for the hard cases...
10321541Srgrimes */
10331549Srgrimesint
10341541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz)
10351541Srgrimes	struct mbuf **mb;
10361541Srgrimes	char **bpos;
103736511Speter	const char *cp;
10381541Srgrimes	long siz;
10391541Srgrimes{
104036519Speter	register struct mbuf *m1 = NULL, *m2;
10411541Srgrimes	long left, xfer, len, tlen;
104236541Speter	u_int32_t *tl;
10431541Srgrimes	int putsize;
10441541Srgrimes
10451541Srgrimes	putsize = 1;
10461541Srgrimes	m2 = *mb;
10471541Srgrimes	left = M_TRAILINGSPACE(m2);
10481541Srgrimes	if (left > 0) {
104936541Speter		tl = ((u_int32_t *)(*bpos));
10501541Srgrimes		*tl++ = txdr_unsigned(siz);
10511541Srgrimes		putsize = 0;
10521541Srgrimes		left -= NFSX_UNSIGNED;
10531541Srgrimes		m2->m_len += NFSX_UNSIGNED;
10541541Srgrimes		if (left > 0) {
10551541Srgrimes			bcopy(cp, (caddr_t) tl, left);
10561541Srgrimes			siz -= left;
10571541Srgrimes			cp += left;
10581541Srgrimes			m2->m_len += left;
10591541Srgrimes			left = 0;
10601541Srgrimes		}
10611541Srgrimes	}
10621541Srgrimes	/* Loop around adding mbufs */
10631541Srgrimes	while (siz > 0) {
10641541Srgrimes		MGET(m1, M_WAIT, MT_DATA);
10651541Srgrimes		if (siz > MLEN)
10661541Srgrimes			MCLGET(m1, M_WAIT);
10671541Srgrimes		m1->m_len = NFSMSIZ(m1);
10681541Srgrimes		m2->m_next = m1;
10691541Srgrimes		m2 = m1;
107036541Speter		tl = mtod(m1, u_int32_t *);
10711541Srgrimes		tlen = 0;
10721541Srgrimes		if (putsize) {
10731541Srgrimes			*tl++ = txdr_unsigned(siz);
10741541Srgrimes			m1->m_len -= NFSX_UNSIGNED;
10751541Srgrimes			tlen = NFSX_UNSIGNED;
10761541Srgrimes			putsize = 0;
10771541Srgrimes		}
10781541Srgrimes		if (siz < m1->m_len) {
10791541Srgrimes			len = nfsm_rndup(siz);
10801541Srgrimes			xfer = siz;
10811541Srgrimes			if (xfer < len)
10821541Srgrimes				*(tl+(xfer>>2)) = 0;
10831541Srgrimes		} else {
10841541Srgrimes			xfer = len = m1->m_len;
10851541Srgrimes		}
10861541Srgrimes		bcopy(cp, (caddr_t) tl, xfer);
10871541Srgrimes		m1->m_len = len+tlen;
10881541Srgrimes		siz -= xfer;
10891541Srgrimes		cp += xfer;
10901541Srgrimes	}
10911541Srgrimes	*mb = m1;
10921541Srgrimes	*bpos = mtod(m1, caddr_t)+m1->m_len;
10931541Srgrimes	return (0);
10941541Srgrimes}
10951541Srgrimes
10961541Srgrimes/*
10971541Srgrimes * Called once to initialize data structures...
10981541Srgrimes */
10991549Srgrimesint
110022521Sdysonnfs_init(vfsp)
110122521Sdyson	struct vfsconf *vfsp;
11021541Srgrimes{
11031541Srgrimes	register int i;
11041541Srgrimes
110536329Speter	nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1);
110636329Speter
110722521Sdyson	nfs_mount_type = vfsp->vfc_typenum;
11081541Srgrimes	nfsrtt.pos = 0;
11091541Srgrimes	rpc_vers = txdr_unsigned(RPC_VER2);
11101541Srgrimes	rpc_call = txdr_unsigned(RPC_CALL);
11111541Srgrimes	rpc_reply = txdr_unsigned(RPC_REPLY);
11121541Srgrimes	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
11131541Srgrimes	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
11141541Srgrimes	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
11151541Srgrimes	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
11161541Srgrimes	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
11179336Sdfr	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
11181541Srgrimes	nfs_prog = txdr_unsigned(NFS_PROG);
11199336Sdfr	nqnfs_prog = txdr_unsigned(NQNFS_PROG);
11201541Srgrimes	nfs_true = txdr_unsigned(TRUE);
11211541Srgrimes	nfs_false = txdr_unsigned(FALSE);
11223664Sphk	nfs_xdrneg1 = txdr_unsigned(-1);
11239336Sdfr	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
11249336Sdfr	if (nfs_ticks < 1)
11259336Sdfr		nfs_ticks = 1;
11261541Srgrimes	/* Ensure async daemons disabled */
112719449Sdfr	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
11281541Srgrimes		nfs_iodwant[i] = (struct proc *)0;
112919449Sdfr		nfs_iodmount[i] = (struct nfsmount *)0;
113019449Sdfr	}
11311541Srgrimes	nfs_nhinit();			/* Init the nfsnode table */
113213416Sphk#ifndef NFS_NOSERVER
11331541Srgrimes	nfsrv_init(0);			/* Init server data structures */
11341541Srgrimes	nfsrv_initcache();		/* Init the server request cache */
113513416Sphk#endif
11361541Srgrimes
11371541Srgrimes	/*
11381541Srgrimes	 * Initialize the nqnfs server stuff.
11391541Srgrimes	 */
11401541Srgrimes	if (nqnfsstarttime == 0) {
11411541Srgrimes		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
11421541Srgrimes			+ nqsrv_clockskew + nqsrv_writeslack;
11431541Srgrimes		NQLOADNOVRAM(nqnfsstarttime);
11443664Sphk		CIRCLEQ_INIT(&nqtimerhead);
11453664Sphk		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
11461541Srgrimes	}
11471541Srgrimes
11481541Srgrimes	/*
11491541Srgrimes	 * Initialize reply list and start timer
11501541Srgrimes	 */
11513664Sphk	TAILQ_INIT(&nfs_reqq);
115216365Sphk
11533305Sphk	nfs_timer(0);
11541549Srgrimes
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
116038894Sbde	nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)];
116130738Sphk	default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check;
116213416Sphk#endif
116338894Sbde	nfs_prev_lease_updatetime = lease_updatetime;
11642997Swollman	lease_updatetime = nfs_lease_updatetime;
116538894Sbde	nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
11662997Swollman	sysent[SYS_nfssvc].sy_narg = 2;
116738894Sbde	nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
116830738Sphk	sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
11692997Swollman
117042957Sdillon	nfs_pbuf_freecnt = nswbuf / 2 + 1;
117142957Sdillon
11721549Srgrimes	return (0);
11731541Srgrimes}
11741541Srgrimes
117538894Sbdeint
117638894Sbdenfs_uninit(vfsp)
117738894Sbde	struct vfsconf *vfsp;
117838894Sbde{
117938894Sbde
118038894Sbde	untimeout(nfs_timer, (void *)NULL, nfs_timer_handle);
118138894Sbde	nfs_mount_type = -1;
118238894Sbde#ifndef NFS_NOSERVER
118338894Sbde	default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check;
118438894Sbde#endif
118538894Sbde	lease_updatetime = nfs_prev_lease_updatetime;
118638894Sbde	sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
118738894Sbde	sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
118838894Sbde	return (0);
118938894Sbde}
119038894Sbde
11911541Srgrimes/*
11921541Srgrimes * Attribute cache routines.
11931541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes
11941541Srgrimes *	that are on the mbuf list
11951541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns
11961541Srgrimes *	error otherwise
11971541Srgrimes */
11981541Srgrimes
11991541Srgrimes/*
12001541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with
12011541Srgrimes * the values on the mbuf list and
12021541Srgrimes * Iff vap not NULL
12031541Srgrimes *    copy the attributes to *vaper
12041541Srgrimes */
12051549Srgrimesint
12061541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper)
12071541Srgrimes	struct vnode **vpp;
12081541Srgrimes	struct mbuf **mdp;
12091541Srgrimes	caddr_t *dposp;
12101541Srgrimes	struct vattr *vaper;
12111541Srgrimes{
12121541Srgrimes	register struct vnode *vp = *vpp;
12131541Srgrimes	register struct vattr *vap;
12149336Sdfr	register struct nfs_fattr *fp;
12153664Sphk	register struct nfsnode *np;
121636541Speter	register int32_t t1;
12179336Sdfr	caddr_t cp2;
12189336Sdfr	int error = 0, rdev;
12191541Srgrimes	struct mbuf *md;
12201541Srgrimes	enum vtype vtyp;
12211541Srgrimes	u_short vmode;
12221541Srgrimes	struct timespec mtime;
12239336Sdfr	int v3 = NFS_ISV3(vp);
12241541Srgrimes
12251541Srgrimes	md = *mdp;
12269336Sdfr	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
122743305Sdillon	if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0)
12281541Srgrimes		return (error);
12299336Sdfr	fp = (struct nfs_fattr *)cp2;
12309336Sdfr	if (v3) {
12319336Sdfr		vtyp = nfsv3tov_type(fp->fa_type);
12329336Sdfr		vmode = fxdr_unsigned(u_short, fp->fa_mode);
123348859Sphk		rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
123416634Sbde			fxdr_unsigned(int, fp->fa3_rdev.specdata2));
12359336Sdfr		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
12361541Srgrimes	} else {
12379336Sdfr		vtyp = nfsv2tov_type(fp->fa_type);
12389336Sdfr		vmode = fxdr_unsigned(u_short, fp->fa_mode);
12399336Sdfr		/*
12409336Sdfr		 * XXX
12419336Sdfr		 *
12429336Sdfr		 * The duplicate information returned in fa_type and fa_mode
12439336Sdfr		 * is an ambiguity in the NFS version 2 protocol.
12449336Sdfr		 *
12459336Sdfr		 * VREG should be taken literally as a regular file.  If a
12469336Sdfr		 * server intents to return some type information differently
12479336Sdfr		 * in the upper bits of the mode field (e.g. for sockets, or
12489336Sdfr		 * FIFOs), NFSv2 mandates fa_type to be VNON.  Anyway, we
12499336Sdfr		 * leave the examination of the mode bits even in the VREG
12509336Sdfr		 * case to avoid breakage for bogus servers, but we make sure
12519336Sdfr		 * that there are actually type bits set in the upper part of
12529336Sdfr		 * fa_mode (and failing that, trust the va_type field).
12539336Sdfr		 *
12549336Sdfr		 * NFSv3 cleared the issue, and requires fa_mode to not
12559336Sdfr		 * contain any type information (while also introduing sockets
12569336Sdfr		 * and FIFOs for fa_type).
12579336Sdfr		 */
12589336Sdfr		if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
12599336Sdfr			vtyp = IFTOVT(vmode);
126036541Speter		rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
12619336Sdfr		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
12629336Sdfr
12639336Sdfr		/*
12649336Sdfr		 * Really ugly NFSv2 kludge.
12659336Sdfr		 */
12669336Sdfr		if (vtyp == VCHR && rdev == 0xffffffff)
12679336Sdfr			vtyp = VFIFO;
12681541Srgrimes	}
12699336Sdfr
12701541Srgrimes	/*
12711541Srgrimes	 * If v_type == VNON it is a new node, so fill in the v_type,
12728876Srgrimes	 * n_mtime fields. Check to see if it represents a special
12731541Srgrimes	 * device, and if so, check for a possible alias. Once the
12741541Srgrimes	 * correct vnode has been obtained, fill in the rest of the
12751541Srgrimes	 * information.
12761541Srgrimes	 */
12771541Srgrimes	np = VTONFS(vp);
127810219Sdfr	if (vp->v_type != vtyp) {
12799336Sdfr		vp->v_type = vtyp;
12801541Srgrimes		if (vp->v_type == VFIFO) {
12811541Srgrimes			vp->v_op = fifo_nfsv2nodeop_p;
12821541Srgrimes		}
12831541Srgrimes		if (vp->v_type == VCHR || vp->v_type == VBLK) {
12841541Srgrimes			vp->v_op = spec_nfsv2nodeop_p;
128550405Sphk			addaliasu(vp, rdev);
12861541Srgrimes		}
128718397Snate		np->n_mtime = mtime.tv_sec;
12881541Srgrimes	}
12891541Srgrimes	vap = &np->n_vattr;
12901541Srgrimes	vap->va_type = vtyp;
12911541Srgrimes	vap->va_mode = (vmode & 07777);
129247028Sphk	vap->va_rdev = rdev;
12931541Srgrimes	vap->va_mtime = mtime;
12941541Srgrimes	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
12959336Sdfr	if (v3) {
12969336Sdfr		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
12979336Sdfr		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
12989336Sdfr		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
129947751Speter		vap->va_size = fxdr_hyper(&fp->fa3_size);
13009336Sdfr		vap->va_blocksize = NFS_FABLKSIZE;
130147751Speter		vap->va_bytes = fxdr_hyper(&fp->fa3_used);
130236541Speter		vap->va_fileid = fxdr_unsigned(int32_t,
130336541Speter		    fp->fa3_fileid.nfsuquad[1]);
13049336Sdfr		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
13059336Sdfr		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
13069336Sdfr		vap->va_flags = 0;
13079336Sdfr		vap->va_filerev = 0;
13081541Srgrimes	} else {
13099336Sdfr		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
13109336Sdfr		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
13119336Sdfr		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
131236541Speter		vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
131336541Speter		vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
131447751Speter		vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks)
131536541Speter		    * NFS_FABLKSIZE;
131636541Speter		vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
13179336Sdfr		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
13181541Srgrimes		vap->va_flags = 0;
131936541Speter		vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
132036541Speter		    fp->fa2_ctime.nfsv2_sec);
132118397Snate		vap->va_ctime.tv_nsec = 0;
132236541Speter		vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
13231541Srgrimes		vap->va_filerev = 0;
13241541Srgrimes	}
13251541Srgrimes	if (vap->va_size != np->n_size) {
13261541Srgrimes		if (vap->va_type == VREG) {
13271541Srgrimes			if (np->n_flag & NMODIFIED) {
13281541Srgrimes				if (vap->va_size < np->n_size)
13291541Srgrimes					vap->va_size = np->n_size;
13301541Srgrimes				else
13311541Srgrimes					np->n_size = vap->va_size;
133254480Sdillon			} else {
13331541Srgrimes				np->n_size = vap->va_size;
133454480Sdillon			}
133541026Speter			vnode_pager_setsize(vp, np->n_size);
133654480Sdillon		} else {
13371541Srgrimes			np->n_size = vap->va_size;
133854480Sdillon		}
13391541Srgrimes	}
134034961Sphk	np->n_attrstamp = time_second;
13411541Srgrimes	if (vaper != NULL) {
13421541Srgrimes		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
13431541Srgrimes		if (np->n_flag & NCHG) {
13449336Sdfr			if (np->n_flag & NACC)
13459336Sdfr				vaper->va_atime = np->n_atim;
13469336Sdfr			if (np->n_flag & NUPD)
13479336Sdfr				vaper->va_mtime = np->n_mtim;
13481541Srgrimes		}
13491541Srgrimes	}
13501541Srgrimes	return (0);
13511541Srgrimes}
13521541Srgrimes
135336176Speter#ifdef NFS_ACDEBUG
135436176Speter#include <sys/sysctl.h>
135544101SbdeSYSCTL_DECL(_vfs_nfs);
135636176Speterstatic int nfs_acdebug;
135736176SpeterSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, "");
135836176Speter#endif
135936176Speter
13601541Srgrimes/*
13611541Srgrimes * Check the time stamp
13621541Srgrimes * If the cache is valid, copy contents to *vap and return 0
13631541Srgrimes * otherwise return an error
13641541Srgrimes */
13651549Srgrimesint
13661541Srgrimesnfs_getattrcache(vp, vaper)
13671541Srgrimes	register struct vnode *vp;
13681541Srgrimes	struct vattr *vaper;
13691541Srgrimes{
137036176Speter	register struct nfsnode *np;
13711541Srgrimes	register struct vattr *vap;
137236176Speter	struct nfsmount *nmp;
137336176Speter	int timeo;
13741541Srgrimes
137536176Speter	np = VTONFS(vp);
137636176Speter	vap = &np->n_vattr;
137736176Speter	nmp = VFSTONFS(vp->v_mount);
137836176Speter	/* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
137936176Speter	timeo = (time_second - np->n_mtime) / 10;
138036176Speter
138136176Speter#ifdef NFS_ACDEBUG
138236176Speter	if (nfs_acdebug>1)
138336176Speter		printf("nfs_getattrcache: initial timeo = %d\n", timeo);
138436176Speter#endif
138536176Speter
138636176Speter	if (vap->va_type == VDIR) {
138736176Speter		if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
138836176Speter			timeo = nmp->nm_acdirmin;
138936176Speter		else if (timeo > nmp->nm_acdirmax)
139036176Speter			timeo = nmp->nm_acdirmax;
139136176Speter	} else {
139236176Speter		if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
139336176Speter			timeo = nmp->nm_acregmin;
139436176Speter		else if (timeo > nmp->nm_acregmax)
139536176Speter			timeo = nmp->nm_acregmax;
139636176Speter	}
139736176Speter
139836176Speter#ifdef NFS_ACDEBUG
139936176Speter	if (nfs_acdebug > 2)
140036176Speter		printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
140136176Speter			nmp->nm_acregmin, nmp->nm_acregmax,
140236176Speter			nmp->nm_acdirmin, nmp->nm_acdirmax);
140336176Speter
140436176Speter	if (nfs_acdebug)
140537089Sbde		printf("nfs_getattrcache: age = %d; final timeo = %d\n",
140636176Speter			(time_second - np->n_attrstamp), timeo);
140736176Speter#endif
140836176Speter
140936176Speter	if ((time_second - np->n_attrstamp) >= timeo) {
14101541Srgrimes		nfsstats.attrcache_misses++;
14111541Srgrimes		return (ENOENT);
14121541Srgrimes	}
14131541Srgrimes	nfsstats.attrcache_hits++;
14141541Srgrimes	if (vap->va_size != np->n_size) {
14151541Srgrimes		if (vap->va_type == VREG) {
14161541Srgrimes			if (np->n_flag & NMODIFIED) {
14171541Srgrimes				if (vap->va_size < np->n_size)
14181541Srgrimes					vap->va_size = np->n_size;
14191541Srgrimes				else
14201541Srgrimes					np->n_size = vap->va_size;
142154480Sdillon			} else {
14221541Srgrimes				np->n_size = vap->va_size;
142354480Sdillon			}
142441026Speter			vnode_pager_setsize(vp, np->n_size);
142554480Sdillon		} else {
14261541Srgrimes			np->n_size = vap->va_size;
142754480Sdillon		}
14281541Srgrimes	}
14291541Srgrimes	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
14301541Srgrimes	if (np->n_flag & NCHG) {
14319336Sdfr		if (np->n_flag & NACC)
14329336Sdfr			vaper->va_atime = np->n_atim;
14339336Sdfr		if (np->n_flag & NUPD)
14349336Sdfr			vaper->va_mtime = np->n_mtim;
14351541Srgrimes	}
14361541Srgrimes	return (0);
14371541Srgrimes}
14381541Srgrimes
143913416Sphk#ifndef NFS_NOSERVER
14401541Srgrimes/*
144127446Sdfr * Set up nameidata for a lookup() call and do it.
144227446Sdfr *
144327446Sdfr * If pubflag is set, this call is done for a lookup operation on the
144427446Sdfr * public filehandle. In that case we allow crossing mountpoints and
144527446Sdfr * absolute pathnames. However, the caller is expected to check that
144627446Sdfr * the lookup result is within the public fs, and deny access if
144727446Sdfr * it is not.
144848125Sjulian *
144948125Sjulian * nfs_namei() clears out garbage fields that namei() might leave garbage.
145048125Sjulian * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
145148125Sjulian * error occurs but the parent was not requested.
145248125Sjulian *
145348125Sjulian * dirp may be set whether an error is returned or not, and must be
145448125Sjulian * released by the caller.
14551541Srgrimes */
14561549Srgrimesint
145727446Sdfrnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
14581541Srgrimes	register struct nameidata *ndp;
14591541Srgrimes	fhandle_t *fhp;
14601541Srgrimes	int len;
14611541Srgrimes	struct nfssvc_sock *slp;
146228270Swollman	struct sockaddr *nam;
14631541Srgrimes	struct mbuf **mdp;
14641541Srgrimes	caddr_t *dposp;
14659336Sdfr	struct vnode **retdirp;
14661541Srgrimes	struct proc *p;
146727446Sdfr	int kerbflag, pubflag;
14681541Srgrimes{
14691541Srgrimes	register int i, rem;
14701541Srgrimes	register struct mbuf *md;
147127446Sdfr	register char *fromcp, *tocp, *cp;
147227446Sdfr	struct iovec aiov;
147327446Sdfr	struct uio auio;
14741541Srgrimes	struct vnode *dp;
147527446Sdfr	int error, rdonly, linklen;
14761541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
14771541Srgrimes
14789336Sdfr	*retdirp = (struct vnode *)0;
147929653Sdyson	cnp->cn_pnbuf = zalloc(namei_zone);
148029653Sdyson
14811541Srgrimes	/*
14821541Srgrimes	 * Copy the name from the mbuf list to ndp->ni_pnbuf
14831541Srgrimes	 * and set the various ndp fields appropriately.
14841541Srgrimes	 */
14851541Srgrimes	fromcp = *dposp;
14861541Srgrimes	tocp = cnp->cn_pnbuf;
14871541Srgrimes	md = *mdp;
14881541Srgrimes	rem = mtod(md, caddr_t) + md->m_len - fromcp;
14891541Srgrimes	for (i = 0; i < len; i++) {
14901541Srgrimes		while (rem == 0) {
14911541Srgrimes			md = md->m_next;
14921541Srgrimes			if (md == NULL) {
14931541Srgrimes				error = EBADRPC;
14941541Srgrimes				goto out;
14951541Srgrimes			}
14961541Srgrimes			fromcp = mtod(md, caddr_t);
14971541Srgrimes			rem = md->m_len;
14981541Srgrimes		}
149927446Sdfr		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
15009336Sdfr			error = EACCES;
15011541Srgrimes			goto out;
15021541Srgrimes		}
15031541Srgrimes		*tocp++ = *fromcp++;
15041541Srgrimes		rem--;
15051541Srgrimes	}
15061541Srgrimes	*tocp = '\0';
15071541Srgrimes	*mdp = md;
15081541Srgrimes	*dposp = fromcp;
15091541Srgrimes	len = nfsm_rndup(len)-len;
15101541Srgrimes	if (len > 0) {
15111541Srgrimes		if (rem >= len)
15121541Srgrimes			*dposp += len;
151327609Sdfr		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
15149336Sdfr			goto out;
15151541Srgrimes	}
151627446Sdfr
15171541Srgrimes	/*
15181541Srgrimes	 * Extract and set starting directory.
15191541Srgrimes	 */
152027446Sdfr	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
152127446Sdfr	    nam, &rdonly, kerbflag, pubflag);
152227446Sdfr	if (error)
15231541Srgrimes		goto out;
15241541Srgrimes	if (dp->v_type != VDIR) {
152517761Sdyson		vrele(dp);
15261541Srgrimes		error = ENOTDIR;
15271541Srgrimes		goto out;
15281541Srgrimes	}
152927446Sdfr
153027446Sdfr	if (rdonly)
153127446Sdfr		cnp->cn_flags |= RDONLY;
153227446Sdfr
153348125Sjulian	/*
153448125Sjulian	 * Set return directory.  Reference to dp is implicitly transfered
153548125Sjulian	 * to the returned pointer
153648125Sjulian	 */
153727609Sdfr	*retdirp = dp;
153827609Sdfr
153927446Sdfr	if (pubflag) {
154027446Sdfr		/*
154127446Sdfr		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
154227446Sdfr		 * and the 'native path' indicator.
154327446Sdfr		 */
154429653Sdyson		cp = zalloc(namei_zone);
154527446Sdfr		fromcp = cnp->cn_pnbuf;
154627446Sdfr		tocp = cp;
154727446Sdfr		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
154827446Sdfr			switch ((unsigned char)*fromcp) {
154927446Sdfr			case WEBNFS_NATIVE_CHAR:
155027446Sdfr				/*
155127446Sdfr				 * 'Native' path for us is the same
155227446Sdfr				 * as a path according to the NFS spec,
155327446Sdfr				 * just skip the escape char.
155427446Sdfr				 */
155527446Sdfr				fromcp++;
155627446Sdfr				break;
155727446Sdfr			/*
155827446Sdfr			 * More may be added in the future, range 0x80-0xff
155927446Sdfr			 */
156027446Sdfr			default:
156127446Sdfr				error = EIO;
156229653Sdyson				zfree(namei_zone, cp);
156327446Sdfr				goto out;
156427446Sdfr			}
156527446Sdfr		}
156627446Sdfr		/*
156727446Sdfr		 * Translate the '%' escapes, URL-style.
156827446Sdfr		 */
156927446Sdfr		while (*fromcp != '\0') {
157027446Sdfr			if (*fromcp == WEBNFS_ESC_CHAR) {
157127446Sdfr				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
157227446Sdfr					fromcp++;
157327446Sdfr					*tocp++ = HEXSTRTOI(fromcp);
157427446Sdfr					fromcp += 2;
157527446Sdfr					continue;
157627446Sdfr				} else {
157727446Sdfr					error = ENOENT;
157829653Sdyson					zfree(namei_zone, cp);
157927446Sdfr					goto out;
158027446Sdfr				}
158127446Sdfr			} else
158227446Sdfr				*tocp++ = *fromcp++;
158327446Sdfr		}
158427446Sdfr		*tocp = '\0';
158529653Sdyson		zfree(namei_zone, cnp->cn_pnbuf);
158627446Sdfr		cnp->cn_pnbuf = cp;
158727446Sdfr	}
158827446Sdfr
158927446Sdfr	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
159027446Sdfr	ndp->ni_segflg = UIO_SYSSPACE;
159127446Sdfr
159227446Sdfr	if (pubflag) {
159327446Sdfr		ndp->ni_rootdir = rootvnode;
159427446Sdfr		ndp->ni_loopcnt = 0;
159527446Sdfr		if (cnp->cn_pnbuf[0] == '/')
159627446Sdfr			dp = rootvnode;
159727446Sdfr	} else {
159827609Sdfr		cnp->cn_flags |= NOCROSSMOUNT;
159927446Sdfr	}
160027446Sdfr
160148125Sjulian	/*
160248125Sjulian	 * Initialize for scan, set ni_startdir and bump ref on dp again
160348125Sjulian	 * becuase lookup() will dereference ni_startdir.
160448125Sjulian	 */
160548125Sjulian
160627446Sdfr	cnp->cn_proc = p;
16079336Sdfr	VREF(dp);
160848125Sjulian	ndp->ni_startdir = dp;
160927446Sdfr
161048125Sjulian	for (;;) {
161148125Sjulian		cnp->cn_nameptr = cnp->cn_pnbuf;
161248125Sjulian		/*
161348125Sjulian		 * Call lookup() to do the real work.  If an error occurs,
161448125Sjulian		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
161548125Sjulian		 * we do not have to dereference anything before returning.
161648125Sjulian		 * In either case ni_startdir will be dereferenced and NULLed
161748125Sjulian		 * out.
161848125Sjulian		 */
161948125Sjulian		error = lookup(ndp);
162048125Sjulian		if (error)
162148125Sjulian			break;
162248125Sjulian
162348125Sjulian		/*
162448125Sjulian		 * Check for encountering a symbolic link.  Trivial
162548125Sjulian		 * termination occurs if no symlink encountered.
162648125Sjulian		 * Note: zfree is safe because error is 0, so we will
162748125Sjulian		 * not zfree it again when we break.
162848125Sjulian		 */
162948125Sjulian		if ((cnp->cn_flags & ISSYMLINK) == 0) {
163048125Sjulian			nfsrv_object_create(ndp->ni_vp);
163148125Sjulian			if (cnp->cn_flags & (SAVENAME | SAVESTART))
163248125Sjulian				cnp->cn_flags |= HASBUF;
163348125Sjulian			else
163448125Sjulian				zfree(namei_zone, cnp->cn_pnbuf);
163548125Sjulian			break;
163627446Sdfr		}
163748125Sjulian
163848125Sjulian		/*
163948125Sjulian		 * Validate symlink
164048125Sjulian		 */
16411541Srgrimes		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
164227446Sdfr			VOP_UNLOCK(ndp->ni_dvp, 0, p);
164327446Sdfr		if (!pubflag) {
164427446Sdfr			error = EINVAL;
164548125Sjulian			goto badlink2;
164627446Sdfr		}
164727446Sdfr
164827446Sdfr		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
164927446Sdfr			error = ELOOP;
165048125Sjulian			goto badlink2;
165127446Sdfr		}
165227609Sdfr		if (ndp->ni_pathlen > 1)
165329653Sdyson			cp = zalloc(namei_zone);
16541541Srgrimes		else
165527446Sdfr			cp = cnp->cn_pnbuf;
165627446Sdfr		aiov.iov_base = cp;
165727446Sdfr		aiov.iov_len = MAXPATHLEN;
165827446Sdfr		auio.uio_iov = &aiov;
165927446Sdfr		auio.uio_iovcnt = 1;
166027446Sdfr		auio.uio_offset = 0;
166127446Sdfr		auio.uio_rw = UIO_READ;
166227446Sdfr		auio.uio_segflg = UIO_SYSSPACE;
166327446Sdfr		auio.uio_procp = (struct proc *)0;
166427446Sdfr		auio.uio_resid = MAXPATHLEN;
166527446Sdfr		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
166627446Sdfr		if (error) {
166748125Sjulian		badlink1:
166827446Sdfr			if (ndp->ni_pathlen > 1)
166929653Sdyson				zfree(namei_zone, cp);
167048125Sjulian		badlink2:
167148125Sjulian			vrele(ndp->ni_dvp);
167248125Sjulian			vput(ndp->ni_vp);
167327446Sdfr			break;
167427446Sdfr		}
167527446Sdfr		linklen = MAXPATHLEN - auio.uio_resid;
167627446Sdfr		if (linklen == 0) {
167727446Sdfr			error = ENOENT;
167848125Sjulian			goto badlink1;
167927446Sdfr		}
168027446Sdfr		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
168127446Sdfr			error = ENAMETOOLONG;
168248125Sjulian			goto badlink1;
168327446Sdfr		}
168448125Sjulian
168548125Sjulian		/*
168648125Sjulian		 * Adjust or replace path
168748125Sjulian		 */
168827446Sdfr		if (ndp->ni_pathlen > 1) {
168927446Sdfr			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
169029653Sdyson			zfree(namei_zone, cnp->cn_pnbuf);
169127446Sdfr			cnp->cn_pnbuf = cp;
169227446Sdfr		} else
169327446Sdfr			cnp->cn_pnbuf[linklen] = '\0';
169427446Sdfr		ndp->ni_pathlen += linklen;
169548125Sjulian
169627446Sdfr		/*
169748125Sjulian		 * Cleanup refs for next loop and check if root directory
169848125Sjulian		 * should replace current directory.  Normally ni_dvp
169948125Sjulian		 * becomes the new base directory and is cleaned up when
170048125Sjulian		 * we loop.  Explicitly null pointers after invalidation
170148125Sjulian		 * to clarify operation.
170227446Sdfr		 */
170348125Sjulian		vput(ndp->ni_vp);
170448125Sjulian		ndp->ni_vp = NULL;
170548125Sjulian
170627446Sdfr		if (cnp->cn_pnbuf[0] == '/') {
170748125Sjulian			vrele(ndp->ni_dvp);
170848125Sjulian			ndp->ni_dvp = ndp->ni_rootdir;
170948125Sjulian			VREF(ndp->ni_dvp);
171027446Sdfr		}
171148125Sjulian		ndp->ni_startdir = ndp->ni_dvp;
171248125Sjulian		ndp->ni_dvp = NULL;
17131541Srgrimes	}
171448125Sjulian
171548125Sjulian	/*
171648125Sjulian	 * nfs_namei() guarentees that fields will not contain garbage
171748125Sjulian	 * whether an error occurs or not.  This allows the caller to track
171848125Sjulian	 * cleanup state trivially.
171948125Sjulian	 */
17201541Srgrimesout:
172148125Sjulian	if (error) {
172248125Sjulian		zfree(namei_zone, cnp->cn_pnbuf);
172348125Sjulian		ndp->ni_vp = NULL;
172448125Sjulian		ndp->ni_dvp = NULL;
172548125Sjulian		ndp->ni_startdir = NULL;
172648125Sjulian		cnp->cn_flags &= ~HASBUF;
172748125Sjulian	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
172848125Sjulian		ndp->ni_dvp = NULL;
172948125Sjulian	}
17301541Srgrimes	return (error);
17311541Srgrimes}
17321541Srgrimes
17331541Srgrimes/*
17341541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long
17351541Srgrimes * boundary and only trims off the back end
17361541Srgrimes */
17371541Srgrimesvoid
17381541Srgrimesnfsm_adj(mp, len, nul)
17391541Srgrimes	struct mbuf *mp;
17401541Srgrimes	register int len;
17411541Srgrimes	int nul;
17421541Srgrimes{
17431541Srgrimes	register struct mbuf *m;
17441541Srgrimes	register int count, i;
17451541Srgrimes	register char *cp;
17461541Srgrimes
17471541Srgrimes	/*
17481541Srgrimes	 * Trim from tail.  Scan the mbuf chain,
17491541Srgrimes	 * calculating its length and finding the last mbuf.
17501541Srgrimes	 * If the adjustment only affects this mbuf, then just
17511541Srgrimes	 * adjust and return.  Otherwise, rescan and truncate
17521541Srgrimes	 * after the remaining size.
17531541Srgrimes	 */
17541541Srgrimes	count = 0;
17551541Srgrimes	m = mp;
17561541Srgrimes	for (;;) {
17571541Srgrimes		count += m->m_len;
17581541Srgrimes		if (m->m_next == (struct mbuf *)0)
17591541Srgrimes			break;
17601541Srgrimes		m = m->m_next;
17611541Srgrimes	}
17621541Srgrimes	if (m->m_len > len) {
17631541Srgrimes		m->m_len -= len;
17641541Srgrimes		if (nul > 0) {
17651541Srgrimes			cp = mtod(m, caddr_t)+m->m_len-nul;
17661541Srgrimes			for (i = 0; i < nul; i++)
17671541Srgrimes				*cp++ = '\0';
17681541Srgrimes		}
17691541Srgrimes		return;
17701541Srgrimes	}
17711541Srgrimes	count -= len;
17721541Srgrimes	if (count < 0)
17731541Srgrimes		count = 0;
17741541Srgrimes	/*
17751541Srgrimes	 * Correct length for chain is "count".
17761541Srgrimes	 * Find the mbuf with last data, adjust its length,
17771541Srgrimes	 * and toss data from remaining mbufs on chain.
17781541Srgrimes	 */
17791541Srgrimes	for (m = mp; m; m = m->m_next) {
17801541Srgrimes		if (m->m_len >= count) {
17811541Srgrimes			m->m_len = count;
17821541Srgrimes			if (nul > 0) {
17831541Srgrimes				cp = mtod(m, caddr_t)+m->m_len-nul;
17841541Srgrimes				for (i = 0; i < nul; i++)
17851541Srgrimes					*cp++ = '\0';
17861541Srgrimes			}
17871541Srgrimes			break;
17881541Srgrimes		}
17891541Srgrimes		count -= m->m_len;
17901541Srgrimes	}
17913305Sphk	for (m = m->m_next;m;m = m->m_next)
17921541Srgrimes		m->m_len = 0;
17931541Srgrimes}
17941541Srgrimes
17951541Srgrimes/*
17969336Sdfr * Make these functions instead of macros, so that the kernel text size
17979336Sdfr * doesn't get too big...
17989336Sdfr */
17999336Sdfrvoid
18009336Sdfrnfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
18019336Sdfr	struct nfsrv_descript *nfsd;
18029336Sdfr	int before_ret;
18039336Sdfr	register struct vattr *before_vap;
18049336Sdfr	int after_ret;
18059336Sdfr	struct vattr *after_vap;
18069336Sdfr	struct mbuf **mbp;
18079336Sdfr	char **bposp;
18089336Sdfr{
18099336Sdfr	register struct mbuf *mb = *mbp, *mb2;
18109336Sdfr	register char *bpos = *bposp;
181136541Speter	register u_int32_t *tl;
18129336Sdfr
18139336Sdfr	if (before_ret) {
181436541Speter		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
18159336Sdfr		*tl = nfs_false;
18169336Sdfr	} else {
181736541Speter		nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
18189336Sdfr		*tl++ = nfs_true;
181947751Speter		txdr_hyper(before_vap->va_size, tl);
18209336Sdfr		tl += 2;
18219336Sdfr		txdr_nfsv3time(&(before_vap->va_mtime), tl);
18229336Sdfr		tl += 2;
18239336Sdfr		txdr_nfsv3time(&(before_vap->va_ctime), tl);
18249336Sdfr	}
18259336Sdfr	*bposp = bpos;
18269336Sdfr	*mbp = mb;
18279336Sdfr	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
18289336Sdfr}
18299336Sdfr
18309336Sdfrvoid
18319336Sdfrnfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
18329336Sdfr	struct nfsrv_descript *nfsd;
18339336Sdfr	int after_ret;
18349336Sdfr	struct vattr *after_vap;
18359336Sdfr	struct mbuf **mbp;
18369336Sdfr	char **bposp;
18379336Sdfr{
18389336Sdfr	register struct mbuf *mb = *mbp, *mb2;
18399336Sdfr	register char *bpos = *bposp;
184036541Speter	register u_int32_t *tl;
18419336Sdfr	register struct nfs_fattr *fp;
18429336Sdfr
18439336Sdfr	if (after_ret) {
184436541Speter		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
18459336Sdfr		*tl = nfs_false;
18469336Sdfr	} else {
184736541Speter		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
18489336Sdfr		*tl++ = nfs_true;
18499336Sdfr		fp = (struct nfs_fattr *)tl;
18509336Sdfr		nfsm_srvfattr(nfsd, after_vap, fp);
18519336Sdfr	}
18529336Sdfr	*mbp = mb;
18539336Sdfr	*bposp = bpos;
18549336Sdfr}
18559336Sdfr
18569336Sdfrvoid
18579336Sdfrnfsm_srvfattr(nfsd, vap, fp)
18589336Sdfr	register struct nfsrv_descript *nfsd;
18599336Sdfr	register struct vattr *vap;
18609336Sdfr	register struct nfs_fattr *fp;
18619336Sdfr{
18629336Sdfr
18639336Sdfr	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
18649336Sdfr	fp->fa_uid = txdr_unsigned(vap->va_uid);
18659336Sdfr	fp->fa_gid = txdr_unsigned(vap->va_gid);
18669336Sdfr	if (nfsd->nd_flag & ND_NFSV3) {
18679336Sdfr		fp->fa_type = vtonfsv3_type(vap->va_type);
18689336Sdfr		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
186947751Speter		txdr_hyper(vap->va_size, &fp->fa3_size);
187047751Speter		txdr_hyper(vap->va_bytes, &fp->fa3_used);
187147028Sphk		fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
187247028Sphk		fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
18739336Sdfr		fp->fa3_fsid.nfsuquad[0] = 0;
18749336Sdfr		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
18759336Sdfr		fp->fa3_fileid.nfsuquad[0] = 0;
18769336Sdfr		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
18779336Sdfr		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
18789336Sdfr		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
18799336Sdfr		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
18809336Sdfr	} else {
18819336Sdfr		fp->fa_type = vtonfsv2_type(vap->va_type);
18829336Sdfr		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
18839336Sdfr		fp->fa2_size = txdr_unsigned(vap->va_size);
18849336Sdfr		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
18859336Sdfr		if (vap->va_type == VFIFO)
18869336Sdfr			fp->fa2_rdev = 0xffffffff;
18879336Sdfr		else
18889336Sdfr			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
18899336Sdfr		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
18909336Sdfr		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
18919336Sdfr		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
18929336Sdfr		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
18939336Sdfr		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
18949336Sdfr		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
18959336Sdfr	}
18969336Sdfr}
18979336Sdfr
18989336Sdfr/*
18991541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
19001541Srgrimes * 	- look up fsid in mount list (if not found ret error)
19011541Srgrimes *	- get vp and export rights by calling VFS_FHTOVP()
19021541Srgrimes *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
19031541Srgrimes *	- if not lockflag unlock it with VOP_UNLOCK()
19041541Srgrimes */
19051549Srgrimesint
190627446Sdfrnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
19071541Srgrimes	fhandle_t *fhp;
19081541Srgrimes	int lockflag;
19091541Srgrimes	struct vnode **vpp;
19101541Srgrimes	struct ucred *cred;
19111541Srgrimes	struct nfssvc_sock *slp;
191228270Swollman	struct sockaddr *nam;
19131541Srgrimes	int *rdonlyp;
19149336Sdfr	int kerbflag;
191527446Sdfr	int pubflag;
19161541Srgrimes{
191722521Sdyson	struct proc *p = curproc; /* XXX */
19181541Srgrimes	register struct mount *mp;
19191541Srgrimes	register int i;
19201541Srgrimes	struct ucred *credanon;
19211541Srgrimes	int error, exflags;
192236534Speter#ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
192336534Speter	struct sockaddr_int *saddr;
192436534Speter#endif
19251541Srgrimes
19261541Srgrimes	*vpp = (struct vnode *)0;
192727446Sdfr
192827446Sdfr	if (nfs_ispublicfh(fhp)) {
192927446Sdfr		if (!pubflag || !nfs_pub.np_valid)
193027446Sdfr			return (ESTALE);
193127446Sdfr		fhp = &nfs_pub.np_handle;
193227446Sdfr	}
193327446Sdfr
193422521Sdyson	mp = vfs_getvfs(&fhp->fh_fsid);
19353305Sphk	if (!mp)
19361541Srgrimes		return (ESTALE);
193751138Salfred	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
19383305Sphk	if (error)
193951138Salfred		return (error);
194051138Salfred	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
194151138Salfred	if (error)
19421541Srgrimes		return (error);
194336534Speter#ifdef MNT_EXNORESPORT
194436534Speter	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
194536534Speter		saddr = (struct sockaddr_in *)nam;
194636534Speter		if (saddr->sin_family == AF_INET &&
194736534Speter		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
194836534Speter			vput(*vpp);
194954485Sdillon			*vpp = NULL;
195036534Speter			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
195136534Speter		}
195236534Speter	}
195336534Speter#endif
19541541Srgrimes	/*
19551541Srgrimes	 * Check/setup credentials.
19561541Srgrimes	 */
19571541Srgrimes	if (exflags & MNT_EXKERB) {
19589336Sdfr		if (!kerbflag) {
19591541Srgrimes			vput(*vpp);
196054485Sdillon			*vpp = NULL;
19619336Sdfr			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
19621541Srgrimes		}
19639336Sdfr	} else if (kerbflag) {
19649336Sdfr		vput(*vpp);
196554485Sdillon		*vpp = NULL;
19669336Sdfr		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
19671541Srgrimes	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
19681541Srgrimes		cred->cr_uid = credanon->cr_uid;
19691541Srgrimes		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
19701541Srgrimes			cred->cr_groups[i] = credanon->cr_groups[i];
19713664Sphk		cred->cr_ngroups = i;
19721541Srgrimes	}
19731541Srgrimes	if (exflags & MNT_EXRDONLY)
19741541Srgrimes		*rdonlyp = 1;
19751541Srgrimes	else
19761541Srgrimes		*rdonlyp = 0;
19777969Sdyson
197817761Sdyson	nfsrv_object_create(*vpp);
19797969Sdyson
19801541Srgrimes	if (!lockflag)
198122521Sdyson		VOP_UNLOCK(*vpp, 0, p);
19821541Srgrimes	return (0);
19831541Srgrimes}
19841541Srgrimes
198527446Sdfr
198627446Sdfr/*
198727446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this
198827446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
198927446Sdfr * transformed this to all zeroes in both cases, so check for it.
199027446Sdfr */
199127446Sdfrint
199227446Sdfrnfs_ispublicfh(fhp)
199327446Sdfr	fhandle_t *fhp;
199427446Sdfr{
199527446Sdfr	char *cp = (char *)fhp;
199627446Sdfr	int i;
199727446Sdfr
199827446Sdfr	for (i = 0; i < NFSX_V3FH; i++)
199927446Sdfr		if (*cp++ != 0)
200027446Sdfr			return (FALSE);
200127446Sdfr	return (TRUE);
200227446Sdfr}
200327446Sdfr
200413416Sphk#endif /* NFS_NOSERVER */
20051541Srgrimes/*
20061541Srgrimes * This function compares two net addresses by family and returns TRUE
20071541Srgrimes * if they are the same host.
20081541Srgrimes * If there is any doubt, return FALSE.
20091541Srgrimes * The AF_INET family is handled as a special case so that address mbufs
20101541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes.
20111541Srgrimes */
20121549Srgrimesint
20131541Srgrimesnetaddr_match(family, haddr, nam)
20141541Srgrimes	int family;
20151541Srgrimes	union nethostaddr *haddr;
201628270Swollman	struct sockaddr *nam;
20171541Srgrimes{
20181541Srgrimes	register struct sockaddr_in *inetaddr;
20191541Srgrimes
20201541Srgrimes	switch (family) {
20211541Srgrimes	case AF_INET:
202228270Swollman		inetaddr = (struct sockaddr_in *)nam;
20231541Srgrimes		if (inetaddr->sin_family == AF_INET &&
20241541Srgrimes		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
20251541Srgrimes			return (1);
20261541Srgrimes		break;
20271541Srgrimes	default:
20281541Srgrimes		break;
20291541Srgrimes	};
20301541Srgrimes	return (0);
20311541Srgrimes}
20325455Sdg
203343305Sdillonstatic nfsuint64 nfs_nullcookie = { { 0, 0 } };
20349336Sdfr/*
20359336Sdfr * This function finds the directory cookie that corresponds to the
20369336Sdfr * logical byte offset given.
20379336Sdfr */
20389336Sdfrnfsuint64 *
20399336Sdfrnfs_getcookie(np, off, add)
20409336Sdfr	register struct nfsnode *np;
20419336Sdfr	off_t off;
20429336Sdfr	int add;
20439336Sdfr{
20449336Sdfr	register struct nfsdmap *dp, *dp2;
20459336Sdfr	register int pos;
20469336Sdfr
204736979Sbde	pos = (uoff_t)off / NFS_DIRBLKSIZ;
204836979Sbde	if (pos == 0 || off < 0) {
20499336Sdfr#ifdef DIAGNOSTIC
20509336Sdfr		if (add)
205136979Sbde			panic("nfs getcookie add at <= 0");
20529336Sdfr#endif
20539336Sdfr		return (&nfs_nullcookie);
20549336Sdfr	}
20559336Sdfr	pos--;
20569336Sdfr	dp = np->n_cookies.lh_first;
20579336Sdfr	if (!dp) {
20589336Sdfr		if (add) {
20599336Sdfr			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
20609336Sdfr				M_NFSDIROFF, M_WAITOK);
20619336Sdfr			dp->ndm_eocookie = 0;
20629336Sdfr			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
20639336Sdfr		} else
20649336Sdfr			return ((nfsuint64 *)0);
20659336Sdfr	}
20669336Sdfr	while (pos >= NFSNUMCOOKIES) {
20679336Sdfr		pos -= NFSNUMCOOKIES;
20689336Sdfr		if (dp->ndm_list.le_next) {
20699336Sdfr			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
20709336Sdfr				pos >= dp->ndm_eocookie)
20719336Sdfr				return ((nfsuint64 *)0);
20729336Sdfr			dp = dp->ndm_list.le_next;
20739336Sdfr		} else if (add) {
20749336Sdfr			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
20759336Sdfr				M_NFSDIROFF, M_WAITOK);
20769336Sdfr			dp2->ndm_eocookie = 0;
20779336Sdfr			LIST_INSERT_AFTER(dp, dp2, ndm_list);
20789336Sdfr			dp = dp2;
20799336Sdfr		} else
20809336Sdfr			return ((nfsuint64 *)0);
20819336Sdfr	}
20829336Sdfr	if (pos >= dp->ndm_eocookie) {
20839336Sdfr		if (add)
20849336Sdfr			dp->ndm_eocookie = pos + 1;
20859336Sdfr		else
20869336Sdfr			return ((nfsuint64 *)0);
20879336Sdfr	}
20889336Sdfr	return (&dp->ndm_cookies[pos]);
20899336Sdfr}
20909336Sdfr
20919336Sdfr/*
20929336Sdfr * Invalidate cached directory information, except for the actual directory
20939336Sdfr * blocks (which are invalidated separately).
20949336Sdfr * Done mainly to avoid the use of stale offset cookies.
20959336Sdfr */
20969336Sdfrvoid
20979336Sdfrnfs_invaldir(vp)
20989336Sdfr	register struct vnode *vp;
20999336Sdfr{
21009336Sdfr	register struct nfsnode *np = VTONFS(vp);
21019336Sdfr
21029336Sdfr#ifdef DIAGNOSTIC
21039336Sdfr	if (vp->v_type != VDIR)
21049336Sdfr		panic("nfs: invaldir not dir");
21059336Sdfr#endif
21069336Sdfr	np->n_direofoffset = 0;
21079336Sdfr	np->n_cookieverf.nfsuquad[0] = 0;
21089336Sdfr	np->n_cookieverf.nfsuquad[1] = 0;
21099336Sdfr	if (np->n_cookies.lh_first)
21109336Sdfr		np->n_cookies.lh_first->ndm_eocookie = 0;
21119336Sdfr}
21129336Sdfr
21139336Sdfr/*
21149336Sdfr * The write verifier has changed (probably due to a server reboot), so all
21159336Sdfr * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
21169336Sdfr * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
211754480Sdillon * and B_CLUSTEROK flags.  Once done the new write verifier can be set for the
211854480Sdillon * mount point.
211954480Sdillon *
212054480Sdillon * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data
212154480Sdillon * writes are not clusterable.
21229336Sdfr */
21239336Sdfrvoid
21249336Sdfrnfs_clearcommit(mp)
21259336Sdfr	struct mount *mp;
21269336Sdfr{
21279336Sdfr	register struct vnode *vp, *nvp;
21289336Sdfr	register struct buf *bp, *nbp;
21299336Sdfr	int s;
21309336Sdfr
21319336Sdfr	s = splbio();
21329336Sdfrloop:
21339336Sdfr	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
21349336Sdfr		if (vp->v_mount != mp)	/* Paranoia */
21359336Sdfr			goto loop;
21369336Sdfr		nvp = vp->v_mntvnodes.le_next;
213740790Speter		for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
213840790Speter			nbp = TAILQ_NEXT(bp, b_vnbufs);
213948225Smckusick			if (BUF_REFCNT(bp) == 0 &&
214048225Smckusick			    (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
21419336Sdfr				== (B_DELWRI | B_NEEDCOMMIT))
214254480Sdillon				bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
21439336Sdfr		}
21449336Sdfr	}
21459336Sdfr	splx(s);
21469336Sdfr}
21479336Sdfr
214813416Sphk#ifndef NFS_NOSERVER
21499336Sdfr/*
21509336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error
21519336Sdfr * numbers not specified for the associated procedure.
21529336Sdfr */
21535455Sdgint
21549336Sdfrnfsrv_errmap(nd, err)
21559336Sdfr	struct nfsrv_descript *nd;
21569336Sdfr	register int err;
21579336Sdfr{
21589336Sdfr	register short *defaulterrp, *errp;
21599336Sdfr
21609336Sdfr	if (nd->nd_flag & ND_NFSV3) {
21619336Sdfr	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
21629336Sdfr		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
21639336Sdfr		while (*++errp) {
21649336Sdfr			if (*errp == err)
21659336Sdfr				return (err);
21669336Sdfr			else if (*errp > err)
21679336Sdfr				break;
21689336Sdfr		}
21699336Sdfr		return ((int)*defaulterrp);
21709336Sdfr	    } else
21719336Sdfr		return (err & 0xffff);
21729336Sdfr	}
21739336Sdfr	if (err <= ELAST)
21749336Sdfr		return ((int)nfsrv_v2errmap[err - 1]);
21759336Sdfr	return (NFSERR_IO);
21769336Sdfr}
21779336Sdfr
21789336Sdfrint
217931886Sbdenfsrv_object_create(vp)
218031886Sbde	struct vnode *vp;
218131886Sbde{
21825455Sdg
218331886Sbde	if (vp == NULL || vp->v_type != VREG)
218431886Sbde		return (1);
218531886Sbde	return (vfs_object_create(vp, curproc,
218642315Seivind				  curproc ? curproc->p_ucred : NULL));
21875455Sdg}
218836503Speter
218936503Speter/*
219036503Speter * Sort the group list in increasing numerical order.
219136503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
219236503Speter *  that used to be here.)
219336503Speter */
219436503Spetervoid
219536503Speternfsrvw_sort(list, num)
219636503Speter        register gid_t *list;
219736503Speter        register int num;
219836503Speter{
219936503Speter	register int i, j;
220036503Speter	gid_t v;
220136503Speter
220236503Speter	/* Insertion sort. */
220336503Speter	for (i = 1; i < num; i++) {
220436503Speter		v = list[i];
220536503Speter		/* find correct slot for value v, moving others up */
220636503Speter		for (j = i; --j >= 0 && v < list[j];)
220736503Speter			list[j + 1] = list[j];
220836503Speter		list[j + 1] = v;
220936503Speter	}
221036503Speter}
221136503Speter
221236503Speter/*
221336503Speter * copy credentials making sure that the result can be compared with bcmp().
221436503Speter */
221536503Spetervoid
221636503Speternfsrv_setcred(incred, outcred)
221736503Speter	register struct ucred *incred, *outcred;
221836503Speter{
221936503Speter	register int i;
222036503Speter
222136503Speter	bzero((caddr_t)outcred, sizeof (struct ucred));
222236503Speter	outcred->cr_ref = 1;
222336503Speter	outcred->cr_uid = incred->cr_uid;
222436503Speter	outcred->cr_ngroups = incred->cr_ngroups;
222536503Speter	for (i = 0; i < incred->cr_ngroups; i++)
222636503Speter		outcred->cr_groups[i] = incred->cr_groups[i];
222736503Speter	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
222836503Speter}
222913416Sphk#endif /* NFS_NOSERVER */
2230