xref: /csrg-svn/sys/nfs/nfs_subs.c (revision 38421)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * 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 are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  *	@(#)nfs_subs.c	7.2 (Berkeley) 07/05/89
21  */
22 
23 /*
24  * These functions support the macros and help fiddle mbuf chains for
25  * the nfs op functions. They do things like create the rpc header and
26  * copy data between mbuf chains and uio lists.
27  */
28 #include "strings.h"
29 #include "types.h"
30 #include "param.h"
31 #include "mount.h"
32 #include "dir.h"
33 #include "time.h"
34 #include "errno.h"
35 #include "kernel.h"
36 #include "malloc.h"
37 #include "mbuf.h"
38 #include "file.h"
39 #include "vnode.h"
40 #include "uio.h"
41 #include "namei.h"
42 #include "ucred.h"
43 #include "rpcv2.h"
44 #include "nfsv2.h"
45 #include "nfsnode.h"
46 #include "nfs.h"
47 #include "xdr_subs.h"
48 #include "nfsm_subs.h"
49 
50 #define TRUE	1
51 #define	FALSE	0
52 
53 /*
54  * Data items converted to xdr at startup, since they are constant
55  * This is kinda hokey, but may save a little time doing byte swaps
56  */
57 u_long nfs_procids[NFS_NPROCS];
58 u_long nfs_xdrneg1;
59 u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied,
60 	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
61 u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
62 /* And other global data */
63 static u_long *rpc_uidp = (u_long *)0;
64 static u_long nfs_xid = 1;
65 static char *rpc_unixauth;
66 extern long hostid;
67 extern enum vtype v_type[NFLNK+1];
68 
69 /* Function ret types */
70 static char *nfs_unixauth();
71 
72 /*
73  * Create the header for an rpc request packet
74  * The function nfs_unixauth() creates a unix style authorization string
75  * and returns a ptr to it.
76  * The hsiz is the size of the rest of the nfs request header.
77  * (just used to decide if a cluster is a good idea)
78  * nb: Note that the prog, vers and proc args are already in xdr byte order
79  */
80 struct mbuf *nfsm_reqh(prog, vers, proc, cred, hsiz, bpos, mb, retxid)
81 	u_long prog;
82 	u_long vers;
83 	u_long proc;
84 	struct ucred *cred;
85 	int hsiz;
86 	caddr_t *bpos;
87 	struct mbuf **mb;
88 	u_long *retxid;
89 {
90 	register struct mbuf *mreq, *m;
91 	register u_long *p;
92 	struct mbuf *m1;
93 	char *ap;
94 	int asiz, siz;
95 
96 	NFSMGETHDR(mreq);
97 	asiz = (((cred->cr_ngroups > 10) ? 10 : cred->cr_ngroups)<<2);
98 	asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED);
99 
100 	/* If we need a lot, alloc a cluster ?? */
101 	if ((asiz+hsiz+RPC_SIZ) > MHLEN)
102 		NFSMCLGET(mreq, M_WAIT);
103 	mreq->m_len = NFSMSIZ(mreq);
104 	siz = mreq->m_len;
105 	m1 = mreq;
106 	/*
107 	 * Alloc enough mbufs
108 	 * We do it now to avoid all sleeps after the call to nfs_unixauth()
109 	 */
110 	while ((asiz+RPC_SIZ) > siz) {
111 		MGET(m, M_WAIT, MT_DATA);
112 		m1->m_next = m;
113 		m->m_len = MLEN;
114 		siz += MLEN;
115 		m1 = m;
116 	}
117 	p = mtod(mreq, u_long *);
118 	*p++ = *retxid = txdr_unsigned(++nfs_xid);
119 	*p++ = rpc_call;
120 	*p++ = rpc_vers;
121 	*p++ = prog;
122 	*p++ = vers;
123 	*p++ = proc;
124 
125 	/* Now we can call nfs_unixauth() and copy it in */
126 	ap = nfs_unixauth(cred);
127 	m = mreq;
128 	siz = m->m_len-RPC_SIZ;
129 	if (asiz <= siz) {
130 		bcopy(ap, (caddr_t)p, asiz);
131 		m->m_len = asiz+RPC_SIZ;
132 	} else {
133 		bcopy(ap, (caddr_t)p, siz);
134 		ap += siz;
135 		asiz -= siz;
136 		while (asiz > 0) {
137 			siz = (asiz > MLEN) ? MLEN : asiz;
138 			m = m->m_next;
139 			bcopy(ap, mtod(m, caddr_t), siz);
140 			m->m_len = siz;
141 			asiz -= siz;
142 			ap += siz;
143 		}
144 	}
145 
146 	/* Finally, return values */
147 	*mb = m;
148 	*bpos = mtod(m, caddr_t)+m->m_len;
149 	return (mreq);
150 }
151 
152 /*
153  * copies mbuf chain to the uio scatter/gather list
154  */
155 nfsm_mbuftouio(mrep, uiop, siz, dpos)
156 	struct mbuf **mrep;
157 	struct uio *uiop;
158 	int siz;
159 	caddr_t *dpos;
160 {
161 	register int xfer, left, len;
162 	register struct mbuf *mp;
163 	register char *mbufcp, *uiocp;
164 	long uiosiz, rem;
165 
166 	mp = *mrep;
167 	mbufcp = *dpos;
168 	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
169 	rem = nfsm_rndup(siz)-siz;
170 	while (siz > 0) {
171 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
172 			return(EFBIG);
173 		left = uiop->uio_iov->iov_len;
174 		uiocp = uiop->uio_iov->iov_base;
175 		if (left > siz)
176 			left = siz;
177 		uiosiz = left;
178 		while (left > 0) {
179 			while (len == 0) {
180 				mp = mp->m_next;
181 				if (mp == NULL)
182 					return (EBADRPC);
183 				mbufcp = mtod(mp, caddr_t);
184 				len = mp->m_len;
185 			}
186 			xfer = (left > len) ? len : left;
187 #ifdef notdef
188 			/* Not Yet.. */
189 			if (uiop->uio_iov->iov_op != NULL)
190 				(*(uiop->uio_iov->iov_op))
191 				(mbufcp, uiocp, xfer);
192 			else
193 #endif
194 			if (uiop->uio_segflg == UIO_SYSSPACE)
195 				bcopy(mbufcp, uiocp, xfer);
196 			else
197 				copyout(mbufcp, uiocp, xfer);
198 			left -= xfer;
199 			len -= xfer;
200 			mbufcp += xfer;
201 			uiocp += xfer;
202 			uiop->uio_resid -= xfer;
203 		}
204 		if (uiop->uio_iov->iov_len <= siz) {
205 			uiop->uio_iovcnt--;
206 			uiop->uio_iov++;
207 		} else {
208 			uiop->uio_iov->iov_base += uiosiz;
209 			uiop->uio_iov->iov_len -= uiosiz;
210 		}
211 		siz -= uiosiz;
212 	}
213 	if (rem > 0)
214 		mbufcp += rem;
215 	*dpos = mbufcp;
216 	*mrep = mp;
217 	return(0);
218 }
219 
220 /*
221  * copies a uio scatter/gather list to an mbuf chain...
222  */
223 nfsm_uiotombuf(uiop, mq, siz, bpos)
224 	register struct uio *uiop;
225 	struct mbuf **mq;
226 	int siz;
227 	caddr_t *bpos;
228 {
229 	register struct mbuf *mp;
230 	struct mbuf *mp2;
231 	long xfer, left, uiosiz, off;
232 	int clflg;
233 	int rem, len;
234 	char *cp, *uiocp;
235 
236 	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
237 		clflg = 1;
238 	else
239 		clflg = 0;
240 	rem = nfsm_rndup(siz)-siz;
241 	mp2 = *mq;
242 	while (siz > 0) {
243 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
244 			return(EINVAL);
245 		left = uiop->uio_iov->iov_len;
246 		uiocp = uiop->uio_iov->iov_base;
247 		if (left > siz)
248 			left = siz;
249 		uiosiz = left;
250 		while (left > 0) {
251 			MGET(mp, M_WAIT, MT_DATA);
252 			if (clflg)
253 				NFSMCLGET(mp, M_WAIT);
254 			mp->m_len = NFSMSIZ(mp);
255 			mp2->m_next = mp;
256 			mp2 = mp;
257 			xfer = (left > mp->m_len) ? mp->m_len : left;
258 #ifdef notdef
259 			/* Not Yet.. */
260 			if (uiop->uio_iov->iov_op != NULL)
261 				(*(uiop->uio_iov->iov_op))
262 				(uiocp, mtod(mp, caddr_t), xfer);
263 			else
264 #endif
265 			if (uiop->uio_segflg == UIO_SYSSPACE)
266 				bcopy(uiocp, mtod(mp, caddr_t), xfer);
267 			else
268 				copyin(uiocp, mtod(mp, caddr_t), xfer);
269 			len = mp->m_len;
270 			mp->m_len = xfer;
271 			left -= xfer;
272 			uiocp += xfer;
273 			uiop->uio_resid -= xfer;
274 		}
275 		if (uiop->uio_iov->iov_len <= siz) {
276 			uiop->uio_iovcnt--;
277 			uiop->uio_iov++;
278 		} else {
279 			uiop->uio_iov->iov_base += uiosiz;
280 			uiop->uio_iov->iov_len -= uiosiz;
281 		}
282 		siz -= uiosiz;
283 	}
284 	if (rem > 0) {
285 		if (rem > (len-mp->m_len)) {
286 			MGET(mp, M_WAIT, MT_DATA);
287 			mp->m_len = 0;
288 			mp2->m_next = mp;
289 		}
290 		cp = mtod(mp, caddr_t)+mp->m_len;
291 		for (left = 0; left < rem; left++)
292 			*cp++ = '\0';
293 		mp->m_len += rem;
294 		*bpos = cp;
295 	} else
296 		*bpos = mtod(mp, caddr_t)+mp->m_len;
297 	*mq = mp;
298 	return(0);
299 }
300 
301 /*
302  * Help break down an mbuf chain by setting the first siz bytes contiguous
303  * pointed to by returned val.
304  * If Updateflg == True we can overwrite the first part of the mbuf data
305  * This is used by the macros nfsm_disect and nfsm_disecton for tough
306  * cases. (The macros use the vars. dpos and dpos2)
307  */
308 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
309 	struct mbuf **mdp;
310 	caddr_t *dposp;
311 	int siz;
312 	int left;
313 	int updateflg;
314 	caddr_t *cp2;
315 {
316 	register struct mbuf *mp, *mp2;
317 	register int siz2, xfer;
318 	register caddr_t p;
319 	caddr_t p2;
320 
321 	mp = *mdp;
322 	while (left == 0) {
323 		*mdp = mp = mp->m_next;
324 		if (mp == NULL)
325 			return(EBADRPC);
326 		left = mp->m_len;
327 		*dposp = mtod(mp, caddr_t);
328 	}
329 	if (left >= siz) {
330 		*cp2 = *dposp;
331 		*dposp += siz;
332 		return(0);
333 	} else if (mp->m_next == NULL) {
334 		return(EBADRPC);
335 	} else if (siz > MCLBYTES) {
336 		panic("nfs S too big");
337 	} else {
338 		/* Iff update, you can overwrite, else must alloc new mbuf */
339 		if (updateflg) {
340 			NFSMINOFF(mp);
341 		} else {
342 			MGET(mp2, M_WAIT, MT_DATA);
343 			mp2->m_next = mp->m_next;
344 			mp->m_next = mp2;
345 			mp->m_len -= left;
346 			mp = mp2;
347 		}
348 		/* Alloc cluster iff we need it */
349 		if (!M_HASCL(mp) && siz > NFSMSIZ(mp)) {
350 			NFSMCLGET(mp, M_WAIT);
351 			if (!M_HASCL(mp))
352 				return(ENOBUFS);
353 		}
354 		*cp2 = p = mtod(mp, caddr_t);
355 		bcopy(*dposp, p, left);		/* Copy what was left */
356 		siz2 = siz-left;
357 		p += left;
358 		mp2 = mp->m_next;
359 		/* Loop arround copying up the siz2 bytes */
360 		while (siz2 > 0) {
361 			if (mp2 == NULL)
362 				return (EBADRPC);
363 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
364 			bcopy(mtod(mp2, caddr_t), p, xfer);
365 			NFSMADV(mp2, xfer);
366 			mp2->m_len -= xfer;
367 			siz2 -= xfer;
368 			if (siz2 > 0)
369 				mp2 = mp2->m_next;
370 		}
371 		mp->m_len = siz;
372 		*mdp = mp2;
373 		*dposp = mtod(mp2, caddr_t);
374 		return (0);
375 	}
376 }
377 
378 /*
379  * Advance the position in the mbuf chain with/without freeing mbufs
380  */
381 nfs_adv(mdp, dposp, offs, left)
382 	struct mbuf **mdp;
383 	caddr_t *dposp;
384 	int offs;
385 	int left;
386 {
387 	register struct mbuf *m;
388 	register int s;
389 
390 	m = *mdp;
391 	s = left;
392 	while (s < offs) {
393 		offs -= s;
394 		m = m->m_next;
395 		if (m == NULL)
396 			return(EBADRPC);
397 		s = m->m_len;
398 	}
399 	*mdp = m;
400 	*dposp = mtod(m, caddr_t)+offs;
401 	return(0);
402 }
403 
404 /*
405  * Copy a string into mbufs for the hard cases...
406  */
407 nfsm_strtmbuf(mb, bpos, cp, siz)
408 	struct mbuf **mb;
409 	char **bpos;
410 	char *cp;
411 	long siz;
412 {
413 	register struct mbuf *m1, *m2;
414 	long left, xfer, len, tlen;
415 	u_long *p;
416 	int putsize;
417 
418 	putsize = 1;
419 	m2 = *mb;
420 	left = NFSMSIZ(m2)-m2->m_len;
421 	if (left > 0) {
422 		p = ((u_long *)(*bpos));
423 		*p++ = txdr_unsigned(siz);
424 		putsize = 0;
425 		left -= NFSX_UNSIGNED;
426 		m2->m_len += NFSX_UNSIGNED;
427 		if (left > 0) {
428 			bcopy(cp, (caddr_t) p, left);
429 			siz -= left;
430 			cp += left;
431 			m2->m_len += left;
432 			left = 0;
433 		}
434 	}
435 	/* Loop arround adding mbufs */
436 	while (siz > 0) {
437 		MGET(m1, M_WAIT, MT_DATA);
438 		if (siz > MLEN)
439 			NFSMCLGET(m1, M_WAIT);
440 		m1->m_len = NFSMSIZ(m1);
441 		m2->m_next = m1;
442 		m2 = m1;
443 		p = mtod(m1, u_long *);
444 		tlen = 0;
445 		if (putsize) {
446 			*p++ = txdr_unsigned(siz);
447 			m1->m_len -= NFSX_UNSIGNED;
448 			tlen = NFSX_UNSIGNED;
449 			putsize = 0;
450 		}
451 		if (siz < m1->m_len) {
452 			len = nfsm_rndup(siz);
453 			xfer = siz;
454 			if (xfer < len)
455 				*(p+(xfer>>2)) = 0;
456 		} else {
457 			xfer = len = m1->m_len;
458 		}
459 		bcopy(cp, (caddr_t) p, xfer);
460 		m1->m_len = len+tlen;
461 		siz -= xfer;
462 		cp += xfer;
463 	}
464 	*mb = m1;
465 	*bpos = mtod(m1, caddr_t)+m1->m_len;
466 	return(0);
467 }
468 
469 /*
470  * Called once to initialize data structures...
471  */
472 nfsinit()
473 {
474 	register int i;
475 
476 	rpc_vers = txdr_unsigned(RPC_VER2);
477 	rpc_call = txdr_unsigned(RPC_CALL);
478 	rpc_reply = txdr_unsigned(RPC_REPLY);
479 	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
480 	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
481 	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
482 	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
483 	nfs_vers = txdr_unsigned(NFS_VER2);
484 	nfs_prog = txdr_unsigned(NFS_PROG);
485 	nfs_true = txdr_unsigned(TRUE);
486 	nfs_false = txdr_unsigned(FALSE);
487 	/* Loop thru nfs procids */
488 	for (i = 0; i < NFS_NPROCS; i++)
489 		nfs_procids[i] = txdr_unsigned(i);
490 	v_type[0] = VNON;
491 	v_type[1] = VREG;
492 	v_type[2] = VDIR;
493 	v_type[3] = VBLK;
494 	v_type[4] = VCHR;
495 	v_type[5] = VLNK;
496 	nfs_xdrneg1 = txdr_unsigned(-1);
497 	nfs_nhinit();			/* Init the nfsnode table */
498 	/* And start timer */
499 	nfs_timer();
500 }
501 
502 /*
503  * Fill in the rest of the rpc_unixauth and return it
504  */
505 static char *nfs_unixauth(cr)
506 	register struct ucred *cr;
507 {
508 	register u_long *p;
509 	register int i;
510 	int ngr;
511 
512 	/* Maybe someday there should be a cache of AUTH_SHORT's */
513 	if ((p = rpc_uidp) == NULL) {
514 		i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED);
515 		MALLOC(p, u_long *, i, M_TEMP, M_WAITOK);
516 		bzero((caddr_t)p, i);
517 		rpc_unixauth = (caddr_t)p;
518 		*p++ = txdr_unsigned(RPCAUTH_UNIX);
519 		p++;	/* Fill in size later */
520 		*p++ = hostid;
521 		*p++ = txdr_unsigned(hostnamelen);
522 		i = nfsm_rndup(hostnamelen);
523 		bcopy(hostname, (caddr_t)p, hostnamelen);
524 		p += (i>>2);
525 		rpc_uidp = p;
526 	}
527 	*p++ = txdr_unsigned(cr->cr_uid);
528 	*p++ = txdr_unsigned(cr->cr_groups[0]);
529 	ngr = (cr->cr_ngroups > 10) ? 10 : cr->cr_ngroups;
530 	*p++ = txdr_unsigned(ngr);
531 	for (i = 0; i < ngr; i++)
532 		*p++ = txdr_unsigned(cr->cr_groups[i]);
533 	/* And add the AUTH_NULL */
534 	*p++ = 0;
535 	*p = 0;
536 	i = (((caddr_t)p)-rpc_unixauth)-12;
537 	p = (u_long *)(rpc_unixauth+4);
538 	*p = txdr_unsigned(i);
539 	return(rpc_unixauth);
540 }
541 
542 /*
543  * Attribute cache routines.
544  * nfs_loadattrcache() - loads or updates the cache contents from attributes
545  *	that are on the mbuf list
546  * nfs_getattrcache() - returns valid attributes if found in cache, returns
547  *	error otherwise
548  */
549 
550 /*
551  * Load the attribute cache (that lives in the nfsnode table) with
552  * the values on the mbuf list and
553  * Iff vap not NULL
554  *    copy the attributes to *vaper
555  */
556 nfs_loadattrcache(vp, mdp, dposp, vaper)
557 	register struct vnode *vp;
558 	struct mbuf **mdp;
559 	caddr_t *dposp;
560 	struct vattr *vaper;
561 {
562 	register struct vattr *vap;
563 	nfsm_vars;
564 	struct nfsnode *np;
565 
566 	md = *mdp;
567 	dpos = *dposp;
568 	t1 = (mtod(md, caddr_t)+md->m_len)-dpos;
569 	if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2))
570 		return (error);
571 	p = (u_long *)cp2;
572 	np = VTONFS(vp);
573 	vap = &np->n_vattr;
574 	vap->va_type = nfstov_type(*p++);
575 	vap->va_mode = nfstov_mode(*p++);
576 	vap->va_nlink = fxdr_unsigned(u_short, *p++);
577 	vap->va_uid = fxdr_unsigned(uid_t, *p++);
578 	vap->va_gid = fxdr_unsigned(gid_t, *p++);
579 	vap->va_size = fxdr_unsigned(u_long, *p++);
580 	vap->va_size1 = 0;		/* OR -1 ?? */
581 	vap->va_blocksize = fxdr_unsigned(long, *p++);
582 	vap->va_rdev = fxdr_unsigned(dev_t, *p++);
583 	vap->va_bytes = fxdr_unsigned(long, *p++);
584 	vap->va_bytes1 = -1;
585 	vap->va_fsid = fxdr_unsigned(long, *p++);
586 	vap->va_fileid = fxdr_unsigned(long, *p++);
587 	fxdr_time(p, &(vap->va_atime));
588 	p += 2;
589 	fxdr_time(p, &(vap->va_mtime));
590 	p += 2;
591 	fxdr_time(p, &(vap->va_ctime));
592 	np->n_attrstamp = time.tv_sec;
593 	*dposp = dpos;
594 	*mdp = md;
595 	if (vaper != NULL)
596 		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
597 	return (0);
598 }
599 
600 /*
601  * Check the time stamp
602  * If the cache is valid, copy contents to *vap and return 0
603  * otherwise return an error
604  */
605 nfs_getattrcache(vp, vap)
606 	register struct vnode *vp;
607 	struct vattr *vap;
608 {
609 	register struct nfsnode *np;
610 
611 	np = VTONFS(vp);
612 	if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) {
613 		nfsstats.attrcache_hits++;
614 		bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr));
615 		return (0);
616 	} else {
617 		nfsstats.attrcache_misses++;
618 		return (ENOENT);
619 	}
620 }
621 
622 #ifndef OPFLAG
623 #define	OPFLAG	(CREATE | DELETE | LOOKUP)
624 #endif
625 
626 /*
627  * nfs_namei - a liitle like namei(), but for one element only
628  *	essentially look up file handle, fill in ndp and call VOP_LOOKUP()
629  */
630 nfs_namei(ndp, fhp, len, mdp, dposp)
631 	register struct nameidata *ndp;
632 	fhandle_t *fhp;
633 	int len;
634 	struct mbuf **mdp;
635 	caddr_t *dposp;
636 {
637 	register int i, rem;
638 	register struct mbuf *md;
639 	register char *cp;
640 	struct vnode *dp = (struct vnode *)0;
641 	struct vnode *tdp;
642 	struct mount *mp;
643 	int flag;
644 	int docache;
645 	int wantparent;
646 	int lockparent;
647 	int rootflg = 0;
648 	int error = 0;
649 
650 	ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
651 	flag = ndp->ni_nameiop & OPFLAG;
652 	wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT);
653 	lockparent = ndp->ni_nameiop & LOCKPARENT;
654 	docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
655 	if (flag == DELETE || wantparent)
656 		docache = 0;
657 
658 	/* Fill in the nameidata and call lookup */
659 	cp = *dposp;
660 	md = *mdp;
661 	rem = mtod(md, caddr_t)+md->m_len-cp;
662 	ndp->ni_hash = 0;
663 	for (i = 0; i < len;) {
664 		if (rem == 0) {
665 			md = md->m_next;
666 			if (md == NULL)
667 				return (EBADRPC);
668 			cp = mtod(md, caddr_t);
669 			rem = md->m_len;
670 		}
671 		if (*cp == '\0' || *cp == '/')
672 			return (EINVAL);
673 		if (*cp & 0200)
674 			if ((*cp&0377) == ('/'|0200) || flag != DELETE)
675 				return (EINVAL);
676 		ndp->ni_dent.d_name[i++] = *cp;
677 		ndp->ni_hash += (unsigned char)*cp * i;
678 		cp++;
679 		rem--;
680 	}
681 	*mdp = md;
682 	len = nfsm_rndup(len)-len;
683 	if (len > 0)
684 		*dposp = cp+len;
685 	else
686 		*dposp = cp;
687 	ndp->ni_namelen = i;
688 	ndp->ni_dent.d_namlen = i;
689 	ndp->ni_dent.d_name[i] = '\0';
690 	ndp->ni_pathlen = 0;
691 	ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0];
692 	ndp->ni_next = &ndp->ni_dent.d_name[i];
693 	ndp->ni_loopcnt = 0;	/* Not actually used for now */
694 	ndp->ni_endoff = 0;
695 	if (docache)
696 		ndp->ni_makeentry = 1;
697 	else
698 		ndp->ni_makeentry = 0;
699 	ndp->ni_isdotdot = (i == 2 &&
700 		ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.');
701 
702 	/*
703 	 * Must remember if this is root so that cr_uid can be set to
704 	 * mp->m_exroot at mount points
705 	 * Then call nfsrv_fhtovp() to get the locked directory vnode
706 	 */
707 	if (ndp->ni_cred->cr_uid == 0)
708 		rootflg++;
709 	if (error = nfsrv_fhtovp(fhp, TRUE, &dp, ndp->ni_cred))
710 		return (error);
711 
712 	/*
713 	 * Handle "..": two special cases.
714 	 * 1. If at root directory (e.g. after chroot)
715 	 *    then ignore it so can't get out.
716 	 * 2. If this vnode is the root of a mounted
717 	 *    file system, then replace it with the
718 	 *    vnode which was mounted on so we take the
719 	 *    .. in the other file system.
720 	 */
721 	if (ndp->ni_isdotdot) {
722 		for (;;) {
723 			if (dp == rootdir) {
724 				ndp->ni_dvp = dp;
725 				dp->v_count++;
726 				goto nextname;
727 			}
728 			if ((dp->v_flag & VROOT) == 0)
729 				break;
730 			tdp = dp;
731 			dp = dp->v_mount->m_vnodecovered;
732 			vput(tdp);
733 			if ((dp->v_mount->m_flag & M_EXPORTED) == 0)
734 				return (EACCES);
735 			VOP_LOCK(dp);
736 			dp->v_count++;
737 			if (rootflg)
738 				ndp->ni_cred->cr_uid = dp->v_mount->m_exroot;
739 		}
740 	}
741 
742 	/*
743 	 * We now have a segment name to search for, and a directory to search.
744 	 */
745 	if (error = VOP_LOOKUP(dp, ndp)) {
746 		if (ndp->ni_vp != NULL)
747 			panic("leaf should be empty");
748 		/*
749 		 * If creating and at end of pathname, then can consider
750 		 * allowing file to be created.
751 		 */
752 		if (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY))
753 			error = EROFS;
754 		if (flag == LOOKUP || flag == DELETE || error != ENOENT)
755 			goto bad;
756 		/*
757 		 * We return with ni_vp NULL to indicate that the entry
758 		 * doesn't currently exist, leaving a pointer to the
759 		 * (possibly locked) directory inode in ndp->ni_dvp.
760 		 */
761 		return (0);	/* should this be ENOENT? */
762 	}
763 
764 	/*
765 	 * Check for symbolic link
766 	 */
767 	dp = ndp->ni_vp;
768 #ifdef notdef
769 	if ((dp->v_type == VLNK) &&
770 	    (ndp->ni_nameiop & FOLLOW)) {
771 		struct iovec aiov;
772 		struct uio auio;
773 		int linklen;
774 
775 		if (++ndp->ni_loopcnt > MAXSYMLINKS) {
776 			error = ELOOP;
777 			goto bad2;
778 		}
779 		MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
780 		aiov.iov_base = cp;
781 		aiov.iov_len = MAXPATHLEN;
782 		auio.uio_iov = &aiov;
783 		auio.uio_iovcnt = 1;
784 		auio.uio_offset = 0;
785 		auio.uio_rw = UIO_READ;
786 		auio.uio_segflg = UIO_SYSSPACE;
787 		auio.uio_resid = MAXPATHLEN;
788 		if (error = VOP_READLINK(dp, &auio, ndp->ni_cred)) {
789 			free(cp, M_NAMEI);
790 			goto bad2;
791 		}
792 		linklen = MAXPATHLEN - auio.uio_resid;
793 		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
794 			free(cp, M_NAMEI);
795 			error = ENAMETOOLONG;
796 			goto bad2;
797 		}
798 		bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
799 		ndp->ni_pnbuf = cp;
800 		} else
801 			ndp->ni_pnbuf[linklen] = '\0';
802 		ndp->ni_ptr = cp;
803 		ndp->ni_pathlen += linklen;
804 		vput(dp);
805 		dp = ndp->ni_dvp;
806 		goto start;
807 	}
808 #endif
809 
810 	/*
811 	 * Check to see if the vnode has been mounted on;
812 	 * if so find the root of the mounted file system.
813 	 * Ignore NFS mount points
814 	 */
815 mntloop:
816 	while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
817 		mp->m_fsid.val[1] != MOUNT_NFS) {
818 		while(mp->m_flag & M_MLOCK) {
819 			mp->m_flag |= M_MWAIT;
820 			sleep((caddr_t)mp, PVFS);
821 			goto mntloop;
822 		}
823 		error = VFS_ROOT(mp, &tdp);
824 		if (error || (mp->m_flag & M_EXPORTED) == 0)
825 			goto bad2;
826 		vput(dp);
827 		ndp->ni_vp = dp = tdp;
828 		if (rootflg)
829 			ndp->ni_cred->cr_uid = mp->m_exroot;
830 	}
831 
832 nextname:
833 	/*
834 	 * Check for read-only file systems.
835 	 */
836 	if (flag == DELETE || flag == RENAME) {
837 		/*
838 		 * Disallow directory write attempts on read-only
839 		 * file systems.
840 		 */
841 		if ((dp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)) ||
842 		    (wantparent && (ndp->ni_dvp->v_mount->m_flag & M_RDONLY))) {
843 			error = EROFS;
844 			goto bad2;
845 		}
846 	}
847 
848 	/*
849 	 * Kludge city... This is hokey, but since ufs_rename() calls
850 	 * namei() and namei() expects ni_cdir to be set, what can I
851 	 * do. Fortunately rename() holds onto the parent so I don't
852 	 * have to increment the v_count.
853 	 */
854 	if (!wantparent)
855 		vrele(ndp->ni_dvp);
856 	else
857 		ndp->ni_cdir = ndp->ni_dvp;
858 
859 	if ((ndp->ni_nameiop & LOCKLEAF) == 0)
860 		VOP_UNLOCK(dp);
861 	return (0);
862 
863 bad2:
864 	if (lockparent)
865 		VOP_UNLOCK(ndp->ni_dvp);
866 	vrele(ndp->ni_dvp);
867 bad:
868 	vput(dp);
869 	ndp->ni_vp = NULL;
870 	return (error);
871 }
872 
873 /*
874  * A fiddled version of m_adj() that ensures null fill to a long
875  * boundary and only trims off the back end
876  */
877 nfsm_adj(mp, len, nul)
878 	struct mbuf *mp;
879 	register int len;
880 	int nul;
881 {
882 	register struct mbuf *m;
883 	register int count, i;
884 	register char *cp;
885 
886 	/*
887 	 * Trim from tail.  Scan the mbuf chain,
888 	 * calculating its length and finding the last mbuf.
889 	 * If the adjustment only affects this mbuf, then just
890 	 * adjust and return.  Otherwise, rescan and truncate
891 	 * after the remaining size.
892 	 */
893 	count = 0;
894 	m = mp;
895 	for (;;) {
896 		count += m->m_len;
897 		if (m->m_next == (struct mbuf *)0)
898 			break;
899 		m = m->m_next;
900 	}
901 	if (m->m_len >= len) {
902 		m->m_len -= len;
903 		if (nul > 0) {
904 			cp = mtod(m, caddr_t)+m->m_len-nul;
905 			for (i = 0; i < nul; i++)
906 				*cp++ = '\0';
907 		}
908 		return;
909 	}
910 	count -= len;
911 	if (count < 0)
912 		count = 0;
913 	/*
914 	 * Correct length for chain is "count".
915 	 * Find the mbuf with last data, adjust its length,
916 	 * and toss data from remaining mbufs on chain.
917 	 */
918 	for (m = mp; m; m = m->m_next) {
919 		if (m->m_len >= count) {
920 			m->m_len = count;
921 			if (nul > 0) {
922 				cp = mtod(m, caddr_t)+m->m_len-nul;
923 				for (i = 0; i < nul; i++)
924 					*cp++ = '\0';
925 			}
926 			break;
927 		}
928 		count -= m->m_len;
929 	}
930 	while (m = m->m_next)
931 		m->m_len = 0;
932 }
933 
934 /*
935  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
936  * 	- look up fsid in mount list (if not found ret error)
937  *	- check that it is exported
938  *	- get vp by calling VFS_FHTOVP() macro
939  *	- if not lockflag unlock it with VOP_UNLOCK()
940  *	- if cred->cr_uid == 0 set it to m_exroot
941  */
942 nfsrv_fhtovp(fhp, lockflag, vpp, cred)
943 	fhandle_t *fhp;
944 	int lockflag;
945 	struct vnode **vpp;
946 	struct ucred *cred;
947 {
948 	register struct mount *mp;
949 	int error;
950 
951 	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
952 		return (ESTALE);
953 	if ((mp->m_flag & M_EXPORTED) == 0)
954 		return (EACCES);
955 	if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
956 		return (ESTALE);
957 	if (cred->cr_uid == 0)
958 		cred->cr_uid = mp->m_exroot;
959 	if (!lockflag)
960 		VOP_UNLOCK(*vpp);
961 	return (0);
962 }
963 
964