nfs_srvsubs.c revision 60833
1139823Simp/*
2200838Sluigi * Copyright (c) 1989, 1993
398943Sluigi *	The Regents of the University of California.  All rights reserved.
498943Sluigi *
598943Sluigi * This code is derived from software contributed to Berkeley by
698943Sluigi * Rick Macklem at The University of Guelph.
798943Sluigi *
898943Sluigi * Redistribution and use in source and binary forms, with or without
9116763Sluigi * modification, are permitted provided that the following conditions
1098943Sluigi * are met:
1198943Sluigi * 1. Redistributions of source code must retain the above copyright
12105775Smaxim *    notice, this list of conditions and the following disclaimer.
1398943Sluigi * 2. Redistributions in binary form must reproduce the above copyright
1498943Sluigi *    notice, this list of conditions and the following disclaimer in the
1598943Sluigi *    documentation and/or other materials provided with the distribution.
1698943Sluigi * 3. All advertising materials mentioning features or use of this software
1798943Sluigi *    must display the following acknowledgement:
1898943Sluigi *	This product includes software developed by the University of
1998943Sluigi *	California, Berkeley and its contributors.
2098943Sluigi * 4. Neither the name of the University nor the names of its contributors
2198943Sluigi *    may be used to endorse or promote products derived from this software
2298943Sluigi *    without specific prior written permission.
2398943Sluigi *
2498943Sluigi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2598943Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26172467Ssilby * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27172467Ssilby * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28172467Ssilby * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2998943Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30200601Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3198943Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3298943Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33225518Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34166479Salc * SUCH DAMAGE.
3598943Sluigi *
3698943Sluigi *	@(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
3798943Sluigi * $FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 60833 2000-05-23 20:41:01Z jake $
3898943Sluigi */
39152928Sume
40152928Sume/*
4198943Sluigi * These functions support the macros and help fiddle mbuf chains for
4298943Sluigi * the nfs op functions. They do things like create the rpc header and
4398943Sluigi * copy data between mbuf chains and uio lists.
44138642Scsjp */
45165648Spiso#include <sys/param.h>
4698943Sluigi#include <sys/systm.h>
4798943Sluigi#include <sys/kernel.h>
4898943Sluigi#include <sys/bio.h>
49155201Scsjp#include <sys/buf.h>
50133600Scsjp#include <sys/proc.h>
51129876Sphk#include <sys/mount.h>
52164033Srwatson#include <sys/vnode.h>
5398943Sluigi#include <sys/namei.h>
54155201Scsjp#include <sys/mbuf.h>
5598943Sluigi#include <sys/socket.h>
5698943Sluigi#include <sys/stat.h>
5798943Sluigi#include <sys/malloc.h>
5898943Sluigi#include <sys/sysent.h>
5998943Sluigi#include <sys/syscall.h>
60188676Sluigi
6198943Sluigi#include <vm/vm.h>
6298943Sluigi#include <vm/vm_object.h>
63171173Smlaier#include <vm/vm_extern.h>
64243586Sae#include <vm/vm_zone.h>
65185571Sbz
66175659Srwatson#include <nfs/rpcv2.h>
6798943Sluigi#include <nfs/nfsproto.h>
6898943Sluigi#include <nfs/nfs.h>
6998943Sluigi#include <nfs/nfsnode.h>
7098943Sluigi#include <nfs/xdr_subs.h>
7198943Sluigi#include <nfs/nfsm_subs.h>
7298943Sluigi#include <nfs/nfsmount.h>
7398943Sluigi#include <nfs/nqnfs.h>
74163069Sbz#include <nfs/nfsrtt.h>
75161767Sjhay
7698943Sluigi#include <netinet/in.h>
7798943Sluigi
7898943Sluigi/*
79164258Sbz * Data items converted to xdr at startup, since they are constant
80185571Sbz * This is kinda hokey, but may save a little time doing byte swaps
81145246Sbrooks */
82145246Sbrooksu_int32_t nfs_xdrneg1;
83148414Sumeu_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
84223073Sae	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
85148414Sume	rpc_auth_kerb;
86200027Sumeu_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false;
87148414Sume
88145246Sbrooks/* And other global data */
89243401Sglebiusstatic u_int32_t nfs_xid = 0;
90243401Sglebiusstatic enum vtype nv2tov_type[8]= {
9199475Sluigi	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON,  VNON
9299475Sluigi};
93188580Sluigienum vtype nv3tov_type[8]= {
94163606Srwatson	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
95188580Sluigi};
96163606Srwatson
97101628Sluigiint nfs_ticks;
98200601Sluigiint nfs_pbuf_freecnt = -1;	/* start out unlimited */
99200601Sluigi
100101628Sluigistruct nfs_reqq nfs_reqq;
10198943Sluigistruct nfssvc_sockhead nfssvc_sockhead;
102200601Sluigiint nfssvc_sockhead_flag;
103215701Sdimstruct nfsd_head nfsd_head;
104200601Sluigiint nfsd_head_flag;
105195699Srwatsonstruct nfs_bufq nfs_bufq;
106215701Sdimstruct nqtimerhead nqtimerhead;
107200601Sluigistruct nqfhhashhead *nqfhhashtbl;
108200601Sluigiu_long nqfhhash;
109225030Sbz
110225030Sbzstatic void (*nfs_prev_lease_updatetime) __P((int));
111225030Sbzstatic int nfs_prev_nfssvc_sy_narg;
112191932Sjhbstatic sy_call_t *nfs_prev_nfssvc_sy_call;
113191932Sjhb
114191932Sjhb#ifndef NFS_NOSERVER
115191932Sjhb
116191932Sjhbstatic vop_t *nfs_prev_vop_lease_check;
11798943Sluigi
118200601Sluigi/*
119220878Sbz * Mapping of old NFS Version 2 RPC numbers to generic numbers.
120193859Soleg */
121234597Smelifaroint nfsv3_procid[NFS_NPROCS] = {
122234597Smelifaro	NFSPROC_NULL,
123234597Smelifaro	NFSPROC_GETATTR,
124234597Smelifaro	NFSPROC_SETATTR,
125130363Scsjp	NFSPROC_NOOP,
126200601Sluigi	NFSPROC_LOOKUP,
127200601Sluigi	NFSPROC_READLINK,
128200601Sluigi	NFSPROC_READ,
129200601Sluigi	NFSPROC_NOOP,
130200601Sluigi	NFSPROC_WRITE,
131200601Sluigi	NFSPROC_CREATE,
132200601Sluigi	NFSPROC_REMOVE,
13398943Sluigi	NFSPROC_RENAME,
134200601Sluigi	NFSPROC_LINK,
135200601Sluigi	NFSPROC_SYMLINK,
136200601Sluigi	NFSPROC_MKDIR,
137200601Sluigi	NFSPROC_RMDIR,
138200601Sluigi	NFSPROC_READDIR,
139200601Sluigi	NFSPROC_FSSTAT,
140200601Sluigi	NFSPROC_NOOP,
141200601Sluigi	NFSPROC_NOOP,
142200601Sluigi	NFSPROC_NOOP,
143195699Srwatson	NFSPROC_NOOP,
14498943Sluigi	NFSPROC_NOOP,
145176669Spiso	NFSPROC_NOOP,
146200580Sluigi	NFSPROC_NOOP,
147176669Spiso	NFSPROC_NOOP
148176669Spiso};
149176669Spiso
150176669Spiso#endif /* NFS_NOSERVER */
15198943Sluigi/*
15298943Sluigi * and the reverse mapping from generic to Version 2 procedure numbers
153204591Sluigi */
154234597Smelifaroint nfsv2_procid[NFS_NPROCS] = {
155204591Sluigi	NFSV2PROC_NULL,
156204591Sluigi	NFSV2PROC_GETATTR,
157204591Sluigi	NFSV2PROC_SETATTR,
15898943Sluigi	NFSV2PROC_LOOKUP,
159200601Sluigi	NFSV2PROC_NOOP,
160200601Sluigi	NFSV2PROC_READLINK,
161200601Sluigi	NFSV2PROC_READ,
162195699Srwatson	NFSV2PROC_WRITE,
163195862Sjulian	NFSV2PROC_CREATE,
164195862Sjulian	NFSV2PROC_MKDIR,
165195699Srwatson	NFSV2PROC_SYMLINK,
166195862Sjulian	NFSV2PROC_CREATE,
167195862Sjulian	NFSV2PROC_REMOVE,
168195699Srwatson	NFSV2PROC_RMDIR,
169195699Srwatson	NFSV2PROC_RENAME,
170186048Sbz	NFSV2PROC_LINK,
171182818Srik	NFSV2PROC_READDIR,
172204591Sluigi	NFSV2PROC_NOOP,
173195862Sjulian	NFSV2PROC_STATFS,
174234597Smelifaro	NFSV2PROC_NOOP,
175234597Smelifaro	NFSV2PROC_NOOP,
176234597Smelifaro	NFSV2PROC_NOOP,
177191932Sjhb	NFSV2PROC_NOOP,
178195862Sjulian	NFSV2PROC_NOOP,
179195862Sjulian	NFSV2PROC_NOOP,
180191932Sjhb	NFSV2PROC_NOOP,
181234597Smelifaro};
182200838Sluigi
183200838Sluigi#ifndef NFS_NOSERVER
184200838Sluigi/*
185200040Sluigi * Maps errno values to nfs error numbers.
186195862Sjulian * Use NFSERR_IO as the catch all for ones not specifically defined in
187195862Sjulian * RFC 1094.
188195862Sjulian */
189195862Sjulianstatic u_char nfsrv_v2errmap[ELAST] = {
190195862Sjulian  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
191195862Sjulian  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
192225030Sbz  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
193225030Sbz  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
194225030Sbz  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
195200040Sluigi  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
19698943Sluigi  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
197204591Sluigi  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
198204591Sluigi  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
199187821Sluigi  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
20098943Sluigi  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
201200580Sluigi  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
202149020Sbz  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
203200601Sluigi  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
204145093Sbrooks  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
205145093Sbrooks  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
20698943Sluigi  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
207145093Sbrooks  NFSERR_IO /* << Last is 86 */
208145093Sbrooks};
209164258Sbz
210145093Sbrooks/*
211145565Sbrooks * Maps errno values to nfs error numbers.
212145246Sbrooks * Although it is not obvious whether or not NFS clients really care if
21398943Sluigi * a returned error value is in the specified list for the procedure, the
21499622Sluigi * safest thing to do is filter them appropriately. For Version 2, the
215145565Sbrooks * X/Open XNFS document is the only specification that defines error values
21698943Sluigi * for each RPC (The RFC simply lists all possible error values for all RPCs),
217145093Sbrooks * so I have decided to not do this for Version 2.
21898943Sluigi * The first entry is the default error return and the rest are the valid
21998943Sluigi * errors for that RPC in increasing numeric order.
22098943Sluigi */
22198943Sluigistatic short nfsv3err_null[] = {
22298943Sluigi	0,
22398943Sluigi	0,
22498943Sluigi};
22598943Sluigi
226145565Sbrooksstatic short nfsv3err_getattr[] = {
22798943Sluigi	NFSERR_IO,
228145093Sbrooks	NFSERR_IO,
229145093Sbrooks	NFSERR_STALE,
23098943Sluigi	NFSERR_BADHANDLE,
23198943Sluigi	NFSERR_SERVERFAULT,
23298943Sluigi	0,
23398943Sluigi};
23498943Sluigi
23598943Sluigistatic short nfsv3err_setattr[] = {
23698943Sluigi	NFSERR_IO,
23798943Sluigi	NFSERR_PERM,
23898943Sluigi	NFSERR_IO,
23998943Sluigi	NFSERR_ACCES,
24098943Sluigi	NFSERR_INVAL,
24198943Sluigi	NFSERR_NOSPC,
24298943Sluigi	NFSERR_ROFS,
24398943Sluigi	NFSERR_DQUOT,
24498943Sluigi	NFSERR_STALE,
24598943Sluigi	NFSERR_BADHANDLE,
24698943Sluigi	NFSERR_NOT_SYNC,
24798943Sluigi	NFSERR_SERVERFAULT,
24898943Sluigi	0,
24998943Sluigi};
25098943Sluigi
25198943Sluigistatic short nfsv3err_lookup[] = {
25298943Sluigi	NFSERR_IO,
25398943Sluigi	NFSERR_NOENT,
25498943Sluigi	NFSERR_IO,
25598943Sluigi	NFSERR_ACCES,
25698943Sluigi	NFSERR_NOTDIR,
25798943Sluigi	NFSERR_NAMETOL,
25898943Sluigi	NFSERR_STALE,
25998943Sluigi	NFSERR_BADHANDLE,
26098943Sluigi	NFSERR_SERVERFAULT,
26198943Sluigi	0,
26298943Sluigi};
26398943Sluigi
26498943Sluigistatic short nfsv3err_access[] = {
26598943Sluigi	NFSERR_IO,
26698943Sluigi	NFSERR_IO,
26798943Sluigi	NFSERR_STALE,
26898943Sluigi	NFSERR_BADHANDLE,
26998943Sluigi	NFSERR_SERVERFAULT,
27098943Sluigi	0,
27198943Sluigi};
27298943Sluigi
27398943Sluigistatic short nfsv3err_readlink[] = {
27498943Sluigi	NFSERR_IO,
27598943Sluigi	NFSERR_IO,
27698943Sluigi	NFSERR_ACCES,
27798943Sluigi	NFSERR_INVAL,
27898943Sluigi	NFSERR_STALE,
27998943Sluigi	NFSERR_BADHANDLE,
28098943Sluigi	NFSERR_NOTSUPP,
28198943Sluigi	NFSERR_SERVERFAULT,
28298943Sluigi	0,
28398943Sluigi};
28498943Sluigi
28598943Sluigistatic short nfsv3err_read[] = {
28698943Sluigi	NFSERR_IO,
28798943Sluigi	NFSERR_IO,
28898943Sluigi	NFSERR_NXIO,
28998943Sluigi	NFSERR_ACCES,
29098943Sluigi	NFSERR_INVAL,
29198943Sluigi	NFSERR_STALE,
29298943Sluigi	NFSERR_BADHANDLE,
29398943Sluigi	NFSERR_SERVERFAULT,
29498943Sluigi	0,
29598943Sluigi};
29698943Sluigi
29798943Sluigistatic short nfsv3err_write[] = {
29898943Sluigi	NFSERR_IO,
29998943Sluigi	NFSERR_IO,
30098943Sluigi	NFSERR_ACCES,
30198943Sluigi	NFSERR_INVAL,
30298943Sluigi	NFSERR_FBIG,
30398943Sluigi	NFSERR_NOSPC,
30498943Sluigi	NFSERR_ROFS,
305145093Sbrooks	NFSERR_DQUOT,
30698943Sluigi	NFSERR_STALE,
30798943Sluigi	NFSERR_BADHANDLE,
30898943Sluigi	NFSERR_SERVERFAULT,
30998943Sluigi	0,
31098943Sluigi};
31198943Sluigi
31298943Sluigistatic short nfsv3err_create[] = {
31398943Sluigi	NFSERR_IO,
31498943Sluigi	NFSERR_IO,
31598943Sluigi	NFSERR_ACCES,
31698943Sluigi	NFSERR_EXIST,
31798943Sluigi	NFSERR_NOTDIR,
31898943Sluigi	NFSERR_NOSPC,
31998943Sluigi	NFSERR_ROFS,
32098943Sluigi	NFSERR_NAMETOL,
32198943Sluigi	NFSERR_DQUOT,
32298943Sluigi	NFSERR_STALE,
32398943Sluigi	NFSERR_BADHANDLE,
32498943Sluigi	NFSERR_NOTSUPP,
32598943Sluigi	NFSERR_SERVERFAULT,
32698943Sluigi	0,
32798943Sluigi};
32898943Sluigi
32998943Sluigistatic short nfsv3err_mkdir[] = {
33098943Sluigi	NFSERR_IO,
33198943Sluigi	NFSERR_IO,
33298943Sluigi	NFSERR_ACCES,
33398943Sluigi	NFSERR_EXIST,
33498943Sluigi	NFSERR_NOTDIR,
33598943Sluigi	NFSERR_NOSPC,
33698943Sluigi	NFSERR_ROFS,
33798943Sluigi	NFSERR_NAMETOL,
33898943Sluigi	NFSERR_DQUOT,
33998943Sluigi	NFSERR_STALE,
34098943Sluigi	NFSERR_BADHANDLE,
34198943Sluigi	NFSERR_NOTSUPP,
34298943Sluigi	NFSERR_SERVERFAULT,
34398943Sluigi	0,
34498943Sluigi};
34598943Sluigi
34698943Sluigistatic short nfsv3err_symlink[] = {
34798943Sluigi	NFSERR_IO,
34898943Sluigi	NFSERR_IO,
34998943Sluigi	NFSERR_ACCES,
35098943Sluigi	NFSERR_EXIST,
351234597Smelifaro	NFSERR_NOTDIR,
35298943Sluigi	NFSERR_NOSPC,
35398943Sluigi	NFSERR_ROFS,
35498943Sluigi	NFSERR_NAMETOL,
35598943Sluigi	NFSERR_DQUOT,
35699475Sluigi	NFSERR_STALE,
357234597Smelifaro	NFSERR_BADHANDLE,
358234597Smelifaro	NFSERR_NOTSUPP,
359234597Smelifaro	NFSERR_SERVERFAULT,
36098943Sluigi	0,
361121816Sbrooks};
362121816Sbrooks
363121816Sbrooksstatic short nfsv3err_mknod[] = {
364121816Sbrooks	NFSERR_IO,
365121816Sbrooks	NFSERR_IO,
366121816Sbrooks	NFSERR_ACCES,
367121816Sbrooks	NFSERR_EXIST,
36898943Sluigi	NFSERR_NOTDIR,
369210120Sluigi	NFSERR_NOSPC,
37098943Sluigi	NFSERR_ROFS,
37198943Sluigi	NFSERR_NAMETOL,
372195023Srwatson	NFSERR_DQUOT,
37398943Sluigi	NFSERR_STALE,
37498943Sluigi	NFSERR_BADHANDLE,
37598943Sluigi	NFSERR_NOTSUPP,
37698943Sluigi	NFSERR_SERVERFAULT,
377191288Srwatson	NFSERR_BADTYPE,
378195023Srwatson	0,
37998943Sluigi};
380191288Srwatson
38198943Sluigistatic short nfsv3err_remove[] = {
382195023Srwatson	NFSERR_IO,
383204591Sluigi	NFSERR_NOENT,
38498943Sluigi	NFSERR_IO,
38598943Sluigi	NFSERR_ACCES,
38698943Sluigi	NFSERR_NOTDIR,
38798943Sluigi	NFSERR_ROFS,
388112250Scjc	NFSERR_NAMETOL,
389128575Sandre	NFSERR_STALE,
390128575Sandre	NFSERR_BADHANDLE,
391128575Sandre	NFSERR_SERVERFAULT,
392112250Scjc	0,
393116763Sluigi};
394200601Sluigi
395200601Sluigistatic short nfsv3err_rmdir[] = {
396200601Sluigi	NFSERR_IO,
397200601Sluigi	NFSERR_NOENT,
398200601Sluigi	NFSERR_IO,
399200601Sluigi	NFSERR_ACCES,
400128575Sandre	NFSERR_EXIST,
401112250Scjc	NFSERR_NOTDIR,
402112250Scjc	NFSERR_INVAL,
403128575Sandre	NFSERR_ROFS,
404112250Scjc	NFSERR_NAMETOL,
405200601Sluigi	NFSERR_NOTEMPTY,
406200601Sluigi	NFSERR_STALE,
407200601Sluigi	NFSERR_BADHANDLE,
408112250Scjc	NFSERR_NOTSUPP,
409112250Scjc	NFSERR_SERVERFAULT,
410178888Sjulian	0,
411112250Scjc};
412204591Sluigi
413204591Sluigistatic short nfsv3err_rename[] = {
414204591Sluigi	NFSERR_IO,
415123000Sandre	NFSERR_NOENT,
416112250Scjc	NFSERR_IO,
417112250Scjc	NFSERR_ACCES,
418123000Sandre	NFSERR_EXIST,
419123000Sandre	NFSERR_XDEV,
420112250Scjc	NFSERR_NOTDIR,
421123000Sandre	NFSERR_ISDIR,
422123000Sandre	NFSERR_INVAL,
423123000Sandre	NFSERR_NOSPC,
424186119Sqingli	NFSERR_ROFS,
425112250Scjc	NFSERR_MLINK,
426122922Sandre	NFSERR_NAMETOL,
427112250Scjc	NFSERR_NOTEMPTY,
428128575Sandre	NFSERR_DQUOT,
429154769Soleg	NFSERR_STALE,
430154769Soleg	NFSERR_BADHANDLE,
431154769Soleg	NFSERR_NOTSUPP,
432154769Soleg	NFSERR_SERVERFAULT,
433154769Soleg	0,
434154769Soleg};
435154769Soleg
436154769Solegstatic short nfsv3err_link[] = {
437122922Sandre	NFSERR_IO,
438122922Sandre	NFSERR_IO,
439122922Sandre	NFSERR_ACCES,
440128575Sandre	NFSERR_EXIST,
441128575Sandre	NFSERR_XDEV,
442128575Sandre	NFSERR_NOTDIR,
443128575Sandre	NFSERR_INVAL,
444128575Sandre	NFSERR_NOSPC,
445128575Sandre	NFSERR_ROFS,
446128575Sandre	NFSERR_MLINK,
447128575Sandre	NFSERR_NAMETOL,
448132510Sandre	NFSERR_DQUOT,
449132510Sandre	NFSERR_STALE,
450132510Sandre	NFSERR_BADHANDLE,
451132510Sandre	NFSERR_NOTSUPP,
452132510Sandre	NFSERR_SERVERFAULT,
453132510Sandre	0,
454128575Sandre};
455122922Sandre
456116981Sluigistatic short nfsv3err_readdir[] = {
457204591Sluigi	NFSERR_IO,
458112250Scjc	NFSERR_IO,
459112250Scjc	NFSERR_ACCES,
460145266Sphk	NFSERR_NOTDIR,
461145246Sbrooks	NFSERR_STALE,
462145246Sbrooks	NFSERR_BADHANDLE,
463145246Sbrooks	NFSERR_BAD_COOKIE,
464145246Sbrooks	NFSERR_TOOSMALL,
465145246Sbrooks	NFSERR_SERVERFAULT,
466145246Sbrooks	0,
467147415Smlaier};
468145246Sbrooks
469112250Scjcstatic short nfsv3err_readdirplus[] = {
470145246Sbrooks	NFSERR_IO,
471145246Sbrooks	NFSERR_IO,
472145246Sbrooks	NFSERR_ACCES,
473147415Smlaier	NFSERR_NOTDIR,
474147415Smlaier	NFSERR_STALE,
475147415Smlaier	NFSERR_BADHANDLE,
476147415Smlaier	NFSERR_BAD_COOKIE,
477147415Smlaier	NFSERR_NOTSUPP,
478145246Sbrooks	NFSERR_TOOSMALL,
479145246Sbrooks	NFSERR_SERVERFAULT,
480145246Sbrooks	0,
481145246Sbrooks};
482145246Sbrooks
483145246Sbrooksstatic short nfsv3err_fsstat[] = {
484147415Smlaier	NFSERR_IO,
485147415Smlaier	NFSERR_IO,
486147415Smlaier	NFSERR_STALE,
487147415Smlaier	NFSERR_BADHANDLE,
488145246Sbrooks	NFSERR_SERVERFAULT,
489191288Srwatson	0,
490195023Srwatson};
491191338Srwatson
492147415Smlaierstatic short nfsv3err_fsinfo[] = {
493147415Smlaier	NFSERR_STALE,
494147415Smlaier	NFSERR_STALE,
495147415Smlaier	NFSERR_BADHANDLE,
496147415Smlaier	NFSERR_SERVERFAULT,
497191288Srwatson	0,
498195023Srwatson};
499147415Smlaier
500191288Srwatsonstatic short nfsv3err_pathconf[] = {
501147415Smlaier	NFSERR_STALE,
502147415Smlaier	NFSERR_STALE,
503195023Srwatson	NFSERR_BADHANDLE,
504191288Srwatson	NFSERR_SERVERFAULT,
505147415Smlaier	0,
506145246Sbrooks};
507145246Sbrooks
508145246Sbrooksstatic short nfsv3err_commit[] = {
509232292Sbz	NFSERR_IO,
510145246Sbrooks	NFSERR_IO,
511147418Smlaier	NFSERR_STALE,
512147415Smlaier	NFSERR_BADHANDLE,
513145246Sbrooks	NFSERR_SERVERFAULT,
514147418Smlaier	0,
515147418Smlaier};
516147415Smlaier
517147418Smlaierstatic short *nfsrv_v3errmap[] = {
518147418Smlaier	nfsv3err_null,
519147418Smlaier	nfsv3err_getattr,
520145246Sbrooks	nfsv3err_setattr,
521232292Sbz	nfsv3err_lookup,
522147418Smlaier	nfsv3err_access,
523147418Smlaier	nfsv3err_readlink,
524147418Smlaier	nfsv3err_read,
525152288Ssuz	nfsv3err_write,
526152288Ssuz	nfsv3err_create,
527152288Ssuz	nfsv3err_mkdir,
528152288Ssuz	nfsv3err_symlink,
529152288Ssuz	nfsv3err_mknod,
530152288Ssuz	nfsv3err_remove,
531152288Ssuz	nfsv3err_rmdir,
532152288Ssuz	nfsv3err_rename,
533147418Smlaier	nfsv3err_link,
534147418Smlaier	nfsv3err_readdir,
535147415Smlaier	nfsv3err_readdirplus,
536147418Smlaier	nfsv3err_fsstat,
537147418Smlaier	nfsv3err_fsinfo,
538147418Smlaier	nfsv3err_pathconf,
539147418Smlaier	nfsv3err_commit,
540147418Smlaier};
541147415Smlaier
542147418Smlaier#endif /* NFS_NOSERVER */
543147418Smlaier
544147418Smlaierextern struct nfsrtt nfsrtt;
545147418Smlaierextern time_t nqnfsstarttime;
546147418Smlaierextern int nqsrv_clockskew;
547147418Smlaierextern int nqsrv_writeslack;
548147418Smlaierextern int nqsrv_maxlease;
549147418Smlaierextern struct nfsstats nfsstats;
550147418Smlaierextern int nqnfs_piggy[NFS_NPROCS];
551147418Smlaierextern nfstype nfsv2_type[9];
552147415Smlaierextern nfstype nfsv3_type[9];
553147418Smlaierextern struct nfsnodehashhead *nfsnodehashtbl;
554145246Sbrooksextern u_long nfsnodehash;
555200601Sluigi
556149020Sbzstruct nfssvc_args;
557149020Sbzextern int nfssvc(struct proc *, struct nfssvc_args *, int *);
558149020Sbz
559149020SbzLIST_HEAD(nfsnodehashhead, struct nfsnode);
560149020Sbz
561149020Sbzint nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
562149020Sbz
563149020Sbzu_quad_t
564149020Sbznfs_curusec()
565149020Sbz{
566149020Sbz	struct timeval tv;
567149020Sbz
568149020Sbz	getmicrotime(&tv);
569149020Sbz	return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec);
570149020Sbz}
571165738Sjulian
572149020Sbz/*
573165738Sjulian * Create the header for an rpc request packet
574165738Sjulian * The hsiz is the size of the rest of the nfs request header.
575165738Sjulian * (just used to decide if a cluster is a good idea)
576160025Sbz */
577149020Sbzstruct mbuf *
578165738Sjuliannfsm_reqh(vp, procid, hsiz, bposp)
579149020Sbz	struct vnode *vp;
580200027Sume	u_long procid;
581200027Sume	int hsiz;
582200601Sluigi	caddr_t *bposp;
583200027Sume{
584200027Sume	register struct mbuf *mb;
585200027Sume	register u_int32_t *tl;
586200027Sume	register caddr_t bpos;
587200027Sume	struct mbuf *mb2;
588149020Sbz	struct nfsmount *nmp;
589201527Sluigi	int nqflag;
590149020Sbz
591165738Sjulian	MGET(mb, M_WAIT, MT_DATA);
592165738Sjulian	if (hsiz >= MINCLSIZE)
593165738Sjulian		MCLGET(mb, M_WAIT);
594165738Sjulian	mb->m_len = 0;
595165738Sjulian	bpos = mtod(mb, caddr_t);
596165738Sjulian
597165738Sjulian	/*
598165738Sjulian	 * For NQNFS, add lease request.
599165738Sjulian	 */
600165738Sjulian	if (vp) {
601165738Sjulian		nmp = VFSTONFS(vp->v_mount);
602165738Sjulian		if (nmp->nm_flag & NFSMNT_NQNFS) {
603165738Sjulian			nqflag = NQNFS_NEEDLEASE(vp, procid);
604149020Sbz			if (nqflag) {
605201527Sluigi				nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED);
606149020Sbz				*tl++ = txdr_unsigned(nqflag);
607149020Sbz				*tl = txdr_unsigned(nmp->nm_leaseterm);
608149020Sbz			} else {
609149020Sbz				nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
610145266Sphk				*tl = 0;
611145266Sphk			}
61298943Sluigi		}
61398943Sluigi	}
61498943Sluigi	/* Finally, return values */
61598943Sluigi	*bposp = bpos;
61698943Sluigi	return (mb);
617201122Sluigi}
61898943Sluigi
619101843Sphk/*
620165738Sjulian * Build the RPC header and fill in the authorization info.
621165738Sjulian * The authorization string argument is only used when the credentials
622165738Sjulian * come from outside of the kernel.
623165738Sjulian * Returns the head of the mbuf list.
624165738Sjulian */
625165738Sjulianstruct mbuf *
626165738Sjuliannfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
627165738Sjulian	verf_str, mrest, mrest_len, mbp, xidp)
628165738Sjulian	register struct ucred *cr;
629165738Sjulian	int nmflag;
630108327Siedowse	int procid;
631108327Siedowse	int auth_type;
632201527Sluigi	int auth_len;
63399475Sluigi	char *auth_str;
634160025Sbz	int verf_len;
63599475Sluigi	char *verf_str;
63699475Sluigi	struct mbuf *mrest;
637147247Sgreen	int mrest_len;
638147247Sgreen	struct mbuf **mbp;
639200601Sluigi	u_int32_t *xidp;
640162238Scsjp{
641100004Sluigi	register struct mbuf *mb;
642147247Sgreen	register u_int32_t *tl;
643147247Sgreen	register caddr_t bpos;
644147247Sgreen	register int i;
645201527Sluigi	struct mbuf *mreq, *mb2;
64699475Sluigi	int siz, grpsiz, authsiz;
647201527Sluigi
64899475Sluigi	authsiz = nfsm_rndup(auth_len);
64998943Sluigi	MGETHDR(mb, M_WAIT, MT_DATA);
65098943Sluigi	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
651200601Sluigi		MCLGET(mb, M_WAIT);
652200601Sluigi	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
653200601Sluigi		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
654200601Sluigi	} else {
655200601Sluigi		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
656200601Sluigi	}
657200601Sluigi	mb->m_len = 0;
658200601Sluigi	mreq = mb;
659200601Sluigi	bpos = mtod(mb, caddr_t);
660200601Sluigi
661122265Ssam	/*
662223073Sae	 * First the RPC header.
663223073Sae	 */
664122265Ssam	nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
665204591Sluigi
666223073Sae	/* Get a pretty random xid to start with */
667204591Sluigi	if (!nfs_xid)
668204591Sluigi		nfs_xid = random();
669204591Sluigi	/*
670204591Sluigi	 * Skip zero xid if it should ever happen.
671223073Sae	 */
672122265Ssam	if (++nfs_xid == 0)
673223073Sae		nfs_xid++;
674223073Sae
675223073Sae	*tl++ = *xidp = txdr_unsigned(nfs_xid);
676222488Srwatson	*tl++ = rpc_call;
677122265Ssam	*tl++ = rpc_vers;
678122265Ssam	if (nmflag & NFSMNT_NQNFS) {
679223073Sae		*tl++ = txdr_unsigned(NQNFS_PROG);
680223073Sae		*tl++ = txdr_unsigned(NQNFS_VER3);
681223073Sae	} else {
682223073Sae		*tl++ = txdr_unsigned(NFS_PROG);
683130363Scsjp		if (nmflag & NFSMNT_NFSV3)
684135920Smlaier			*tl++ = txdr_unsigned(NFS_VER3);
685135920Smlaier		else
686135920Smlaier			*tl++ = txdr_unsigned(NFS_VER2);
687135920Smlaier	}
688183398Srwatson	if (nmflag & NFSMNT_NFSV3)
689178325Srwatson		*tl++ = txdr_unsigned(procid);
690135920Smlaier	else
691194498Sbrooks		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
692183398Srwatson
693183418Srwatson	/*
694183418Srwatson	 * And then the authorization cred.
695135920Smlaier	 */
696135920Smlaier	*tl++ = txdr_unsigned(auth_type);
697130363Scsjp	*tl = txdr_unsigned(authsiz);
698130363Scsjp	switch (auth_type) {
699130363Scsjp	case RPCAUTH_UNIX:
700130363Scsjp		nfsm_build(tl, u_int32_t *, auth_len);
701183398Srwatson		*tl++ = 0;		/* stamp ?? */
702130363Scsjp		*tl++ = 0;		/* NULL hostname */
703223073Sae		*tl++ = txdr_unsigned(cr->cr_uid);
704222488Srwatson		*tl++ = txdr_unsigned(cr->cr_groups[0]);
705181803Sbz		grpsiz = (auth_len >> 2) - 5;
706223073Sae		*tl++ = txdr_unsigned(grpsiz);
707222488Srwatson		for (i = 1; i <= grpsiz; i++)
708181803Sbz			*tl++ = txdr_unsigned(cr->cr_groups[i]);
709122265Ssam		break;
710122265Ssam	case RPCAUTH_KERB4:
711222488Srwatson		siz = auth_len;
712122265Ssam		while (siz > 0) {
713183398Srwatson			if (M_TRAILINGSPACE(mb) == 0) {
714223073Sae				MGET(mb2, M_WAIT, MT_DATA);
715223073Sae				if (siz >= MINCLSIZE)
716223073Sae					MCLGET(mb2, M_WAIT);
717223073Sae				mb->m_next = mb2;
718223073Sae				mb = mb2;
719223073Sae				mb->m_len = 0;
720223073Sae				bpos = mtod(mb, caddr_t);
721223073Sae			}
722223073Sae			i = min(siz, M_TRAILINGSPACE(mb));
723223073Sae			bcopy(auth_str, bpos, i);
724223073Sae			mb->m_len += i;
725223073Sae			auth_str += i;
726223073Sae			bpos += i;
727223073Sae			siz -= i;
728223073Sae		}
729223073Sae		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
730223073Sae			for (i = 0; i < siz; i++)
731223073Sae				*bpos++ = '\0';
732223073Sae			mb->m_len += siz;
733223073Sae		}
734223073Sae		break;
735223073Sae	};
736223073Sae
737223073Sae	/*
738223073Sae	 * And the verifier...
739223073Sae	 */
740223073Sae	nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
741223073Sae	if (verf_str) {
742223073Sae		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
743223073Sae		*tl = txdr_unsigned(verf_len);
744130363Scsjp		siz = verf_len;
745222488Srwatson		while (siz > 0) {
746196201Sjulian			if (M_TRAILINGSPACE(mb) == 0) {
747183606Sbz				MGET(mb2, M_WAIT, MT_DATA);
748222488Srwatson				if (siz >= MINCLSIZE)
749122265Ssam					MCLGET(mb2, M_WAIT);
750183398Srwatson				mb->m_next = mb2;
751130363Scsjp				mb = mb2;
752200601Sluigi				mb->m_len = 0;
753200601Sluigi				bpos = mtod(mb, caddr_t);
754130363Scsjp			}
755183398Srwatson			i = min(siz, M_TRAILINGSPACE(mb));
756130363Scsjp			bcopy(verf_str, bpos, i);
757130363Scsjp			mb->m_len += i;
758223073Sae			verf_str += i;
759130363Scsjp			bpos += i;
760194498Sbrooks			siz -= i;
761194498Sbrooks		}
762194498Sbrooks		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
763194498Sbrooks			for (i = 0; i < siz; i++)
764194498Sbrooks				*bpos++ = '\0';
765223073Sae			mb->m_len += siz;
766204591Sluigi		}
767122265Ssam	} else {
768122265Ssam		*tl++ = txdr_unsigned(RPCAUTH_NULL);
76998943Sluigi		*tl = 0;
770201527Sluigi	}
771201527Sluigi	mb->m_next = mrest;
772201527Sluigi	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
773200838Sluigi	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
774200838Sluigi	*mbp = mb;
775200855Sluigi	return (mreq);
776200855Sluigi}
777200838Sluigi
778201527Sluigi/*
779201527Sluigi * copies mbuf chain to the uio scatter/gather list
780201527Sluigi */
781201527Sluigiint
782200838Sluiginfsm_mbuftouio(mrep, uiop, siz, dpos)
783200838Sluigi	struct mbuf **mrep;
784200838Sluigi	register struct uio *uiop;
78598943Sluigi	int siz;
78698943Sluigi	caddr_t *dpos;
78798943Sluigi{
78898943Sluigi	register char *mbufcp, *uiocp;
78998943Sluigi	register int xfer, left, len;
79098943Sluigi	register struct mbuf *mp;
79198943Sluigi	long uiosiz, rem;
79298943Sluigi	int error = 0;
79398943Sluigi
794200601Sluigi	mp = *mrep;
795165738Sjulian	mbufcp = *dpos;
796165738Sjulian	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
797200601Sluigi	rem = nfsm_rndup(siz)-siz;
79898943Sluigi	while (siz > 0) {
79998943Sluigi		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
80098943Sluigi			return (EFBIG);
80198943Sluigi		left = uiop->uio_iov->iov_len;
80298943Sluigi		uiocp = uiop->uio_iov->iov_base;
80398943Sluigi		if (left > siz)
80498943Sluigi			left = siz;
805225044Sbz		uiosiz = left;
80698943Sluigi		while (left > 0) {
807201527Sluigi			while (len == 0) {
80898943Sluigi				mp = mp->m_next;
80998943Sluigi				if (mp == NULL)
81098943Sluigi					return (EBADRPC);
811140224Sglebius				mbufcp = mtod(mp, caddr_t);
812140224Sglebius				len = mp->m_len;
813140224Sglebius			}
814140224Sglebius			xfer = (left > len) ? len : left;
815140224Sglebius#ifdef notdef
816140224Sglebius			/* Not Yet.. */
817201527Sluigi			if (uiop->uio_iov->iov_op != NULL)
818201527Sluigi				(*(uiop->uio_iov->iov_op))
81998943Sluigi				(mbufcp, uiocp, xfer);
82098943Sluigi			else
821133920Sandre#endif
82298943Sluigi			if (uiop->uio_segflg == UIO_SYSSPACE)
82398943Sluigi				bcopy(mbufcp, uiocp, xfer);
824183550Szec			else
82598943Sluigi				copyout(mbufcp, uiocp, xfer);
826200601Sluigi			left -= xfer;
82798943Sluigi			len -= xfer;
82898943Sluigi			mbufcp += xfer;
82998943Sluigi			uiocp += xfer;
83098943Sluigi			uiop->uio_offset += xfer;
83198943Sluigi			uiop->uio_resid -= xfer;
83298943Sluigi		}
833101978Sluigi		if (uiop->uio_iov->iov_len <= siz) {
83498943Sluigi			uiop->uio_iovcnt--;
83598943Sluigi			uiop->uio_iov++;
836165738Sjulian		} else {
837165738Sjulian			uiop->uio_iov->iov_base += uiosiz;
83898943Sluigi			uiop->uio_iov->iov_len -= uiosiz;
83998943Sluigi		}
84098943Sluigi		siz -= uiosiz;
84198943Sluigi	}
84298943Sluigi	*dpos = mbufcp;
84398943Sluigi	*mrep = mp;
844165738Sjulian	if (rem > 0) {
845165738Sjulian		if (len < rem)
846165738Sjulian			error = nfs_adv(mrep, dpos, rem, len);
847165738Sjulian		else
84898943Sluigi			*dpos += rem;
84998943Sluigi	}
85098943Sluigi	return (error);
85198943Sluigi}
85298943Sluigi
853130363Scsjp/*
854130363Scsjp * copies a uio scatter/gather list to an mbuf chain.
855130363Scsjp * NOTE: can ony handle iovcnt == 1
856130363Scsjp */
857130363Scsjpint
858130363Scsjpnfsm_uiotombuf(uiop, mq, siz, bpos)
859204591Sluigi	register struct uio *uiop;
860204591Sluigi	struct mbuf **mq;
861204591Sluigi	int siz;
862194498Sbrooks	caddr_t *bpos;
863204591Sluigi{
864194498Sbrooks	register char *uiocp;
865130363Scsjp	register struct mbuf *mp, *mp2;
866130363Scsjp	register int xfer, left, mlen;
86798943Sluigi	int uiosiz, clflg, rem;
868150636Smlaier	char *cp;
86998943Sluigi
87098943Sluigi#ifdef DIAGNOSTIC
87198943Sluigi	if (uiop->uio_iovcnt != 1)
87298943Sluigi		panic("nfsm_uiotombuf: iovcnt != 1");
87398943Sluigi#endif
874200855Sluigi
87598943Sluigi	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
87698943Sluigi		clflg = 1;
87798943Sluigi	else
878147758Smlaier		clflg = 0;
87998943Sluigi	rem = nfsm_rndup(siz)-siz;
88098943Sluigi	mp = mp2 = *mq;
88198943Sluigi	while (siz > 0) {
88298943Sluigi		left = uiop->uio_iov->iov_len;
88398943Sluigi		uiocp = uiop->uio_iov->iov_base;
88498943Sluigi		if (left > siz)
88598943Sluigi			left = siz;
88698943Sluigi		uiosiz = left;
887225032Sbz		while (left > 0) {
888225032Sbz			mlen = M_TRAILINGSPACE(mp);
889225032Sbz			if (mlen == 0) {
890225032Sbz				MGET(mp, M_WAIT, MT_DATA);
891225030Sbz				if (clflg)
89298943Sluigi					MCLGET(mp, M_WAIT);
89398943Sluigi				mp->m_len = 0;
894225032Sbz				mp2->m_next = mp;
89598943Sluigi				mp2 = mp;
89698943Sluigi				mlen = M_TRAILINGSPACE(mp);
89798943Sluigi			}
89898943Sluigi			xfer = (left > mlen) ? mlen : left;
89998943Sluigi#ifdef notdef
90098943Sluigi			/* Not Yet.. */
90198943Sluigi			if (uiop->uio_iov->iov_op != NULL)
90298943Sluigi				(*(uiop->uio_iov->iov_op))
90398943Sluigi				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
90498943Sluigi			else
90598943Sluigi#endif
90698943Sluigi			if (uiop->uio_segflg == UIO_SYSSPACE)
90798943Sluigi				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
90898943Sluigi			else
90998943Sluigi				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
910201122Sluigi			mp->m_len += xfer;
911201122Sluigi			left -= xfer;
91298943Sluigi			uiocp += xfer;
913201122Sluigi			uiop->uio_offset += xfer;
914115750Skbyanc			uiop->uio_resid -= xfer;
915201122Sluigi		}
916145093Sbrooks		uiop->uio_iov->iov_base += uiosiz;
917145093Sbrooks		uiop->uio_iov->iov_len -= uiosiz;
918145093Sbrooks		siz -= uiosiz;
919145093Sbrooks	}
920145093Sbrooks	if (rem > 0) {
921145093Sbrooks		if (rem > M_TRAILINGSPACE(mp)) {
92298943Sluigi			MGET(mp, M_WAIT, MT_DATA);
92398943Sluigi			mp->m_len = 0;
924181803Sbz			mp2->m_next = mp;
92598943Sluigi		}
92698943Sluigi		cp = mtod(mp, caddr_t)+mp->m_len;
927145093Sbrooks		for (left = 0; left < rem; left++)
928145093Sbrooks			*cp++ = '\0';
929145093Sbrooks		mp->m_len += rem;
930145093Sbrooks		*bpos = cp;
93198943Sluigi	} else
932145093Sbrooks		*bpos = mtod(mp, caddr_t)+mp->m_len;
933205173Sluigi	*mq = mp;
934145246Sbrooks	return (0);
935145246Sbrooks}
936205173Sluigi
937205173Sluigi/*
938145246Sbrooks * Help break down an mbuf chain by setting the first siz bytes contiguous
939205173Sluigi * pointed to by returned val.
940146894Smlaier * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
94198943Sluigi * cases. (The macros use the vars. dpos and dpos2)
942200059Sluigi */
943200059Sluigiint
944196423Sjuliannfsm_disct(mdp, dposp, siz, left, cp2)
945145093Sbrooks	struct mbuf **mdp;
946145093Sbrooks	caddr_t *dposp;
947187822Sluigi	int siz;
948200040Sluigi	int left;
949115750Skbyanc	caddr_t *cp2;
950178888Sjulian{
951145093Sbrooks	register struct mbuf *mp, *mp2;
952149020Sbz	register int siz2, xfer;
95398943Sluigi	register caddr_t p;
954145093Sbrooks
955145093Sbrooks	mp = *mdp;
956145093Sbrooks	while (left == 0) {
957145093Sbrooks		*mdp = mp = mp->m_next;
958145093Sbrooks		if (mp == NULL)
959145093Sbrooks			return (EBADRPC);
960220796Sglebius		left = mp->m_len;
961220796Sglebius		*dposp = mtod(mp, caddr_t);
962200601Sluigi	}
963220796Sglebius	if (left >= siz) {
964200601Sluigi		*cp2 = *dposp;
965200601Sluigi		*dposp += siz;
966200601Sluigi	} else if (mp->m_next == NULL) {
967200601Sluigi		return (EBADRPC);
968200601Sluigi	} else if (siz > MHLEN) {
969200601Sluigi		panic("nfs S too big");
970145093Sbrooks	} else {
97198943Sluigi		MGET(mp2, M_WAIT, MT_DATA);
972165738Sjulian		mp2->m_next = mp->m_next;
973165738Sjulian		mp->m_next = mp2;
974165738Sjulian		mp->m_len -= left;
975165738Sjulian		mp = mp2;
976165738Sjulian		*cp2 = p = mtod(mp, caddr_t);
977165738Sjulian		bcopy(*dposp, p, left);		/* Copy what was left */
978145246Sbrooks		siz2 = siz-left;
979145246Sbrooks		p += left;
980165738Sjulian		mp2 = mp->m_next;
981165738Sjulian		/* Loop around copying up the siz2 bytes */
982145246Sbrooks		while (siz2 > 0) {
983145246Sbrooks			if (mp2 == NULL)
984145246Sbrooks				return (EBADRPC);
985165738Sjulian			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
986145246Sbrooks			if (xfer > 0) {
987145246Sbrooks				bcopy(mtod(mp2, caddr_t), p, xfer);
988225033Sbz				NFSMADV(mp2, xfer);
989145246Sbrooks				mp2->m_len -= xfer;
990145246Sbrooks				p += xfer;
991145246Sbrooks				siz2 -= xfer;
992205173Sluigi			}
993145246Sbrooks			if (siz2 > 0)
994145246Sbrooks				mp2 = mp2->m_next;
995145246Sbrooks		}
996145246Sbrooks		mp->m_len = siz;
997145246Sbrooks		*mdp = mp2;
998145246Sbrooks		*dposp = mtod(mp2, caddr_t);
999205173Sluigi	}
1000205173Sluigi	return (0);
1001145246Sbrooks}
1002145246Sbrooks
1003164258Sbz/*
1004164258Sbz * Advance the position in the mbuf chain.
1005164258Sbz */
1006164258Sbzint
1007164258Sbznfs_adv(mdp, dposp, offs, left)
1008164258Sbz	struct mbuf **mdp;
1009145246Sbrooks	caddr_t *dposp;
1010145246Sbrooks	int offs;
1011145246Sbrooks	int left;
1012145246Sbrooks{
1013145246Sbrooks	register struct mbuf *m;
1014145246Sbrooks	register int s;
1015149020Sbz
1016145246Sbrooks	m = *mdp;
1017145246Sbrooks	s = left;
1018149020Sbz	while (s < offs) {
1019145246Sbrooks		offs -= s;
1020145246Sbrooks		m = m->m_next;
1021145246Sbrooks		if (m == NULL)
1022145246Sbrooks			return (EBADRPC);
1023149020Sbz		s = m->m_len;
1024145246Sbrooks	}
1025159857Sume	*mdp = m;
1026159857Sume	*dposp = mtod(m, caddr_t)+offs;
1027169245Sbz	return (0);
1028159857Sume}
1029169245Sbz
1030169245Sbz/*
1031169245Sbz * Copy a string into mbufs for the hard cases...
1032159857Sume */
1033225036Sbzint
1034225036Sbznfsm_strtmbuf(mb, bpos, cp, siz)
1035225036Sbz	struct mbuf **mb;
1036225036Sbz	char **bpos;
1037225036Sbz	const char *cp;
1038181803Sbz	long siz;
1039149020Sbz{
1040149020Sbz	register struct mbuf *m1 = NULL, *m2;
1041149020Sbz	long left, xfer, len, tlen;
1042145246Sbrooks	u_int32_t *tl;
1043149020Sbz	int putsize;
1044145246Sbrooks
1045145246Sbrooks	putsize = 1;
1046145246Sbrooks	m2 = *mb;
1047145246Sbrooks	left = M_TRAILINGSPACE(m2);
1048149020Sbz	if (left > 0) {
1049145246Sbrooks		tl = ((u_int32_t *)(*bpos));
1050145246Sbrooks		*tl++ = txdr_unsigned(siz);
1051145246Sbrooks		putsize = 0;
1052145246Sbrooks		left -= NFSX_UNSIGNED;
1053149020Sbz		m2->m_len += NFSX_UNSIGNED;
1054149020Sbz		if (left > 0) {
1055225032Sbz			bcopy(cp, (caddr_t) tl, left);
1056149020Sbz			siz -= left;
1057225030Sbz			cp += left;
1058225032Sbz			m2->m_len += left;
1059225036Sbz			left = 0;
1060225036Sbz		}
1061225036Sbz	}
1062181803Sbz	/* Loop around adding mbufs */
1063149020Sbz	while (siz > 0) {
1064149020Sbz		MGET(m1, M_WAIT, MT_DATA);
1065149020Sbz		if (siz > MLEN)
1066205173Sluigi			MCLGET(m1, M_WAIT);
1067149020Sbz		m1->m_len = NFSMSIZ(m1);
1068149020Sbz		m2->m_next = m1;
1069145246Sbrooks		m2 = m1;
1070145246Sbrooks		tl = mtod(m1, u_int32_t *);
1071149020Sbz		tlen = 0;
1072149020Sbz		if (putsize) {
1073149020Sbz			*tl++ = txdr_unsigned(siz);
1074149020Sbz			m1->m_len -= NFSX_UNSIGNED;
1075149020Sbz			tlen = NFSX_UNSIGNED;
1076149020Sbz			putsize = 0;
1077149020Sbz		}
1078149020Sbz		if (siz < m1->m_len) {
1079149020Sbz			len = nfsm_rndup(siz);
1080145246Sbrooks			xfer = siz;
1081145246Sbrooks			if (xfer < len)
1082149020Sbz				*(tl+(xfer>>2)) = 0;
1083145246Sbrooks		} else {
1084145246Sbrooks			xfer = len = m1->m_len;
1085145246Sbrooks		}
1086145246Sbrooks		bcopy(cp, (caddr_t) tl, xfer);
1087149020Sbz		m1->m_len = len+tlen;
1088149020Sbz		siz -= xfer;
1089149020Sbz		cp += xfer;
1090149020Sbz	}
1091149020Sbz	*mb = m1;
1092149020Sbz	*bpos = mtod(m1, caddr_t)+m1->m_len;
1093149020Sbz	return (0);
1094149020Sbz}
1095174479Sdwmalone
1096174479Sdwmalone/*
1097174479Sdwmalone * Called once to initialize data structures...
1098174479Sdwmalone */
1099174479Sdwmaloneint
1100174479Sdwmalonenfs_init(vfsp)
1101149020Sbz	struct vfsconf *vfsp;
1102149020Sbz{
1103146704Stanimura	register int i;
1104146704Stanimura
1105146704Stanimura	nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1);
1106146704Stanimura
1107146704Stanimura	nfs_mount_type = vfsp->vfc_typenum;
1108161767Sjhay	nfsrtt.pos = 0;
1109161767Sjhay	rpc_vers = txdr_unsigned(RPC_VER2);
1110161767Sjhay	rpc_call = txdr_unsigned(RPC_CALL);
1111161767Sjhay	rpc_reply = txdr_unsigned(RPC_REPLY);
1112161767Sjhay	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1113163069Sbz	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1114163069Sbz	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1115163069Sbz	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1116163069Sbz	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1117163069Sbz	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1118163069Sbz	nfs_prog = txdr_unsigned(NFS_PROG);
1119163069Sbz	nqnfs_prog = txdr_unsigned(NQNFS_PROG);
1120163069Sbz	nfs_true = txdr_unsigned(TRUE);
1121163069Sbz	nfs_false = txdr_unsigned(FALSE);
1122163069Sbz	nfs_xdrneg1 = txdr_unsigned(-1);
1123159857Sume	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1124159857Sume	if (nfs_ticks < 1)
1125159857Sume		nfs_ticks = 1;
1126159857Sume	/* Ensure async daemons disabled */
1127159857Sume	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
1128159857Sume		nfs_iodwant[i] = (struct proc *)0;
1129159857Sume		nfs_iodmount[i] = (struct nfsmount *)0;
1130159857Sume	}
1131145246Sbrooks	nfs_nhinit();			/* Init the nfsnode table */
1132225036Sbz#ifndef NFS_NOSERVER
1133225036Sbz	nfsrv_init(0);			/* Init server data structures */
1134225036Sbz	nfsrv_initcache();		/* Init the server request cache */
1135225036Sbz#endif
1136181803Sbz
1137149020Sbz	/*
1138159857Sume	 * Initialize the nqnfs server stuff.
1139145246Sbrooks	 */
1140145246Sbrooks	if (nqnfsstarttime == 0) {
1141145246Sbrooks		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
1142165738Sjulian			+ nqsrv_clockskew + nqsrv_writeslack;
1143165738Sjulian		NQLOADNOVRAM(nqnfsstarttime);
1144165738Sjulian		CIRCLEQ_INIT(&nqtimerhead);
1145165738Sjulian		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
1146145246Sbrooks	}
1147145246Sbrooks
1148165738Sjulian	/*
1149145246Sbrooks	 * Initialize reply list and start timer
1150165738Sjulian	 */
1151146894Smlaier	TAILQ_INIT(&nfs_reqq);
1152145093Sbrooks
1153145093Sbrooks	nfs_timer(0);
115498943Sluigi
1155145093Sbrooks	/*
1156145093Sbrooks	 * Set up lease_check and lease_updatetime so that other parts
1157145093Sbrooks	 * of the system can call us, if we are loadable.
1158145093Sbrooks	 */
1159145093Sbrooks#ifndef NFS_NOSERVER
1160145093Sbrooks	nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)];
1161201527Sluigi	default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check;
1162201527Sluigi#endif
1163201122Sluigi	nfs_prev_lease_updatetime = lease_updatetime;
116498943Sluigi	lease_updatetime = nfs_lease_updatetime;
1165145093Sbrooks	nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
1166145093Sbrooks	sysent[SYS_nfssvc].sy_narg = 2;
1167145093Sbrooks	nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
1168145093Sbrooks	sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
1169145093Sbrooks
1170145093Sbrooks	nfs_pbuf_freecnt = nswbuf / 2 + 1;
1171205173Sluigi
1172205173Sluigi	return (0);
1173145093Sbrooks}
117498943Sluigi
1175220211Saeint
1176220211Saenfs_uninit(vfsp)
1177220211Sae	struct vfsconf *vfsp;
1178220211Sae{
1179220211Sae
1180220211Sae	untimeout(nfs_timer, (void *)NULL, nfs_timer_handle);
1181145093Sbrooks	nfs_mount_type = -1;
1182145093Sbrooks#ifndef NFS_NOSERVER
1183145093Sbrooks	default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check;
1184145093Sbrooks#endif
1185145093Sbrooks	lease_updatetime = nfs_prev_lease_updatetime;
118698943Sluigi	sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
1187145093Sbrooks	sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
1188145565Sbrooks	return (0);
1189205173Sluigi}
1190145093Sbrooks
119198943Sluigi/*
1192145093Sbrooks * Attribute cache routines.
1193145093Sbrooks * nfs_loadattrcache() - loads or updates the cache contents from attributes
119498943Sluigi *	that are on the mbuf list
1195145093Sbrooks * nfs_getattrcache() - returns valid attributes if found in cache, returns
119698943Sluigi *	error otherwise
1197165738Sjulian */
1198145093Sbrooks
1199145093Sbrooks/*
1200145093Sbrooks * Load the attribute cache (that lives in the nfsnode entry) with
120198943Sluigi * the values on the mbuf list and
1202145093Sbrooks * Iff vap not NULL
1203145093Sbrooks *    copy the attributes to *vaper
1204145093Sbrooks */
1205145093Sbrooksint
120698943Sluiginfs_loadattrcache(vpp, mdp, dposp, vaper)
120798943Sluigi	struct vnode **vpp;
1208138642Scsjp	struct mbuf **mdp;
1209197952Sjulian	caddr_t *dposp;
1210197952Sjulian	struct vattr *vaper;
1211197952Sjulian{
1212197952Sjulian	register struct vnode *vp = *vpp;
1213201527Sluigi	register struct vattr *vap;
121498943Sluigi	register struct nfs_fattr *fp;
1215200629Sluigi	register struct nfsnode *np;
1216200629Sluigi	register int32_t t1;
1217201527Sluigi	caddr_t cp2;
1218200855Sluigi	int error = 0, rdev;
1219200855Sluigi	struct mbuf *md;
122098943Sluigi	enum vtype vtyp;
1221201527Sluigi	u_short vmode;
1222201527Sluigi	struct timespec mtime;
1223201527Sluigi	int v3 = NFS_ISV3(vp);
1224201527Sluigi
122598943Sluigi	md = *mdp;
1226200855Sluigi	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
122798943Sluigi	if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0)
122898943Sluigi		return (error);
122998943Sluigi	fp = (struct nfs_fattr *)cp2;
123098943Sluigi	if (v3) {
1231200059Sluigi		vtyp = nfsv3tov_type(fp->fa_type);
1232200059Sluigi		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1233200059Sluigi		rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
1234200059Sluigi			fxdr_unsigned(int, fp->fa3_rdev.specdata2));
1235200855Sluigi		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1236200059Sluigi	} else {
1237200059Sluigi		vtyp = nfsv2tov_type(fp->fa_type);
1238200059Sluigi		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1239200059Sluigi		/*
1240200059Sluigi		 * XXX
1241200059Sluigi		 *
1242200059Sluigi		 * The duplicate information returned in fa_type and fa_mode
1243200059Sluigi		 * is an ambiguity in the NFS version 2 protocol.
1244200855Sluigi		 *
1245200059Sluigi		 * VREG should be taken literally as a regular file.  If a
124698943Sluigi		 * server intents to return some type information differently
1247200855Sluigi		 * in the upper bits of the mode field (e.g. for sockets, or
124898943Sluigi		 * FIFOs), NFSv2 mandates fa_type to be VNON.  Anyway, we
1249153374Sglebius		 * leave the examination of the mode bits even in the VREG
1250153374Sglebius		 * case to avoid breakage for bogus servers, but we make sure
1251200855Sluigi		 * that there are actually type bits set in the upper part of
125298943Sluigi		 * fa_mode (and failing that, trust the va_type field).
1253200855Sluigi		 *
1254181803Sbz		 * NFSv3 cleared the issue, and requires fa_mode to not
1255101628Sluigi		 * contain any type information (while also introduing sockets
1256101628Sluigi		 * and FIFOs for fa_type).
125798943Sluigi		 */
125898943Sluigi		if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
125998943Sluigi			vtyp = IFTOVT(vmode);
126099622Sluigi		rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
126198943Sluigi		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
126298943Sluigi
126398943Sluigi		/*
126498943Sluigi		 * Really ugly NFSv2 kludge.
126598943Sluigi		 */
126698943Sluigi		if (vtyp == VCHR && rdev == 0xffffffff)
126798943Sluigi			vtyp = VFIFO;
1268200059Sluigi	}
126998943Sluigi
127098943Sluigi	/*
127198943Sluigi	 * If v_type == VNON it is a new node, so fill in the v_type,
127298943Sluigi	 * n_mtime fields. Check to see if it represents a special
127398943Sluigi	 * device, and if so, check for a possible alias. Once the
127498943Sluigi	 * correct vnode has been obtained, fill in the rest of the
127598943Sluigi	 * information.
127698943Sluigi	 */
127798943Sluigi	np = VTONFS(vp);
127898943Sluigi	if (vp->v_type != vtyp) {
127998943Sluigi		vp->v_type = vtyp;
128098943Sluigi		if (vp->v_type == VFIFO) {
128198943Sluigi			vp->v_op = fifo_nfsv2nodeop_p;
128299622Sluigi		}
128399622Sluigi		if (vp->v_type == VCHR || vp->v_type == VBLK) {
128498943Sluigi			vp->v_op = spec_nfsv2nodeop_p;
128599622Sluigi			addaliasu(vp, rdev);
128699622Sluigi		}
128799622Sluigi		np->n_mtime = mtime.tv_sec;
128899622Sluigi	}
128999622Sluigi	vap = &np->n_vattr;
129099622Sluigi	vap->va_type = vtyp;
129199622Sluigi	vap->va_mode = (vmode & 07777);
129298943Sluigi	vap->va_rdev = rdev;
129399622Sluigi	vap->va_mtime = mtime;
129499622Sluigi	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
129598943Sluigi	if (v3) {
129698943Sluigi		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
129798943Sluigi		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
129898943Sluigi		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
129999622Sluigi		vap->va_size = fxdr_hyper(&fp->fa3_size);
130098943Sluigi		vap->va_blocksize = NFS_FABLKSIZE;
130198943Sluigi		vap->va_bytes = fxdr_hyper(&fp->fa3_used);
130298943Sluigi		vap->va_fileid = fxdr_unsigned(int32_t,
1303133600Scsjp		    fp->fa3_fileid.nfsuquad[1]);
130498943Sluigi		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
130598943Sluigi		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1306145246Sbrooks		vap->va_flags = 0;
130798943Sluigi		vap->va_filerev = 0;
130898943Sluigi	} else {
1309223073Sae		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
131099622Sluigi		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1311122265Ssam		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1312122265Ssam		vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1313122265Ssam		vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
1314122265Ssam		vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks)
1315223073Sae		    * NFS_FABLKSIZE;
1316204591Sluigi		vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1317223073Sae		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1318204591Sluigi		vap->va_flags = 0;
1319223073Sae		vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
1320204591Sluigi		    fp->fa2_ctime.nfsv2_sec);
132199622Sluigi		vap->va_ctime.tv_nsec = 0;
132298943Sluigi		vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
132398943Sluigi		vap->va_filerev = 0;
132499622Sluigi	}
1325234597Smelifaro	if (vap->va_size != np->n_size) {
132699622Sluigi		if (vap->va_type == VREG) {
132798943Sluigi			if (np->n_flag & NMODIFIED) {
132898943Sluigi				if (vap->va_size < np->n_size)
1329234597Smelifaro					vap->va_size = np->n_size;
1330234597Smelifaro				else
133199622Sluigi					np->n_size = vap->va_size;
133298943Sluigi			} else {
133398943Sluigi				np->n_size = vap->va_size;
133499622Sluigi			}
1335234597Smelifaro			vnode_pager_setsize(vp, np->n_size);
1336234597Smelifaro		} else {
133799622Sluigi			np->n_size = vap->va_size;
133898943Sluigi		}
133998943Sluigi	}
134098943Sluigi	np->n_attrstamp = time_second;
134198943Sluigi	if (vaper != NULL) {
134298943Sluigi		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
134398943Sluigi		if (np->n_flag & NCHG) {
134498943Sluigi			if (np->n_flag & NACC)
134598943Sluigi				vaper->va_atime = np->n_atim;
134698943Sluigi			if (np->n_flag & NUPD)
134799622Sluigi				vaper->va_mtime = np->n_mtim;
134899622Sluigi		}
134999622Sluigi	}
135099622Sluigi	return (0);
135198943Sluigi}
135299622Sluigi
135398943Sluigi#ifdef NFS_ACDEBUG
135498943Sluigi#include <sys/sysctl.h>
135598943SluigiSYSCTL_DECL(_vfs_nfs);
135698943Sluigistatic int nfs_acdebug;
135798943SluigiSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, "");
135898943Sluigi#endif
135998943Sluigi
136099622Sluigi/*
136199622Sluigi * Check the time stamp
1362165738Sjulian * If the cache is valid, copy contents to *vap and return 0
1363165738Sjulian * otherwise return an error
136498943Sluigi */
136599622Sluigiint
136698943Sluiginfs_getattrcache(vp, vaper)
136798943Sluigi	register struct vnode *vp;
1368145246Sbrooks	struct vattr *vaper;
136999622Sluigi{
137098943Sluigi	register struct nfsnode *np;
137198943Sluigi	register struct vattr *vap;
137299622Sluigi	struct nfsmount *nmp;
137399622Sluigi	int timeo;
137498943Sluigi
137598943Sluigi	np = VTONFS(vp);
137699622Sluigi	vap = &np->n_vattr;
137799622Sluigi	nmp = VFSTONFS(vp->v_mount);
137898943Sluigi	/* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
1379136073Sgreen	timeo = (time_second - np->n_mtime) / 10;
1380201527Sluigi
1381201527Sluigi#ifdef NFS_ACDEBUG
1382201527Sluigi	if (nfs_acdebug>1)
1383201527Sluigi		printf("nfs_getattrcache: initial timeo = %d\n", timeo);
1384210120Sluigi#endif
1385201527Sluigi
1386201527Sluigi	if (vap->va_type == VDIR) {
1387201527Sluigi		if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
1388201527Sluigi			timeo = nmp->nm_acdirmin;
1389136073Sgreen		else if (timeo > nmp->nm_acdirmax)
1390136073Sgreen			timeo = nmp->nm_acdirmax;
139198943Sluigi	} else {
139298943Sluigi		if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
139398943Sluigi			timeo = nmp->nm_acregmin;
139498943Sluigi		else if (timeo > nmp->nm_acregmax)
139598943Sluigi			timeo = nmp->nm_acregmax;
139699622Sluigi	}
139799622Sluigi
139898943Sluigi#ifdef NFS_ACDEBUG
139998943Sluigi	if (nfs_acdebug > 2)
1400147758Smlaier		printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
1401147758Smlaier			nmp->nm_acregmin, nmp->nm_acregmax,
140299622Sluigi			nmp->nm_acdirmin, nmp->nm_acdirmax);
140399622Sluigi
1404105775Smaxim	if (nfs_acdebug)
1405130281Sru		printf("nfs_getattrcache: age = %d; final timeo = %d\n",
1406130281Sru			(time_second - np->n_attrstamp), timeo);
1407147758Smlaier#endif
1408201122Sluigi
1409130281Sru	if ((time_second - np->n_attrstamp) >= timeo) {
1410130281Sru		nfsstats.attrcache_misses++;
1411187822Sluigi		return (ENOENT);
1412130281Sru	}
1413200567Sluigi	nfsstats.attrcache_hits++;
1414201122Sluigi	if (vap->va_size != np->n_size) {
1415201122Sluigi		if (vap->va_type == VREG) {
1416201122Sluigi			if (np->n_flag & NMODIFIED) {
1417200567Sluigi				if (vap->va_size < np->n_size)
1418200567Sluigi					vap->va_size = np->n_size;
1419201122Sluigi				else
1420200567Sluigi					np->n_size = vap->va_size;
1421201122Sluigi			} else {
1422205173Sluigi				np->n_size = vap->va_size;
1423205173Sluigi			}
1424200567Sluigi			vnode_pager_setsize(vp, np->n_size);
1425200567Sluigi		} else {
1426200567Sluigi			np->n_size = vap->va_size;
1427200567Sluigi		}
1428200567Sluigi	}
1429200567Sluigi	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1430201122Sluigi	if (np->n_flag & NCHG) {
1431200567Sluigi		if (np->n_flag & NACC)
1432201150Sluigi			vaper->va_atime = np->n_atim;
1433200567Sluigi		if (np->n_flag & NUPD)
1434200567Sluigi			vaper->va_mtime = np->n_mtim;
1435200567Sluigi	}
1436223073Sae	return (0);
1437204591Sluigi}
1438223073Sae
1439200567Sluigi#ifndef NFS_NOSERVER
1440201122Sluigi/*
1441200567Sluigi * Set up nameidata for a lookup() call and do it.
1442201122Sluigi *
1443204591Sluigi * If pubflag is set, this call is done for a lookup operation on the
1444223073Sae * public filehandle. In that case we allow crossing mountpoints and
1445204591Sluigi * absolute pathnames. However, the caller is expected to check that
1446204591Sluigi * the lookup result is within the public fs, and deny access if
1447204591Sluigi * it is not.
1448204591Sluigi *
1449204591Sluigi * nfs_namei() clears out garbage fields that namei() might leave garbage.
1450201122Sluigi * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
1451200567Sluigi * error occurs but the parent was not requested.
1452200567Sluigi *
1453200567Sluigi * dirp may be set whether an error is returned or not, and must be
1454201122Sluigi * released by the caller.
1455201122Sluigi */
1456130281Sruint
1457130281Srunfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
1458130281Sru	register struct nameidata *ndp;
1459130281Sru	fhandle_t *fhp;
1460130281Sru	int len;
1461153374Sglebius	struct nfssvc_sock *slp;
1462153374Sglebius	struct sockaddr *nam;
1463234597Smelifaro	struct mbuf **mdp;
1464234597Smelifaro	caddr_t *dposp;
1465234597Smelifaro	struct vnode **retdirp;
1466234597Smelifaro	struct proc *p;
1467234597Smelifaro	int kerbflag, pubflag;
1468234597Smelifaro{
1469234597Smelifaro	register int i, rem;
1470234597Smelifaro	register struct mbuf *md;
1471234597Smelifaro	register char *fromcp, *tocp, *cp;
1472234597Smelifaro	struct iovec aiov;
1473234597Smelifaro	struct uio auio;
1474130281Sru	struct vnode *dp;
1475130281Sru	int error, rdonly, linklen;
1476130281Sru	struct componentname *cnp = &ndp->ni_cnd;
147798943Sluigi
1478117327Sluigi	*retdirp = (struct vnode *)0;
1479147758Smlaier	cnp->cn_pnbuf = zalloc(namei_zone);
1480117327Sluigi
1481117327Sluigi	/*
1482117327Sluigi	 * Copy the name from the mbuf list to ndp->ni_pnbuf
1483117327Sluigi	 * and set the various ndp fields appropriately.
1484117327Sluigi	 */
1485117327Sluigi	fromcp = *dposp;
1486117327Sluigi	tocp = cnp->cn_pnbuf;
1487117327Sluigi	md = *mdp;
1488117327Sluigi	rem = mtod(md, caddr_t) + md->m_len - fromcp;
148999622Sluigi	for (i = 0; i < len; i++) {
149098943Sluigi		while (rem == 0) {
149198943Sluigi			md = md->m_next;
1492147758Smlaier			if (md == NULL) {
149399622Sluigi				error = EBADRPC;
149498943Sluigi				goto out;
149599622Sluigi			}
149699622Sluigi			fromcp = mtod(md, caddr_t);
1497202459Sume			rem = md->m_len;
149899622Sluigi		}
1499204591Sluigi		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1500202459Sume			error = EACCES;
1501202459Sume			goto out;
1502204591Sluigi		}
1503202459Sume		*tocp++ = *fromcp++;
150499622Sluigi		rem--;
1505105775Smaxim	}
150698943Sluigi	*tocp = '\0';
150798943Sluigi	*mdp = md;
1508147758Smlaier	*dposp = fromcp;
150999622Sluigi	len = nfsm_rndup(len)-len;
151099622Sluigi	if (len > 0) {
151199622Sluigi		if (rem >= len)
1512105886Sluigi			*dposp += len;
1513105886Sluigi		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
151498943Sluigi			goto out;
151599622Sluigi	}
151699622Sluigi
151799622Sluigi	/*
151899622Sluigi	 * Extract and set starting directory.
151999622Sluigi	 */
152099622Sluigi	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
152199622Sluigi	    nam, &rdonly, kerbflag, pubflag);
152299622Sluigi	if (error)
152398943Sluigi		goto out;
152498943Sluigi	if (dp->v_type != VDIR) {
1525147758Smlaier		vrele(dp);
1526147758Smlaier		error = ENOTDIR;
152799622Sluigi		goto out;
152899622Sluigi	}
152998943Sluigi
153098943Sluigi	if (rdonly)
1531147758Smlaier		cnp->cn_flags |= RDONLY;
153299622Sluigi
153399622Sluigi	/*
153499622Sluigi	 * Set return directory.  Reference to dp is implicitly transfered
153599622Sluigi	 * to the returned pointer
1536202459Sume	 */
153799622Sluigi	*retdirp = dp;
1538204591Sluigi
1539202459Sume	if (pubflag) {
1540202459Sume		/*
1541204591Sluigi		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
1542202459Sume		 * and the 'native path' indicator.
154399622Sluigi		 */
1544105775Smaxim		cp = zalloc(namei_zone);
1545204591Sluigi		fromcp = cnp->cn_pnbuf;
154698943Sluigi		tocp = cp;
154798943Sluigi		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
154898943Sluigi			switch ((unsigned char)*fromcp) {
154998943Sluigi			case WEBNFS_NATIVE_CHAR:
1550145246Sbrooks				/*
155198943Sluigi				 * 'Native' path for us is the same
155298943Sluigi				 * as a path according to the NFS spec,
155399622Sluigi				 * just skip the escape char.
155499622Sluigi				 */
155599622Sluigi				fromcp++;
155698943Sluigi				break;
155799622Sluigi			/*
155898943Sluigi			 * More may be added in the future, range 0x80-0xff
155998943Sluigi			 */
156098943Sluigi			default:
156198943Sluigi				error = EIO;
156299622Sluigi				zfree(namei_zone, cp);
156399622Sluigi				goto out;
156499622Sluigi			}
156598943Sluigi		}
156699622Sluigi		/*
156798943Sluigi		 * Translate the '%' escapes, URL-style.
156898943Sluigi		 */
156999622Sluigi		while (*fromcp != '\0') {
1570145093Sbrooks			if (*fromcp == WEBNFS_ESC_CHAR) {
157199622Sluigi				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
157298943Sluigi					fromcp++;
1573145266Sphk					*tocp++ = HEXSTRTOI(fromcp);
1574145246Sbrooks					fromcp += 2;
1575145246Sbrooks					continue;
1576145246Sbrooks				} else {
1577145246Sbrooks					error = ENOENT;
1578145246Sbrooks					zfree(namei_zone, cp);
1579145246Sbrooks					goto out;
1580145246Sbrooks				}
1581145266Sphk			} else
1582145246Sbrooks				*tocp++ = *fromcp++;
158398943Sluigi		}
1584147758Smlaier		*tocp = '\0';
1585165738Sjulian		zfree(namei_zone, cnp->cn_pnbuf);
158699622Sluigi		cnp->cn_pnbuf = cp;
158798943Sluigi	}
158898943Sluigi
1589147758Smlaier	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
1590165738Sjulian	ndp->ni_segflg = UIO_SYSSPACE;
159199622Sluigi
159298943Sluigi	if (pubflag) {
1593116690Sluigi		ndp->ni_rootdir = rootvnode;
1594116690Sluigi		ndp->ni_loopcnt = 0;
159598943Sluigi		if (cnp->cn_pnbuf[0] == '/')
1596147758Smlaier			dp = rootvnode;
1597116690Sluigi	} else {
1598116690Sluigi		cnp->cn_flags |= NOCROSSMOUNT;
1599116690Sluigi	}
160098943Sluigi
1601116690Sluigi	/*
1602201122Sluigi	 * Initialize for scan, set ni_startdir and bump ref on dp again
1603116690Sluigi	 * becuase lookup() will dereference ni_startdir.
1604165738Sjulian	 */
1605116690Sluigi
1606165738Sjulian	cnp->cn_proc = p;
1607116690Sluigi	VREF(dp);
1608116690Sluigi	ndp->ni_startdir = dp;
1609116690Sluigi
1610116690Sluigi	for (;;) {
1611116690Sluigi		cnp->cn_nameptr = cnp->cn_pnbuf;
1612116690Sluigi		/*
1613116690Sluigi		 * Call lookup() to do the real work.  If an error occurs,
1614116690Sluigi		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
1615116690Sluigi		 * we do not have to dereference anything before returning.
1616116690Sluigi		 * In either case ni_startdir will be dereferenced and NULLed
161799622Sluigi		 * out.
161898943Sluigi		 */
161999475Sluigi		error = lookup(ndp);
1620147758Smlaier		if (error)
1621165738Sjulian			break;
162299622Sluigi
162399475Sluigi		/*
162498943Sluigi		 * Check for encountering a symbolic link.  Trivial
1625147758Smlaier		 * termination occurs if no symlink encountered.
1626165738Sjulian		 * Note: zfree is safe because error is 0, so we will
162799622Sluigi		 * not zfree it again when we break.
162898943Sluigi		 */
1629136075Sgreen		if ((cnp->cn_flags & ISSYMLINK) == 0) {
1630136075Sgreen			nfsrv_object_create(ndp->ni_vp);
1631136075Sgreen			if (cnp->cn_flags & (SAVENAME | SAVESTART))
1632136075Sgreen				cnp->cn_flags |= HASBUF;
1633136075Sgreen			else
1634136075Sgreen				zfree(namei_zone, cnp->cn_pnbuf);
1635136075Sgreen			break;
1636145093Sbrooks		}
1637201122Sluigi
1638136075Sgreen		/*
1639136075Sgreen		 * Validate symlink
1640136075Sgreen		 */
1641136075Sgreen		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1642136075Sgreen			VOP_UNLOCK(ndp->ni_dvp, 0, p);
1643136075Sgreen		if (!pubflag) {
1644136075Sgreen			error = EINVAL;
1645136075Sgreen			goto badlink2;
1646136075Sgreen		}
1647136075Sgreen
1648136075Sgreen		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
1649136075Sgreen			error = ELOOP;
1650136075Sgreen			goto badlink2;
165198943Sluigi		}
165299622Sluigi		if (ndp->ni_pathlen > 1)
1653145093Sbrooks			cp = zalloc(namei_zone);
165499622Sluigi		else
165598943Sluigi			cp = cnp->cn_pnbuf;
165698943Sluigi		aiov.iov_base = cp;
1657220796Sglebius		aiov.iov_len = MAXPATHLEN;
165899622Sluigi		auio.uio_iov = &aiov;
1659145093Sbrooks		auio.uio_iovcnt = 1;
166099622Sluigi		auio.uio_offset = 0;
166198943Sluigi		auio.uio_rw = UIO_READ;
166298943Sluigi		auio.uio_segflg = UIO_SYSSPACE;
166399622Sluigi		auio.uio_procp = (struct proc *)0;
166499622Sluigi		auio.uio_resid = MAXPATHLEN;
1665145093Sbrooks		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
166699622Sluigi		if (error) {
166798943Sluigi		badlink1:
166898943Sluigi			if (ndp->ni_pathlen > 1)
166999622Sluigi				zfree(namei_zone, cp);
167099622Sluigi		badlink2:
1671145093Sbrooks			vrele(ndp->ni_dvp);
167299622Sluigi			vput(ndp->ni_vp);
167398943Sluigi			break;
167498943Sluigi		}
1675234278Sglebius		linklen = MAXPATHLEN - auio.uio_resid;
1676234278Sglebius		if (linklen == 0) {
1677234278Sglebius			error = ENOENT;
1678234278Sglebius			goto badlink1;
1679234278Sglebius		}
1680234278Sglebius		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
1681234278Sglebius			error = ENAMETOOLONG;
1682234278Sglebius			goto badlink1;
1683234278Sglebius		}
1684234278Sglebius
1685234278Sglebius		/*
1686234278Sglebius		 * Adjust or replace path
1687234278Sglebius		 */
1688234278Sglebius		if (ndp->ni_pathlen > 1) {
1689234278Sglebius			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
1690234278Sglebius			zfree(namei_zone, cnp->cn_pnbuf);
169199622Sluigi			cnp->cn_pnbuf = cp;
169298943Sluigi		} else
169398943Sluigi			cnp->cn_pnbuf[linklen] = '\0';
169498943Sluigi		ndp->ni_pathlen += linklen;
169599622Sluigi
169699622Sluigi		/*
1697145093Sbrooks		 * Cleanup refs for next loop and check if root directory
169899622Sluigi		 * should replace current directory.  Normally ni_dvp
169999622Sluigi		 * becomes the new base directory and is cleaned up when
170098943Sluigi		 * we loop.  Explicitly null pointers after invalidation
1701136071Sgreen		 * to clarify operation.
1702171173Smlaier		 */
1703136071Sgreen		vput(ndp->ni_vp);
1704136071Sgreen		ndp->ni_vp = NULL;
1705136071Sgreen
1706171173Smlaier		if (cnp->cn_pnbuf[0] == '/') {
1707171173Smlaier			vrele(ndp->ni_dvp);
1708146962Sgreen			ndp->ni_dvp = ndp->ni_rootdir;
1709171173Smlaier			VREF(ndp->ni_dvp);
1710171173Smlaier		}
1711136071Sgreen		ndp->ni_startdir = ndp->ni_dvp;
1712136071Sgreen		ndp->ni_dvp = NULL;
1713136071Sgreen	}
1714136071Sgreen
1715136071Sgreen	/*
1716136071Sgreen	 * nfs_namei() guarentees that fields will not contain garbage
1717136071Sgreen	 * whether an error occurs or not.  This allows the caller to track
1718136071Sgreen	 * cleanup state trivially.
1719136071Sgreen	 */
1720136071Sgreenout:
1721136071Sgreen	if (error) {
172298943Sluigi		zfree(namei_zone, cnp->cn_pnbuf);
1723200654Sluigi		ndp->ni_vp = NULL;
1724225032Sbz		ndp->ni_dvp = NULL;
172599622Sluigi		ndp->ni_startdir = NULL;
172699622Sluigi		cnp->cn_flags &= ~HASBUF;
172798943Sluigi	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
172899475Sluigi		ndp->ni_dvp = NULL;
172999622Sluigi	}
173099622Sluigi	return (error);
173198943Sluigi}
1732112250Scjc
1733112250Scjc/*
1734145246Sbrooks * A fiddled version of m_adj() that ensures null fill to a long
1735116763Sluigi * boundary and only trims off the back end
1736145266Sphk */
1737145266Sphkvoid
1738145266Sphknfsm_adj(mp, len, nul)
1739147418Smlaier	struct mbuf *mp;
1740232292Sbz	register int len;
1741145266Sphk	int nul;
1742178888Sjulian{
1743178888Sjulian	register struct mbuf *m;
1744112250Scjc	register int count, i;
1745112250Scjc	register char *cp;
1746128575Sandre
1747128575Sandre	/*
1748133485Sandre	 * Trim from tail.  Scan the mbuf chain,
1749147418Smlaier	 * calculating its length and finding the last mbuf.
1750147418Smlaier	 * If the adjustment only affects this mbuf, then just
1751147418Smlaier	 * adjust and return.  Otherwise, rescan and truncate
1752232292Sbz	 * after the remaining size.
1753147418Smlaier	 */
1754178888Sjulian	count = 0;
1755128575Sandre	m = mp;
1756128575Sandre	for (;;) {
1757133387Sandre		count += m->m_len;
1758133387Sandre		if (m->m_next == (struct mbuf *)0)
1759133387Sandre			break;
1760147418Smlaier		m = m->m_next;
1761147418Smlaier	}
1762147418Smlaier	if (m->m_len > len) {
1763147418Smlaier		m->m_len -= len;
1764147418Smlaier		if (nul > 0) {
1765147418Smlaier			cp = mtod(m, caddr_t)+m->m_len-nul;
1766147418Smlaier			for (i = 0; i < nul; i++)
1767147418Smlaier				*cp++ = '\0';
1768147418Smlaier		}
1769147418Smlaier		return;
1770232292Sbz	}
1771232292Sbz	count -= len;
1772147418Smlaier	if (count < 0)
1773147418Smlaier		count = 0;
1774178888Sjulian	/*
1775178888Sjulian	 * Correct length for chain is "count".
1776133387Sandre	 * Find the mbuf with last data, adjust its length,
1777133387Sandre	 * and toss data from remaining mbufs on chain.
1778133387Sandre	 */
1779133387Sandre	for (m = mp; m; m = m->m_next) {
1780117241Sluigi		if (m->m_len >= count) {
1781171167Sgnn			m->m_len = count;
1782117241Sluigi			if (nul > 0) {
1783117241Sluigi				cp = mtod(m, caddr_t)+m->m_len-nul;
1784117241Sluigi				for (i = 0; i < nul; i++)
1785117241Sluigi					*cp++ = '\0';
1786117241Sluigi			}
1787117241Sluigi			break;
1788150122Sbz		}
1789145246Sbrooks		count -= m->m_len;
1790145246Sbrooks	}
1791145246Sbrooks	for (m = m->m_next;m;m = m->m_next)
1792145246Sbrooks		m->m_len = 0;
1793145246Sbrooks}
1794145246Sbrooks
1795145246Sbrooks/*
1796145246Sbrooks * Make these functions instead of macros, so that the kernel text size
1797145246Sbrooks * doesn't get too big...
1798145246Sbrooks */
1799145246Sbrooksvoid
1800145246Sbrooksnfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1801145246Sbrooks	struct nfsrv_descript *nfsd;
1802145246Sbrooks	int before_ret;
1803162351Sjhay	register struct vattr *before_vap;
1804162351Sjhay	int after_ret;
1805162351Sjhay	struct vattr *after_vap;
1806162351Sjhay	struct mbuf **mbp;
1807145246Sbrooks	char **bposp;
1808162351Sjhay{
1809162351Sjhay	register struct mbuf *mb = *mbp, *mb2;
1810162351Sjhay	register char *bpos = *bposp;
1811162351Sjhay	register u_int32_t *tl;
1812162351Sjhay
1813162351Sjhay	if (before_ret) {
1814162351Sjhay		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1815162351Sjhay		*tl = nfs_false;
1816162351Sjhay	} else {
1817162351Sjhay		nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1818162351Sjhay		*tl++ = nfs_true;
1819162351Sjhay		txdr_hyper(before_vap->va_size, tl);
1820145246Sbrooks		tl += 2;
1821145246Sbrooks		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1822145246Sbrooks		tl += 2;
1823145246Sbrooks		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1824145246Sbrooks	}
1825145246Sbrooks	*bposp = bpos;
1826145246Sbrooks	*mbp = mb;
1827145246Sbrooks	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1828145246Sbrooks}
1829145246Sbrooks
1830145246Sbrooksvoid
1831145246Sbrooksnfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1832145246Sbrooks	struct nfsrv_descript *nfsd;
1833145246Sbrooks	int after_ret;
1834145246Sbrooks	struct vattr *after_vap;
1835145246Sbrooks	struct mbuf **mbp;
1836145246Sbrooks	char **bposp;
1837145266Sphk{
1838145246Sbrooks	register struct mbuf *mb = *mbp, *mb2;
1839146894Smlaier	register char *bpos = *bposp;
1840146894Smlaier	register u_int32_t *tl;
1841146894Smlaier	register struct nfs_fattr *fp;
1842146894Smlaier
1843159636Soleg	if (after_ret) {
1844201527Sluigi		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1845159636Soleg		*tl = nfs_false;
1846159636Soleg	} else {
1847159636Soleg		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1848158879Soleg		*tl++ = nfs_true;
1849159636Soleg		fp = (struct nfs_fattr *)tl;
1850159636Soleg		nfsm_srvfattr(nfsd, after_vap, fp);
1851158879Soleg	}
1852158879Soleg	*mbp = mb;
1853158879Soleg	*bposp = bpos;
1854158879Soleg}
1855158879Soleg
1856158879Solegvoid
1857158879Solegnfsm_srvfattr(nfsd, vap, fp)
1858158879Soleg	register struct nfsrv_descript *nfsd;
1859158879Soleg	register struct vattr *vap;
1860158879Soleg	register struct nfs_fattr *fp;
1861201527Sluigi{
1862220568Sae
1863220568Sae	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1864220568Sae	fp->fa_uid = txdr_unsigned(vap->va_uid);
1865220568Sae	fp->fa_gid = txdr_unsigned(vap->va_gid);
1866220568Sae	if (nfsd->nd_flag & ND_NFSV3) {
1867220568Sae		fp->fa_type = vtonfsv3_type(vap->va_type);
1868220568Sae		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1869201527Sluigi		txdr_hyper(vap->va_size, &fp->fa3_size);
1870158879Soleg		txdr_hyper(vap->va_bytes, &fp->fa3_used);
1871158879Soleg		fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1872159636Soleg		fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1873158879Soleg		fp->fa3_fsid.nfsuquad[0] = 0;
1874178888Sjulian		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1875178888Sjulian		fp->fa3_fileid.nfsuquad[0] = 0;
1876178888Sjulian		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1877178888Sjulian		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1878178888Sjulian		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1879215179Sluigi		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1880215179Sluigi	} else {
1881215179Sluigi		fp->fa_type = vtonfsv2_type(vap->va_type);
1882215179Sluigi		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1883215179Sluigi		fp->fa2_size = txdr_unsigned(vap->va_size);
1884215179Sluigi		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1885215179Sluigi		if (vap->va_type == VFIFO)
1886215179Sluigi			fp->fa2_rdev = 0xffffffff;
1887215179Sluigi		else
1888215179Sluigi			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1889215179Sluigi		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1890215179Sluigi		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1891215179Sluigi		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1892215179Sluigi		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1893222488Srwatson		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1894222488Srwatson		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1895222488Srwatson	}
1896222488Srwatson}
1897222488Srwatson
1898215179Sluigi/*
1899215179Sluigi * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1900215179Sluigi * 	- look up fsid in mount list (if not found ret error)
1901222488Srwatson *	- get vp and export rights by calling VFS_FHTOVP()
1902215179Sluigi *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1903215179Sluigi *	- if not lockflag unlock it with VOP_UNLOCK()
1904222488Srwatson */
1905222488Srwatsonint
1906222488Srwatsonnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
1907222488Srwatson	fhandle_t *fhp;
1908222488Srwatson	int lockflag;
1909222488Srwatson	struct vnode **vpp;
1910222488Srwatson	struct ucred *cred;
1911222488Srwatson	struct nfssvc_sock *slp;
1912222488Srwatson	struct sockaddr *nam;
1913222488Srwatson	int *rdonlyp;
1914222488Srwatson	int kerbflag;
1915222488Srwatson	int pubflag;
1916222488Srwatson{
1917222488Srwatson	struct proc *p = curproc; /* XXX */
1918222488Srwatson	register struct mount *mp;
1919215179Sluigi	register int i;
1920215179Sluigi	struct ucred *credanon;
1921215179Sluigi	int error, exflags;
1922215179Sluigi#ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
1923159636Soleg	struct sockaddr_int *saddr;
1924201527Sluigi#endif
1925159636Soleg
1926159636Soleg	*vpp = (struct vnode *)0;
1927159636Soleg
1928158879Soleg	if (nfs_ispublicfh(fhp)) {
1929159636Soleg		if (!pubflag || !nfs_pub.np_valid)
1930159636Soleg			return (ESTALE);
1931158879Soleg		fhp = &nfs_pub.np_handle;
1932158879Soleg	}
1933158879Soleg
1934158879Soleg	mp = vfs_getvfs(&fhp->fh_fsid);
1935158879Soleg	if (!mp)
1936158879Soleg		return (ESTALE);
1937158879Soleg	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1938158879Soleg	if (error)
1939158879Soleg		return (error);
1940158879Soleg	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1941158879Soleg	if (error)
1942158879Soleg		return (error);
1943158879Soleg#ifdef MNT_EXNORESPORT
1944158879Soleg	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1945158879Soleg		saddr = (struct sockaddr_in *)nam;
1946158879Soleg		if (saddr->sin_family == AF_INET &&
1947158879Soleg		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1948158879Soleg			vput(*vpp);
1949158879Soleg			*vpp = NULL;
1950158879Soleg			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1951158879Soleg		}
1952159636Soleg	}
1953158879Soleg#endif
195499622Sluigi	/*
195599622Sluigi	 * Check/setup credentials.
195699622Sluigi	 */
195799622Sluigi	if (exflags & MNT_EXKERB) {
195899622Sluigi		if (!kerbflag) {
195999622Sluigi			vput(*vpp);
196099622Sluigi			*vpp = NULL;
196199622Sluigi			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
196299622Sluigi		}
196399622Sluigi	} else if (kerbflag) {
1964200059Sluigi		vput(*vpp);
196599622Sluigi		*vpp = NULL;
196699622Sluigi		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
196799622Sluigi	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
196899622Sluigi		cred->cr_uid = credanon->cr_uid;
1969200855Sluigi		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1970200855Sluigi			cred->cr_groups[i] = credanon->cr_groups[i];
197199622Sluigi		cred->cr_ngroups = i;
1972158879Soleg	}
1973136071Sgreen	if (exflags & MNT_EXRDONLY)
1974136071Sgreen		*rdonlyp = 1;
197599622Sluigi	else
197699622Sluigi		*rdonlyp = 0;
197799622Sluigi
197899622Sluigi	nfsrv_object_create(*vpp);
197999622Sluigi
198099622Sluigi	if (!lockflag)
1981200059Sluigi		VOP_UNLOCK(*vpp, 0, p);
1982200059Sluigi	return (0);
198399622Sluigi}
198499622Sluigi
198599622Sluigi
198699622Sluigi/*
1987200059Sluigi * WebNFS: check if a filehandle is a public filehandle. For v3, this
198899622Sluigi * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1989200059Sluigi * transformed this to all zeroes in both cases, so check for it.
1990200059Sluigi */
1991200059Sluigiint
1992200059Sluiginfs_ispublicfh(fhp)
1993200059Sluigi	fhandle_t *fhp;
199499622Sluigi{
199598943Sluigi	char *cp = (char *)fhp;
199698943Sluigi	int i;
1997200601Sluigi
1998159636Soleg	for (i = 0; i < NFSX_V3FH; i++)
1999200059Sluigi		if (*cp++ != 0)
2000140224Sglebius			return (FALSE);
2001200059Sluigi	return (TRUE);
2002200059Sluigi}
200399622Sluigi
200499622Sluigi#endif /* NFS_NOSERVER */
200599622Sluigi/*
200698943Sluigi * This function compares two net addresses by family and returns TRUE
200798943Sluigi * if they are the same host.
200898943Sluigi * If there is any doubt, return FALSE.
200998943Sluigi * The AF_INET family is handled as a special case so that address mbufs
201098943Sluigi * don't need to be saved to store "struct in_addr", which is only 4 bytes.
201199622Sluigi */
201299622Sluigiint
201399622Sluiginetaddr_match(family, haddr, nam)
201498943Sluigi	int family;
201599622Sluigi	union nethostaddr *haddr;
201698943Sluigi	struct sockaddr *nam;
201798943Sluigi{
201899622Sluigi	register struct sockaddr_in *inetaddr;
2019200601Sluigi
2020100004Sluigi	switch (family) {
2021145093Sbrooks	case AF_INET:
2022100004Sluigi		inetaddr = (struct sockaddr_in *)nam;
202399622Sluigi		if (inetaddr->sin_family == AF_INET &&
202499622Sluigi		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
202599622Sluigi			return (1);
2026200059Sluigi		break;
2027200059Sluigi	default:
202899622Sluigi		break;
202999622Sluigi	};
2030115750Skbyanc	return (0);
2031200855Sluigi}
2032200855Sluigi
2033200855Sluigistatic nfsuint64 nfs_nullcookie = { { 0, 0 } };
2034200855Sluigi/*
2035200855Sluigi * This function finds the directory cookie that corresponds to the
203699622Sluigi * logical byte offset given.
2037200855Sluigi */
2038200855Sluiginfsuint64 *
203999622Sluiginfs_getcookie(np, off, add)
204099622Sluigi	register struct nfsnode *np;
2041200580Sluigi	off_t off;
2042200059Sluigi	int add;
2043200059Sluigi{
2044200059Sluigi	register struct nfsdmap *dp, *dp2;
204598943Sluigi	register int pos;
204699622Sluigi
204799622Sluigi	pos = (uoff_t)off / NFS_DIRBLKSIZ;
204899622Sluigi	if (pos == 0 || off < 0) {
204999622Sluigi#ifdef DIAGNOSTIC
205099622Sluigi		if (add)
205198943Sluigi			panic("nfs getcookie add at <= 0");
2052200059Sluigi#endif
205399622Sluigi		return (&nfs_nullcookie);
205499622Sluigi	}
205598943Sluigi	pos--;
205698943Sluigi	dp = np->n_cookies.lh_first;
205798943Sluigi	if (!dp) {
2058200059Sluigi		if (add) {
2059200059Sluigi			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
2060200059Sluigi				M_NFSDIROFF, M_WAITOK);
206198943Sluigi			dp->ndm_eocookie = 0;
206298943Sluigi			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
206398943Sluigi		} else
2064200855Sluigi			return ((nfsuint64 *)0);
2065201527Sluigi	}
2066200838Sluigi	while (pos >= NFSNUMCOOKIES) {
2067201527Sluigi		pos -= NFSNUMCOOKIES;
2068201527Sluigi		if (dp->ndm_list.le_next) {
2069201527Sluigi			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
2070201527Sluigi				pos >= dp->ndm_eocookie)
2071140224Sglebius				return ((nfsuint64 *)0);
2072200059Sluigi			dp = dp->ndm_list.le_next;
2073200059Sluigi		} else if (add) {
2074200059Sluigi			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
2075105775Smaxim				M_NFSDIROFF, M_WAITOK);
207698943Sluigi			dp2->ndm_eocookie = 0;
2077200059Sluigi			LIST_INSERT_AFTER(dp, dp2, ndm_list);
207898943Sluigi			dp = dp2;
2079200059Sluigi		} else
2080200059Sluigi			return ((nfsuint64 *)0);
2081200059Sluigi	}
2082200059Sluigi	if (pos >= dp->ndm_eocookie) {
2083201527Sluigi		if (add)
2084200059Sluigi			dp->ndm_eocookie = pos + 1;
2085201527Sluigi		else
2086201527Sluigi			return ((nfsuint64 *)0);
2087201527Sluigi	}
2088200059Sluigi	return (&dp->ndm_cookies[pos]);
2089200059Sluigi}
209098943Sluigi
209198943Sluigi/*
2092115750Skbyanc * Invalidate cached directory information, except for the actual directory
2093150350Sandre * blocks (which are invalidated separately).
2094200896Sluigi * Done mainly to avoid the use of stale offset cookies.
2095200896Sluigi */
2096200855Sluigivoid
2097200855Sluiginfs_invaldir(vp)
2098200855Sluigi	register struct vnode *vp;
2099200855Sluigi{
2100200855Sluigi	register struct nfsnode *np = VTONFS(vp);
2101200855Sluigi
2102200855Sluigi#ifdef DIAGNOSTIC
2103200855Sluigi	if (vp->v_type != VDIR)
2104200855Sluigi		panic("nfs: invaldir not dir");
2105200855Sluigi#endif
2106200896Sluigi	np->n_direofoffset = 0;
2107200896Sluigi	np->n_cookieverf.nfsuquad[0] = 0;
2108200855Sluigi	np->n_cookieverf.nfsuquad[1] = 0;
2109200855Sluigi	if (np->n_cookies.lh_first)
2110200855Sluigi		np->n_cookies.lh_first->ndm_eocookie = 0;
2111200855Sluigi}
2112200855Sluigi
2113200855Sluigi/*
2114200855Sluigi * The write verifier has changed (probably due to a server reboot), so all
2115200855Sluigi * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
2116200855Sluigi * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
2117200896Sluigi * and B_CLUSTEROK flags.  Once done the new write verifier can be set for the
2118200855Sluigi * mount point.
2119200855Sluigi *
2120200855Sluigi * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data
2121181139Sjulian * writes are not clusterable.
2122200896Sluigi */
2123200896Sluigivoid
2124200855Sluiginfs_clearcommit(mp)
2125200855Sluigi	struct mount *mp;
2126200855Sluigi{
2127200896Sluigi	register struct vnode *vp, *nvp;
2128200896Sluigi	register struct buf *bp, *nbp;
2129200855Sluigi	int s;
2130200855Sluigi
2131200855Sluigi	s = splbio();
2132200855Sluigiloop:
2133200855Sluigi	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
2134209589Sglebius		if (vp->v_mount != mp)	/* Paranoia */
2135200855Sluigi			goto loop;
2136200896Sluigi		nvp = vp->v_mntvnodes.le_next;
2137200896Sluigi		for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
2138200896Sluigi			nbp = TAILQ_NEXT(bp, b_vnbufs);
2139200896Sluigi			if (BUF_REFCNT(bp) == 0 &&
2140200896Sluigi			    (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
2141209589Sglebius				== (B_DELWRI | B_NEEDCOMMIT))
2142209589Sglebius				bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
214398943Sluigi		}
2144223666Sae	}
2145223666Sae	splx(s);
2146223666Sae}
2147223666Sae
2148223666Sae#ifndef NFS_NOSERVER
2149223666Sae/*
2150223666Sae * Map errnos to NFS error numbers. For Version 3 also filter out error
2151223666Sae * numbers not specified for the associated procedure.
2152223666Sae */
2153223666Saeint
2154223666Saenfsrv_errmap(nd, err)
2155223666Sae	struct nfsrv_descript *nd;
2156223666Sae	register int err;
2157223666Sae{
2158223666Sae	register short *defaulterrp, *errp;
2159223666Sae
2160223666Sae	if (nd->nd_flag & ND_NFSV3) {
2161223666Sae	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
2162223666Sae		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
2163223666Sae		while (*++errp) {
2164223666Sae			if (*errp == err)
2165223666Sae				return (err);
2166223666Sae			else if (*errp > err)
2167223666Sae				break;
2168223666Sae		}
2169223666Sae		return ((int)*defaulterrp);
2170223666Sae	    } else
2171223666Sae		return (err & 0xffff);
2172223666Sae	}
2173223666Sae	if (err <= ELAST)
2174223666Sae		return ((int)nfsrv_v2errmap[err - 1]);
2175223666Sae	return (NFSERR_IO);
2176223666Sae}
2177223666Sae
2178223666Saeint
2179223666Saenfsrv_object_create(vp)
2180223666Sae	struct vnode *vp;
2181223666Sae{
2182223666Sae
2183223666Sae	if (vp == NULL || vp->v_type != VREG)
2184223666Sae		return (1);
2185223666Sae	return (vfs_object_create(vp, curproc,
2186223666Sae				  curproc ? curproc->p_ucred : NULL));
2187223666Sae}
2188223666Sae
2189223666Sae/*
2190223666Sae * Sort the group list in increasing numerical order.
2191223666Sae * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
2192223666Sae *  that used to be here.)
2193223666Sae */
2194223666Saevoid
2195223666Saenfsrvw_sort(list, num)
2196223666Sae        register gid_t *list;
2197223666Sae        register int num;
2198223666Sae{
2199223666Sae	register int i, j;
2200223666Sae	gid_t v;
2201223666Sae
2202223666Sae	/* Insertion sort. */
2203223666Sae	for (i = 1; i < num; i++) {
2204223666Sae		v = list[i];
2205223666Sae		/* find correct slot for value v, moving others up */
2206223666Sae		for (j = i; --j >= 0 && v < list[j];)
2207223666Sae			list[j + 1] = list[j];
2208223666Sae		list[j + 1] = v;
2209223666Sae	}
2210223666Sae}
2211223666Sae
2212223666Sae/*
2213223666Sae * copy credentials making sure that the result can be compared with bcmp().
2214223666Sae */
2215223666Saevoid
2216223666Saenfsrv_setcred(incred, outcred)
2217223666Sae	register struct ucred *incred, *outcred;
2218223666Sae{
2219223666Sae	register int i;
2220223666Sae
2221223666Sae	bzero((caddr_t)outcred, sizeof (struct ucred));
2222223666Sae	outcred->cr_ref = 1;
2223223666Sae	outcred->cr_uid = incred->cr_uid;
2224223666Sae	outcred->cr_ngroups = incred->cr_ngroups;
2225223666Sae	for (i = 0; i < incred->cr_ngroups; i++)
2226223666Sae		outcred->cr_groups[i] = incred->cr_groups[i];
2227223666Sae	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
2228223666Sae}
2229223666Sae#endif /* NFS_NOSERVER */
2230223666Sae