nfs_srvsubs.c revision 7969
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	@(#)nfs_subs.c	8.3 (Berkeley) 1/4/94
37 * $Id: nfs_subs.c,v 1.12 1995/03/16 18:15:39 bde Exp $
38 */
39
40/*
41 * These functions support the macros and help fiddle mbuf chains for
42 * the nfs op functions. They do things like create the rpc header and
43 * copy data between mbuf chains and uio lists.
44 */
45#include <sys/param.h>
46#include <sys/proc.h>
47#include <sys/systm.h>
48#include <sys/kernel.h>
49#include <sys/mount.h>
50#include <sys/vnode.h>
51#include <sys/namei.h>
52#include <sys/mbuf.h>
53#include <sys/socket.h>
54#include <sys/stat.h>
55#ifdef VFS_LKM
56#include <sys/sysent.h>
57#include <sys/syscall.h>
58#endif
59
60#include <vm/vm.h>
61
62#include <nfs/rpcv2.h>
63#include <nfs/nfsv2.h>
64#include <nfs/nfsnode.h>
65#include <nfs/nfs.h>
66#include <nfs/xdr_subs.h>
67#include <nfs/nfsm_subs.h>
68#include <nfs/nfsmount.h>
69#include <nfs/nqnfs.h>
70#include <nfs/nfsrtt.h>
71
72#include <miscfs/specfs/specdev.h>
73
74#include <vm/vnode_pager.h>
75
76#include <netinet/in.h>
77#ifdef ISO
78#include <netiso/iso.h>
79#endif
80
81#define TRUE	1
82#define	FALSE	0
83
84/*
85 * Data items converted to xdr at startup, since they are constant
86 * This is kinda hokey, but may save a little time doing byte swaps
87 */
88u_long nfs_procids[NFS_NPROCS];
89u_long nfs_xdrneg1;
90u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
91	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
92	rpc_auth_kerb;
93u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
94
95/* And other global data */
96static u_long nfs_xid = 0;
97enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
98extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
99extern int nqnfs_piggy[NFS_NPROCS];
100extern struct nfsrtt nfsrtt;
101extern time_t nqnfsstarttime;
102extern u_long nqnfs_prog, nqnfs_vers;
103extern int nqsrv_clockskew;
104extern int nqsrv_writeslack;
105extern int nqsrv_maxlease;
106
107#ifdef VFS_LKM
108struct getfh_args;
109extern int getfh(struct proc *, struct getfh_args *, int *);
110struct nfssvc_args;
111extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
112#endif
113
114LIST_HEAD(nfsnodehashhead, nfsnode);
115
116/*
117 * Create the header for an rpc request packet
118 * The hsiz is the size of the rest of the nfs request header.
119 * (just used to decide if a cluster is a good idea)
120 */
121struct mbuf *
122nfsm_reqh(vp, procid, hsiz, bposp)
123	struct vnode *vp;
124	u_long procid;
125	int hsiz;
126	caddr_t *bposp;
127{
128	register struct mbuf *mb;
129	register u_long *tl;
130	register caddr_t bpos;
131	struct mbuf *mb2;
132	struct nfsmount *nmp;
133	int nqflag;
134
135	MGET(mb, M_WAIT, MT_DATA);
136	if (hsiz >= MINCLSIZE)
137		MCLGET(mb, M_WAIT);
138	mb->m_len = 0;
139	bpos = mtod(mb, caddr_t);
140
141	/*
142	 * For NQNFS, add lease request.
143	 */
144	if (vp) {
145		nmp = VFSTONFS(vp->v_mount);
146		if (nmp->nm_flag & NFSMNT_NQNFS) {
147			nqflag = NQNFS_NEEDLEASE(vp, procid);
148			if (nqflag) {
149				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
150				*tl++ = txdr_unsigned(nqflag);
151				*tl = txdr_unsigned(nmp->nm_leaseterm);
152			} else {
153				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
154				*tl = 0;
155			}
156		}
157	}
158	/* Finally, return values */
159	*bposp = bpos;
160	return (mb);
161}
162
163/*
164 * Build the RPC header and fill in the authorization info.
165 * The authorization string argument is only used when the credentials
166 * come from outside of the kernel.
167 * Returns the head of the mbuf list.
168 */
169struct mbuf *
170nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
171	mrest_len, mbp, xidp)
172	register struct ucred *cr;
173	int nqnfs;
174	int procid;
175	int auth_type;
176	int auth_len;
177	char *auth_str;
178	struct mbuf *mrest;
179	int mrest_len;
180	struct mbuf **mbp;
181	u_long *xidp;
182{
183	register struct mbuf *mb;
184	register u_long *tl;
185	register caddr_t bpos;
186	register int i;
187	struct mbuf *mreq, *mb2;
188	int siz, grpsiz, authsiz;
189
190	authsiz = nfsm_rndup(auth_len);
191	if (auth_type == RPCAUTH_NQNFS)
192		authsiz += 2 * NFSX_UNSIGNED;
193	MGETHDR(mb, M_WAIT, MT_DATA);
194	if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
195		MCLGET(mb, M_WAIT);
196	} else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
197		MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
198	} else {
199		MH_ALIGN(mb, 8*NFSX_UNSIGNED);
200	}
201	mb->m_len = 0;
202	mreq = mb;
203	bpos = mtod(mb, caddr_t);
204
205	/*
206	 * First the RPC header.
207	 */
208	nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
209	if (++nfs_xid == 0)
210		nfs_xid++;
211	*tl++ = *xidp = txdr_unsigned(nfs_xid);
212	*tl++ = rpc_call;
213	*tl++ = rpc_vers;
214	if (nqnfs) {
215		*tl++ = txdr_unsigned(NQNFS_PROG);
216		*tl++ = txdr_unsigned(NQNFS_VER1);
217	} else {
218		*tl++ = txdr_unsigned(NFS_PROG);
219		*tl++ = txdr_unsigned(NFS_VER2);
220	}
221	*tl++ = txdr_unsigned(procid);
222
223	/*
224	 * And then the authorization cred.
225	 */
226	*tl++ = txdr_unsigned(auth_type);
227	*tl = txdr_unsigned(authsiz);
228	switch (auth_type) {
229	case RPCAUTH_UNIX:
230		nfsm_build(tl, u_long *, auth_len);
231		*tl++ = 0;		/* stamp ?? */
232		*tl++ = 0;		/* NULL hostname */
233		*tl++ = txdr_unsigned(cr->cr_uid);
234		*tl++ = txdr_unsigned(cr->cr_groups[0]);
235		grpsiz = (auth_len >> 2) - 5;
236		*tl++ = txdr_unsigned(grpsiz);
237		for (i = 1; i <= grpsiz; i++)
238			*tl++ = txdr_unsigned(cr->cr_groups[i]);
239		break;
240	case RPCAUTH_NQNFS:
241		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
242		*tl++ = txdr_unsigned(cr->cr_uid);
243		*tl = txdr_unsigned(auth_len);
244		siz = auth_len;
245		while (siz > 0) {
246			if (M_TRAILINGSPACE(mb) == 0) {
247				MGET(mb2, M_WAIT, MT_DATA);
248				if (siz >= MINCLSIZE)
249					MCLGET(mb2, M_WAIT);
250				mb->m_next = mb2;
251				mb = mb2;
252				mb->m_len = 0;
253				bpos = mtod(mb, caddr_t);
254			}
255			i = min(siz, M_TRAILINGSPACE(mb));
256			bcopy(auth_str, bpos, i);
257			mb->m_len += i;
258			auth_str += i;
259			bpos += i;
260			siz -= i;
261		}
262		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
263			for (i = 0; i < siz; i++)
264				*bpos++ = '\0';
265			mb->m_len += siz;
266		}
267		break;
268	};
269	nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
270	*tl++ = txdr_unsigned(RPCAUTH_NULL);
271	*tl = 0;
272	mb->m_next = mrest;
273	mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
274	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
275	*mbp = mb;
276	return (mreq);
277}
278
279/*
280 * copies mbuf chain to the uio scatter/gather list
281 */
282int
283nfsm_mbuftouio(mrep, uiop, siz, dpos)
284	struct mbuf **mrep;
285	register struct uio *uiop;
286	int siz;
287	caddr_t *dpos;
288{
289	register char *mbufcp, *uiocp;
290	register int xfer, left, len;
291	register struct mbuf *mp;
292	long uiosiz, rem;
293	int error = 0;
294
295	mp = *mrep;
296	mbufcp = *dpos;
297	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
298	rem = nfsm_rndup(siz)-siz;
299	while (siz > 0) {
300		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
301			return (EFBIG);
302		left = uiop->uio_iov->iov_len;
303		uiocp = uiop->uio_iov->iov_base;
304		if (left > siz)
305			left = siz;
306		uiosiz = left;
307		while (left > 0) {
308			while (len == 0) {
309				mp = mp->m_next;
310				if (mp == NULL)
311					return (EBADRPC);
312				mbufcp = mtod(mp, caddr_t);
313				len = mp->m_len;
314			}
315			xfer = (left > len) ? len : left;
316#ifdef notdef
317			/* Not Yet.. */
318			if (uiop->uio_iov->iov_op != NULL)
319				(*(uiop->uio_iov->iov_op))
320				(mbufcp, uiocp, xfer);
321			else
322#endif
323			if (uiop->uio_segflg == UIO_SYSSPACE)
324				bcopy(mbufcp, uiocp, xfer);
325			else
326				copyout(mbufcp, uiocp, xfer);
327			left -= xfer;
328			len -= xfer;
329			mbufcp += xfer;
330			uiocp += xfer;
331			uiop->uio_offset += xfer;
332			uiop->uio_resid -= xfer;
333		}
334		if (uiop->uio_iov->iov_len <= siz) {
335			uiop->uio_iovcnt--;
336			uiop->uio_iov++;
337		} else {
338			uiop->uio_iov->iov_base += uiosiz;
339			uiop->uio_iov->iov_len -= uiosiz;
340		}
341		siz -= uiosiz;
342	}
343	*dpos = mbufcp;
344	*mrep = mp;
345	if (rem > 0) {
346		if (len < rem)
347			error = nfs_adv(mrep, dpos, rem, len);
348		else
349			*dpos += rem;
350	}
351	return (error);
352}
353
354/*
355 * copies a uio scatter/gather list to an mbuf chain...
356 */
357int
358nfsm_uiotombuf(uiop, mq, siz, bpos)
359	register struct uio *uiop;
360	struct mbuf **mq;
361	int siz;
362	caddr_t *bpos;
363{
364	register char *uiocp;
365	register struct mbuf *mp, *mp2;
366	register int xfer, left, mlen;
367	int uiosiz, clflg, rem;
368	char *cp;
369
370	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
371		clflg = 1;
372	else
373		clflg = 0;
374	rem = nfsm_rndup(siz)-siz;
375	mp = mp2 = *mq;
376	while (siz > 0) {
377		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
378			return (EINVAL);
379		left = uiop->uio_iov->iov_len;
380		uiocp = uiop->uio_iov->iov_base;
381		if (left > siz)
382			left = siz;
383		uiosiz = left;
384		while (left > 0) {
385			mlen = M_TRAILINGSPACE(mp);
386			if (mlen == 0) {
387				MGET(mp, M_WAIT, MT_DATA);
388				if (clflg)
389					MCLGET(mp, M_WAIT);
390				mp->m_len = 0;
391				mp2->m_next = mp;
392				mp2 = mp;
393				mlen = M_TRAILINGSPACE(mp);
394			}
395			xfer = (left > mlen) ? mlen : left;
396#ifdef notdef
397			/* Not Yet.. */
398			if (uiop->uio_iov->iov_op != NULL)
399				(*(uiop->uio_iov->iov_op))
400				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
401			else
402#endif
403			if (uiop->uio_segflg == UIO_SYSSPACE)
404				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
405			else
406				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
407			mp->m_len += xfer;
408			left -= xfer;
409			uiocp += xfer;
410			uiop->uio_offset += xfer;
411			uiop->uio_resid -= xfer;
412		}
413		if (uiop->uio_iov->iov_len <= siz) {
414			uiop->uio_iovcnt--;
415			uiop->uio_iov++;
416		} else {
417			uiop->uio_iov->iov_base += uiosiz;
418			uiop->uio_iov->iov_len -= uiosiz;
419		}
420		siz -= uiosiz;
421	}
422	if (rem > 0) {
423		if (rem > M_TRAILINGSPACE(mp)) {
424			MGET(mp, M_WAIT, MT_DATA);
425			mp->m_len = 0;
426			mp2->m_next = mp;
427		}
428		cp = mtod(mp, caddr_t)+mp->m_len;
429		for (left = 0; left < rem; left++)
430			*cp++ = '\0';
431		mp->m_len += rem;
432		*bpos = cp;
433	} else
434		*bpos = mtod(mp, caddr_t)+mp->m_len;
435	*mq = mp;
436	return (0);
437}
438
439/*
440 * Help break down an mbuf chain by setting the first siz bytes contiguous
441 * pointed to by returned val.
442 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
443 * cases. (The macros use the vars. dpos and dpos2)
444 */
445int
446nfsm_disct(mdp, dposp, siz, left, cp2)
447	struct mbuf **mdp;
448	caddr_t *dposp;
449	int siz;
450	int left;
451	caddr_t *cp2;
452{
453	register struct mbuf *mp, *mp2;
454	register int siz2, xfer;
455	register caddr_t p;
456
457	mp = *mdp;
458	while (left == 0) {
459		*mdp = mp = mp->m_next;
460		if (mp == NULL)
461			return (EBADRPC);
462		left = mp->m_len;
463		*dposp = mtod(mp, caddr_t);
464	}
465	if (left >= siz) {
466		*cp2 = *dposp;
467		*dposp += siz;
468	} else if (mp->m_next == NULL) {
469		return (EBADRPC);
470	} else if (siz > MHLEN) {
471		panic("nfs S too big");
472	} else {
473		MGET(mp2, M_WAIT, MT_DATA);
474		mp2->m_next = mp->m_next;
475		mp->m_next = mp2;
476		mp->m_len -= left;
477		mp = mp2;
478		*cp2 = p = mtod(mp, caddr_t);
479		bcopy(*dposp, p, left);		/* Copy what was left */
480		siz2 = siz-left;
481		p += left;
482		mp2 = mp->m_next;
483		/* Loop around copying up the siz2 bytes */
484		while (siz2 > 0) {
485			if (mp2 == NULL)
486				return (EBADRPC);
487			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
488			if (xfer > 0) {
489				bcopy(mtod(mp2, caddr_t), p, xfer);
490				NFSMADV(mp2, xfer);
491				mp2->m_len -= xfer;
492				p += xfer;
493				siz2 -= xfer;
494			}
495			if (siz2 > 0)
496				mp2 = mp2->m_next;
497		}
498		mp->m_len = siz;
499		*mdp = mp2;
500		*dposp = mtod(mp2, caddr_t);
501	}
502	return (0);
503}
504
505/*
506 * Advance the position in the mbuf chain.
507 */
508int
509nfs_adv(mdp, dposp, offs, left)
510	struct mbuf **mdp;
511	caddr_t *dposp;
512	int offs;
513	int left;
514{
515	register struct mbuf *m;
516	register int s;
517
518	m = *mdp;
519	s = left;
520	while (s < offs) {
521		offs -= s;
522		m = m->m_next;
523		if (m == NULL)
524			return (EBADRPC);
525		s = m->m_len;
526	}
527	*mdp = m;
528	*dposp = mtod(m, caddr_t)+offs;
529	return (0);
530}
531
532/*
533 * Copy a string into mbufs for the hard cases...
534 */
535int
536nfsm_strtmbuf(mb, bpos, cp, siz)
537	struct mbuf **mb;
538	char **bpos;
539	char *cp;
540	long siz;
541{
542	register struct mbuf *m1 = 0, *m2;
543	long left, xfer, len, tlen;
544	u_long *tl;
545	int putsize;
546
547	putsize = 1;
548	m2 = *mb;
549	left = M_TRAILINGSPACE(m2);
550	if (left > 0) {
551		tl = ((u_long *)(*bpos));
552		*tl++ = txdr_unsigned(siz);
553		putsize = 0;
554		left -= NFSX_UNSIGNED;
555		m2->m_len += NFSX_UNSIGNED;
556		if (left > 0) {
557			bcopy(cp, (caddr_t) tl, left);
558			siz -= left;
559			cp += left;
560			m2->m_len += left;
561			left = 0;
562		}
563	}
564	/* Loop around adding mbufs */
565	while (siz > 0) {
566		MGET(m1, M_WAIT, MT_DATA);
567		if (siz > MLEN)
568			MCLGET(m1, M_WAIT);
569		m1->m_len = NFSMSIZ(m1);
570		m2->m_next = m1;
571		m2 = m1;
572		tl = mtod(m1, u_long *);
573		tlen = 0;
574		if (putsize) {
575			*tl++ = txdr_unsigned(siz);
576			m1->m_len -= NFSX_UNSIGNED;
577			tlen = NFSX_UNSIGNED;
578			putsize = 0;
579		}
580		if (siz < m1->m_len) {
581			len = nfsm_rndup(siz);
582			xfer = siz;
583			if (xfer < len)
584				*(tl+(xfer>>2)) = 0;
585		} else {
586			xfer = len = m1->m_len;
587		}
588		bcopy(cp, (caddr_t) tl, xfer);
589		m1->m_len = len+tlen;
590		siz -= xfer;
591		cp += xfer;
592	}
593	*mb = m1;
594	*bpos = mtod(m1, caddr_t)+m1->m_len;
595	return (0);
596}
597
598/*
599 * Called once to initialize data structures...
600 */
601int
602nfs_init()
603{
604	register int i;
605
606	nfsrtt.pos = 0;
607	rpc_vers = txdr_unsigned(RPC_VER2);
608	rpc_call = txdr_unsigned(RPC_CALL);
609	rpc_reply = txdr_unsigned(RPC_REPLY);
610	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
611	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
612	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
613	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
614	rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
615	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
616	rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
617	nfs_vers = txdr_unsigned(NFS_VER2);
618	nfs_prog = txdr_unsigned(NFS_PROG);
619	nfs_true = txdr_unsigned(TRUE);
620	nfs_false = txdr_unsigned(FALSE);
621	nfs_xdrneg1 = txdr_unsigned(-1);
622	/* Loop thru nfs procids */
623	for (i = 0; i < NFS_NPROCS; i++)
624		nfs_procids[i] = txdr_unsigned(i);
625	/* Ensure async daemons disabled */
626	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
627		nfs_iodwant[i] = (struct proc *)0;
628	TAILQ_INIT(&nfs_bufq);
629	nfs_nhinit();			/* Init the nfsnode table */
630	nfsrv_init(0);			/* Init server data structures */
631	nfsrv_initcache();		/* Init the server request cache */
632
633	/*
634	 * Initialize the nqnfs server stuff.
635	 */
636	if (nqnfsstarttime == 0) {
637		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
638			+ nqsrv_clockskew + nqsrv_writeslack;
639		NQLOADNOVRAM(nqnfsstarttime);
640		nqnfs_prog = txdr_unsigned(NQNFS_PROG);
641		nqnfs_vers = txdr_unsigned(NQNFS_VER1);
642		CIRCLEQ_INIT(&nqtimerhead);
643		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
644	}
645
646	/*
647	 * Initialize reply list and start timer
648	 */
649	TAILQ_INIT(&nfs_reqq);
650	nfs_timer(0);
651
652	/*
653	 * Set up lease_check and lease_updatetime so that other parts
654	 * of the system can call us, if we are loadable.
655	 */
656	lease_check = nfs_lease_check;
657	lease_updatetime = nfs_lease_updatetime;
658	vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */
659#ifdef VFS_LKM
660	sysent[SYS_nfssvc].sy_narg = 2;
661	sysent[SYS_nfssvc].sy_call = nfssvc;
662	sysent[SYS_getfh].sy_narg = 2;
663	sysent[SYS_getfh].sy_call = getfh;
664#endif
665
666	return (0);
667}
668
669/*
670 * Attribute cache routines.
671 * nfs_loadattrcache() - loads or updates the cache contents from attributes
672 *	that are on the mbuf list
673 * nfs_getattrcache() - returns valid attributes if found in cache, returns
674 *	error otherwise
675 */
676
677/*
678 * Load the attribute cache (that lives in the nfsnode entry) with
679 * the values on the mbuf list and
680 * Iff vap not NULL
681 *    copy the attributes to *vaper
682 */
683int
684nfs_loadattrcache(vpp, mdp, dposp, vaper)
685	struct vnode **vpp;
686	struct mbuf **mdp;
687	caddr_t *dposp;
688	struct vattr *vaper;
689{
690	register struct vnode *vp = *vpp;
691	register struct vattr *vap;
692	register struct nfsv2_fattr *fp;
693	register struct nfsnode *np;
694	register struct nfsnodehashhead *nhpp;
695	register long t1;
696	caddr_t dpos, cp2;
697	int error = 0, isnq;
698	struct mbuf *md;
699	enum vtype vtyp;
700	u_short vmode;
701	long rdev;
702	struct timespec mtime;
703	struct vnode *nvp;
704
705	md = *mdp;
706	dpos = *dposp;
707	t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
708	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
709	error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2);
710	if (error)
711		return (error);
712	fp = (struct nfsv2_fattr *)cp2;
713	vtyp = nfstov_type(fp->fa_type);
714	vmode = fxdr_unsigned(u_short, fp->fa_mode);
715	if (vtyp == VNON || vtyp == VREG)
716		vtyp = IFTOVT(vmode);
717	if (isnq) {
718		rdev = fxdr_unsigned(long, fp->fa_nqrdev);
719		fxdr_nqtime(&fp->fa_nqmtime, &mtime);
720	} else {
721		rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
722		fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
723	}
724	/*
725	 * If v_type == VNON it is a new node, so fill in the v_type,
726	 * n_mtime fields. Check to see if it represents a special
727	 * device, and if so, check for a possible alias. Once the
728	 * correct vnode has been obtained, fill in the rest of the
729	 * information.
730	 */
731	np = VTONFS(vp);
732	if (vp->v_type == VNON) {
733		if (vtyp == VCHR && rdev == 0xffffffff)
734			vp->v_type = vtyp = VFIFO;
735		else
736			vp->v_type = vtyp;
737		if (vp->v_type == VFIFO) {
738			vp->v_op = fifo_nfsv2nodeop_p;
739		}
740		if (vp->v_type == VCHR || vp->v_type == VBLK) {
741			vp->v_op = spec_nfsv2nodeop_p;
742			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
743			if (nvp) {
744				/*
745				 * Discard unneeded vnode, but save its nfsnode.
746				 */
747				LIST_REMOVE(np, n_hash);
748				nvp->v_data = vp->v_data;
749				vp->v_data = NULL;
750				vp->v_op = spec_vnodeop_p;
751				vrele(vp);
752				vgone(vp);
753				/*
754				 * Reinitialize aliased node.
755				 */
756				np->n_vnode = nvp;
757				nhpp = nfs_hash(&np->n_fh);
758				LIST_INSERT_HEAD(nhpp, np, n_hash);
759				*vpp = vp = nvp;
760			}
761		}
762		np->n_mtime = mtime.ts_sec;
763	}
764	vap = &np->n_vattr;
765	vap->va_type = vtyp;
766	vap->va_mode = (vmode & 07777);
767	vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
768	vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
769	vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
770	vap->va_rdev = (dev_t)rdev;
771	vap->va_mtime = mtime;
772	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
773	if (isnq) {
774		fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
775		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
776		fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
777		vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
778		fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
779		vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
780		fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
781		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
782		fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
783	} else {
784		vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
785		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
786		vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
787		vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
788		fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
789		vap->va_flags = 0;
790		fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime);
791		vap->va_gen = 0;
792		vap->va_filerev = 0;
793	}
794	if (vap->va_size != np->n_size) {
795		if (vap->va_type == VREG) {
796			if (np->n_flag & NMODIFIED) {
797				if (vap->va_size < np->n_size)
798					vap->va_size = np->n_size;
799				else
800					np->n_size = vap->va_size;
801			} else
802				np->n_size = vap->va_size;
803			vnode_pager_setsize(vp, (u_long)np->n_size);
804		} else
805			np->n_size = vap->va_size;
806	}
807	np->n_attrstamp = time.tv_sec;
808	*dposp = dpos;
809	*mdp = md;
810	if (vaper != NULL) {
811		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
812#ifdef notdef
813		if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
814		if (np->n_size > vap->va_size)
815			vaper->va_size = np->n_size;
816#endif
817		if (np->n_flag & NCHG) {
818			if (np->n_flag & NACC) {
819				vaper->va_atime.ts_sec = np->n_atim.tv_sec;
820				vaper->va_atime.ts_nsec =
821				    np->n_atim.tv_usec * 1000;
822			}
823			if (np->n_flag & NUPD) {
824				vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
825				vaper->va_mtime.ts_nsec =
826				    np->n_mtim.tv_usec * 1000;
827			}
828		}
829	}
830	return (0);
831}
832
833/*
834 * Check the time stamp
835 * If the cache is valid, copy contents to *vap and return 0
836 * otherwise return an error
837 */
838int
839nfs_getattrcache(vp, vaper)
840	register struct vnode *vp;
841	struct vattr *vaper;
842{
843	register struct nfsnode *np = VTONFS(vp);
844	register struct vattr *vap;
845
846	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
847		if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
848			nfsstats.attrcache_misses++;
849			return (ENOENT);
850		}
851	} else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
852		nfsstats.attrcache_misses++;
853		return (ENOENT);
854	}
855	nfsstats.attrcache_hits++;
856	vap = &np->n_vattr;
857	if (vap->va_size != np->n_size) {
858		if (vap->va_type == VREG) {
859			if (np->n_flag & NMODIFIED) {
860				if (vap->va_size < np->n_size)
861					vap->va_size = np->n_size;
862				else
863					np->n_size = vap->va_size;
864			} else
865				np->n_size = vap->va_size;
866			vnode_pager_setsize(vp, (u_long)np->n_size);
867		} else
868			np->n_size = vap->va_size;
869	}
870	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
871#ifdef notdef
872	if ((np->n_flag & NMODIFIED) == 0) {
873		np->n_size = vaper->va_size;
874		vnode_pager_setsize(vp, (u_long)np->n_size);
875	} else if (np->n_size > vaper->va_size)
876	if (np->n_size > vaper->va_size)
877		vaper->va_size = np->n_size;
878#endif
879	if (np->n_flag & NCHG) {
880		if (np->n_flag & NACC) {
881			vaper->va_atime.ts_sec = np->n_atim.tv_sec;
882			vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
883		}
884		if (np->n_flag & NUPD) {
885			vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
886			vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
887		}
888	}
889	return (0);
890}
891
892/*
893 * Set up nameidata for a lookup() call and do it
894 */
895int
896nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
897	register struct nameidata *ndp;
898	fhandle_t *fhp;
899	int len;
900	struct nfssvc_sock *slp;
901	struct mbuf *nam;
902	struct mbuf **mdp;
903	caddr_t *dposp;
904	struct proc *p;
905{
906	register int i, rem;
907	register struct mbuf *md;
908	register char *fromcp, *tocp;
909	struct vnode *dp;
910	int error, rdonly;
911	struct componentname *cnp = &ndp->ni_cnd;
912
913	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
914	/*
915	 * Copy the name from the mbuf list to ndp->ni_pnbuf
916	 * and set the various ndp fields appropriately.
917	 */
918	fromcp = *dposp;
919	tocp = cnp->cn_pnbuf;
920	md = *mdp;
921	rem = mtod(md, caddr_t) + md->m_len - fromcp;
922	cnp->cn_hash = 0;
923	for (i = 0; i < len; i++) {
924		while (rem == 0) {
925			md = md->m_next;
926			if (md == NULL) {
927				error = EBADRPC;
928				goto out;
929			}
930			fromcp = mtod(md, caddr_t);
931			rem = md->m_len;
932		}
933		if (*fromcp == '\0' || *fromcp == '/') {
934			error = EINVAL;
935			goto out;
936		}
937		cnp->cn_hash += (unsigned char)*fromcp;
938		*tocp++ = *fromcp++;
939		rem--;
940	}
941	*tocp = '\0';
942	*mdp = md;
943	*dposp = fromcp;
944	len = nfsm_rndup(len)-len;
945	if (len > 0) {
946		if (rem >= len)
947			*dposp += len;
948		else {
949			error = nfs_adv(mdp, dposp, len, rem);
950			if (error)
951				goto out;
952		}
953	}
954	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
955	cnp->cn_nameptr = cnp->cn_pnbuf;
956	/*
957	 * Extract and set starting directory.
958	 */
959	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
960	    nam, &rdonly);
961	if (error)
962		goto out;
963	if (dp->v_type != VDIR) {
964		nfsrv_vrele(dp);
965		error = ENOTDIR;
966		goto out;
967	}
968	ndp->ni_startdir = dp;
969	if (rdonly)
970		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
971	else
972		cnp->cn_flags |= NOCROSSMOUNT;
973	/*
974	 * And call lookup() to do the real work
975	 */
976	cnp->cn_proc = p;
977	error = lookup(ndp);
978	if (error)
979		goto out;
980	/*
981	 * Check for encountering a symbolic link
982	 */
983	if (cnp->cn_flags & ISSYMLINK) {
984		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
985			vput(ndp->ni_dvp);
986		else
987			vrele(ndp->ni_dvp);
988		vput(ndp->ni_vp);
989		ndp->ni_vp = NULL;
990		error = EINVAL;
991		goto out;
992	}
993	/*
994	 * Check for saved name request
995	 */
996	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
997		cnp->cn_flags |= HASBUF;
998		nfsrv_vmio( ndp->ni_vp);
999		return (0);
1000	}
1001out:
1002	FREE(cnp->cn_pnbuf, M_NAMEI);
1003	return (error);
1004}
1005
1006/*
1007 * A fiddled version of m_adj() that ensures null fill to a long
1008 * boundary and only trims off the back end
1009 */
1010void
1011nfsm_adj(mp, len, nul)
1012	struct mbuf *mp;
1013	register int len;
1014	int nul;
1015{
1016	register struct mbuf *m;
1017	register int count, i;
1018	register char *cp;
1019
1020	/*
1021	 * Trim from tail.  Scan the mbuf chain,
1022	 * calculating its length and finding the last mbuf.
1023	 * If the adjustment only affects this mbuf, then just
1024	 * adjust and return.  Otherwise, rescan and truncate
1025	 * after the remaining size.
1026	 */
1027	count = 0;
1028	m = mp;
1029	for (;;) {
1030		count += m->m_len;
1031		if (m->m_next == (struct mbuf *)0)
1032			break;
1033		m = m->m_next;
1034	}
1035	if (m->m_len > len) {
1036		m->m_len -= len;
1037		if (nul > 0) {
1038			cp = mtod(m, caddr_t)+m->m_len-nul;
1039			for (i = 0; i < nul; i++)
1040				*cp++ = '\0';
1041		}
1042		return;
1043	}
1044	count -= len;
1045	if (count < 0)
1046		count = 0;
1047	/*
1048	 * Correct length for chain is "count".
1049	 * Find the mbuf with last data, adjust its length,
1050	 * and toss data from remaining mbufs on chain.
1051	 */
1052	for (m = mp; m; m = m->m_next) {
1053		if (m->m_len >= count) {
1054			m->m_len = count;
1055			if (nul > 0) {
1056				cp = mtod(m, caddr_t)+m->m_len-nul;
1057				for (i = 0; i < nul; i++)
1058					*cp++ = '\0';
1059			}
1060			break;
1061		}
1062		count -= m->m_len;
1063	}
1064	for (m = m->m_next;m;m = m->m_next)
1065		m->m_len = 0;
1066}
1067
1068/*
1069 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1070 * 	- look up fsid in mount list (if not found ret error)
1071 *	- get vp and export rights by calling VFS_FHTOVP()
1072 *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1073 *	- if not lockflag unlock it with VOP_UNLOCK()
1074 */
1075int
1076nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
1077	fhandle_t *fhp;
1078	int lockflag;
1079	struct vnode **vpp;
1080	struct ucred *cred;
1081	struct nfssvc_sock *slp;
1082	struct mbuf *nam;
1083	int *rdonlyp;
1084{
1085	register struct mount *mp;
1086	register struct nfsuid *uidp;
1087	register int i;
1088	struct ucred *credanon;
1089	int error, exflags;
1090
1091	*vpp = (struct vnode *)0;
1092	mp = getvfs(&fhp->fh_fsid);
1093	if (!mp)
1094		return (ESTALE);
1095	error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
1096	if (error)
1097		return (error);
1098	/*
1099	 * Check/setup credentials.
1100	 */
1101	if (exflags & MNT_EXKERB) {
1102		for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0;
1103		    uidp = uidp->nu_hash.le_next) {
1104			if (uidp->nu_uid == cred->cr_uid)
1105				break;
1106		}
1107		if (uidp == 0) {
1108			vput(*vpp);
1109			return (NQNFS_AUTHERR);
1110		}
1111		cred->cr_uid = uidp->nu_cr.cr_uid;
1112		for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
1113			cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
1114		cred->cr_ngroups = i;
1115	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1116		cred->cr_uid = credanon->cr_uid;
1117		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1118			cred->cr_groups[i] = credanon->cr_groups[i];
1119		cred->cr_ngroups = i;
1120	}
1121	if (exflags & MNT_EXRDONLY)
1122		*rdonlyp = 1;
1123	else
1124		*rdonlyp = 0;
1125
1126	nfsrv_vmio(*vpp);
1127
1128	if (!lockflag)
1129		VOP_UNLOCK(*vpp);
1130	return (0);
1131}
1132
1133/*
1134 * This function compares two net addresses by family and returns TRUE
1135 * if they are the same host.
1136 * If there is any doubt, return FALSE.
1137 * The AF_INET family is handled as a special case so that address mbufs
1138 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1139 */
1140int
1141netaddr_match(family, haddr, nam)
1142	int family;
1143	union nethostaddr *haddr;
1144	struct mbuf *nam;
1145{
1146	register struct sockaddr_in *inetaddr;
1147
1148	switch (family) {
1149	case AF_INET:
1150		inetaddr = mtod(nam, struct sockaddr_in *);
1151		if (inetaddr->sin_family == AF_INET &&
1152		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1153			return (1);
1154		break;
1155#ifdef ISO
1156	case AF_ISO:
1157	    {
1158		register struct sockaddr_iso *isoaddr1, *isoaddr2;
1159
1160		isoaddr1 = mtod(nam, struct sockaddr_iso *);
1161		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
1162		if (isoaddr1->siso_family == AF_ISO &&
1163		    isoaddr1->siso_nlen > 0 &&
1164		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
1165		    SAME_ISOADDR(isoaddr1, isoaddr2))
1166			return (1);
1167		break;
1168	    }
1169#endif	/* ISO */
1170	default:
1171		break;
1172	};
1173	return (0);
1174}
1175
1176int
1177nfsrv_vmio( struct vnode *vp) {
1178	vm_object_t object;
1179	vm_pager_t pager;
1180
1181	if( (vp == NULL) || (vp->v_type != VREG))
1182		return 1;
1183
1184retry:
1185	if( (vp->v_flag & VVMIO) == 0) {
1186		pager = (vm_pager_t) vnode_pager_alloc((caddr_t) vp, 0, 0, 0);
1187		object = (vm_object_t) vp->v_vmdata;
1188		if( object->pager != pager)
1189			panic("nfsrv_vmio: pager/object mismatch");
1190		(void) vm_object_lookup( pager);
1191		pager_cache( object, TRUE);
1192		vp->v_flag |= VVMIO;
1193	} else {
1194		if( (object = (vm_object_t)vp->v_vmdata) &&
1195			(object->flags & OBJ_DEAD)) {
1196			tsleep( (caddr_t) object, PVM, "nfdead", 0);
1197			goto retry;
1198		}
1199		if( !object)
1200			panic("nfsrv_vmio: VMIO object missing");
1201		pager = object->pager;
1202		if( !pager)
1203			panic("nfsrv_vmio: VMIO pager missing");
1204		(void) vm_object_lookup( pager);
1205	}
1206	return 0;
1207}
1208int
1209nfsrv_vput( struct vnode *vp) {
1210	if( (vp->v_flag & VVMIO) && vp->v_vmdata) {
1211		vput( vp);
1212		vm_object_deallocate( (vm_object_t) vp->v_vmdata);
1213	} else {
1214		vput( vp);
1215	}
1216	return 0;
1217}
1218int
1219nfsrv_vrele( struct vnode *vp) {
1220	if( (vp->v_flag & VVMIO) && vp->v_vmdata) {
1221		vrele( vp);
1222		vm_object_deallocate( (vm_object_t) vp->v_vmdata);
1223	} else {
1224		vrele( vp);
1225	}
1226	return 0;
1227}
1228