xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 38414)
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_vnops.c	7.1 (Berkeley) 07/05/89
21  */
22 
23 /*
24  * vnode op calls for sun nfs version 2
25  */
26 
27 #include "machine/pte.h"
28 #include "machine/mtpr.h"
29 #include "strings.h"
30 #include "param.h"
31 #include "user.h"
32 #include "proc.h"
33 #include "mount.h"
34 #include "buf.h"
35 #include "vm.h"
36 #include "dir.h"
37 #include "malloc.h"
38 #include "mbuf.h"
39 #include "uio.h"
40 #include "ucred.h"
41 #include "namei.h"
42 #include "errno.h"
43 #include "file.h"
44 #include "conf.h"
45 #include "vnode.h"
46 #include "../ufs/inode.h"
47 #include "nfsv2.h"
48 #include "nfs.h"
49 #include "nfsnode.h"
50 #include "nfsmount.h"
51 #include "xdr_subs.h"
52 #include "nfsm_subs.h"
53 
54 /* Defs */
55 #define	TRUE	1
56 #define	FALSE	0
57 
58 /* Global vars */
59 int	nfs_lookup(),
60 	nfs_create(),
61 	nfs_open(),
62 	nfs_close(),
63 	nfs_access(),
64 	nfs_getattr(),
65 	nfs_setattr(),
66 	nfs_read(),
67 	nfs_write(),
68 	vfs_noop(),
69 	vfs_nullop(),
70 	nfs_remove(),
71 	nfs_link(),
72 	nfs_rename(),
73 	nfs_mkdir(),
74 	nfs_rmdir(),
75 	nfs_symlink(),
76 	nfs_readdir(),
77 	nfs_readlink(),
78 	nfs_abortop(),
79 	nfs_lock(),
80 	nfs_unlock(),
81 	nfs_bmap(),
82 	nfs_strategy(),
83 	nfs_inactive();
84 
85 struct vnodeops nfsv2_vnodeops = {
86 	nfs_lookup,
87 	nfs_create,
88 	vfs_noop,
89 	nfs_open,
90 	nfs_close,
91 	nfs_access,
92 	nfs_getattr,
93 	nfs_setattr,
94 	nfs_read,
95 	nfs_write,
96 	vfs_noop,
97 	vfs_noop,
98 	vfs_noop,
99 	vfs_nullop,
100 	vfs_noop,
101 	nfs_remove,
102 	nfs_link,
103 	nfs_rename,
104 	nfs_mkdir,
105 	nfs_rmdir,
106 	nfs_symlink,
107 	nfs_readdir,
108 	nfs_readlink,
109 	nfs_abortop,
110 	nfs_inactive,
111 	nfs_lock,
112 	nfs_unlock,
113 	nfs_bmap,
114 	nfs_strategy,
115 };
116 
117 /* Special device vnode ops */
118 int	blk_open(),
119 	blk_read(),
120 	blk_write(),
121 	blk_ioctl(),
122 	blk_select(),
123 	ufs_bmap(),
124 	blk_strategy();
125 
126 struct vnodeops nfsv2chr_vnodeops = {
127 	vfs_noop,
128 	vfs_noop,
129 	vfs_noop,
130 	blk_open,
131 	nfs_close,
132 	nfs_access,
133 	nfs_getattr,
134 	nfs_setattr,
135 	blk_read,
136 	blk_write,
137 	blk_ioctl,
138 	blk_select,
139 	vfs_noop,
140 	vfs_nullop,
141 	vfs_noop,
142 	nfs_remove,
143 	nfs_link,
144 	nfs_rename,
145 	vfs_noop,
146 	vfs_noop,
147 	nfs_symlink,
148 	vfs_noop,
149 	vfs_noop,
150 	nfs_abortop,
151 	nfs_inactive,
152 	nfs_lock,
153 	nfs_unlock,
154 	ufs_bmap,
155 	blk_strategy,
156 };
157 
158 extern u_long nfs_procids[NFS_NPROCS];
159 extern u_long nfs_prog, nfs_vers;
160 extern struct vnode *cache_lookup();
161 extern char nfsiobuf[MAXPHYS+NBPG];
162 enum vtype v_type[NFLNK+1];
163 
164 /*
165  * nfs null call from vfs.
166  */
167 nfs_null(vp, cred)
168 	struct vnode *vp;
169 	struct ucred *cred;
170 {
171 	nfsm_vars;
172 
173 	nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0);
174 	nfsm_request(vp);
175 	nfsm_reqdone;
176 	return (error);
177 }
178 
179 /*
180  * nfs access vnode op.
181  * Essentially just get vattr and then imitate iaccess()
182  */
183 nfs_access(vp, mode, cred)
184 	struct vnode *vp;
185 	int mode;
186 	register struct ucred *cred;
187 {
188 	register struct vattr *vap;
189 	register gid_t *gp;
190 	struct vattr vattr;
191 	register int i;
192 	int error;
193 
194 	/*
195 	 * If you're the super-user,
196 	 * you always get access.
197 	 */
198 	if (cred->cr_uid == 0)
199 		return (0);
200 	vap = &vattr;
201 	if (nfs_getattrcache(vp, vap)) {
202 		if (error = nfs_getattr(vp, vap, cred))
203 			return (error);
204 	}
205 	/*
206 	 * Access check is based on only one of owner, group, public.
207 	 * If not owner, then check group. If not a member of the
208 	 * group, then check public access.
209 	 */
210 	if (cred->cr_uid != vap->va_uid) {
211 		mode >>= 3;
212 		gp = cred->cr_groups;
213 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
214 			if (vap->va_gid == *gp)
215 				goto found;
216 		mode >>= 3;
217 found:
218 		;
219 	}
220 	if ((vap->va_mode & mode) != 0)
221 		return (0);
222 	return (EACCES);
223 }
224 
225 /*
226  * nfs open vnode op
227  * Just check to see if the type is ok
228  */
229 nfs_open(vp, mode, cred)
230 	struct vnode *vp;
231 	int mode;
232 	struct ucred *cred;
233 {
234 	register enum vtype vtyp;
235 
236 	vtyp = vp->v_type;
237 	if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK)
238 		return (0);
239 	else
240 		return (EACCES);
241 }
242 
243 /*
244  * nfs close vnode op
245  * Nothin to do unless its a VCHR
246  */
247 nfs_close(vp, fflags, cred)
248 	register struct vnode *vp;
249 	int fflags;
250 	struct ucred *cred;
251 {
252 	dev_t dev;
253 	int error;
254 
255 	if (vp->v_type != VCHR || vp->v_count > 1)
256 		return (0);
257 	dev = vp->v_rdev;
258 	/* XXX what is this doing below the vnode op call */
259 	if (setjmp(&u.u_qsave)) {
260 		/*
261 		 * If device close routine is interrupted,
262 		 * must return so closef can clean up.
263 		 */
264 		error = EINTR;
265 	} else
266 		error = (*cdevsw[major(dev)].d_close)(dev, fflags, IFCHR);
267 	/*
268 	 * Most device close routines don't return errors,
269 	 * and dup2() doesn't work right on error.
270 	 */
271 	error = 0;		/* XXX */
272 	return (error);
273 }
274 
275 /*
276  * nfs getattr call from vfs.
277  */
278 nfs_getattr(vp, vap, cred)
279 	struct vnode *vp;
280 	register struct vattr *vap;
281 	struct ucred *cred;
282 {
283 	nfsm_vars;
284 
285 	/* First look in the cache.. */
286 	if (nfs_getattrcache(vp, vap) == 0)
287 		return (0);
288 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
289 	nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH);
290 	nfsm_fhtom(vp);
291 	nfsm_request(vp);
292 	nfsm_loadattr(vp, vap);
293 	nfsm_reqdone;
294 	return (error);
295 }
296 
297 /*
298  * nfs setattr call.
299  */
300 nfs_setattr(vp, vap, cred)
301 	struct vnode *vp;
302 	register struct vattr *vap;
303 	struct ucred *cred;
304 {
305 	nfsm_vars;
306 
307 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
308 	nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR);
309 	nfsm_fhtom(vp);
310 	nfsm_build(p, u_long *, NFSX_SATTR);
311 	if (vap->va_mode == 0xffff)
312 		*p++ = VNOVAL;
313 	else
314 		*p++ = vtonfs_mode(vp->v_type, vap->va_mode);
315 	if (vap->va_uid == 0xffff)
316 		*p++ = VNOVAL;
317 	else
318 		*p++ = txdr_unsigned(vap->va_uid);
319 	if (vap->va_gid == 0xffff)
320 		*p++ = VNOVAL;
321 	else
322 		*p++ = txdr_unsigned(vap->va_gid);
323 	*p++ = txdr_unsigned(vap->va_size);
324 	txdr_time(&(vap->va_atime), p);
325 	p += 2;
326 	txdr_time(&(vap->va_mtime), p);
327 	nfsm_request(vp);
328 	nfsm_loadattr(vp, (struct vattr *)0);
329 	/* should we fill in any vap fields ?? */
330 	nfsm_reqdone;
331 	return (error);
332 }
333 
334 /*
335  * nfs lookup call, one step at a time...
336  * First look in cache
337  * If not found, unlock the directory nfsnode and do the rpc
338  */
339 nfs_lookup(vp, ndp)
340 	register struct vnode *vp;
341 	register struct nameidata *ndp;
342 {
343 	register struct vnode *vdp;
344 	nfsm_vars;
345 	struct vnode *newvp;
346 	long len;
347 	nfsv2fh_t *fhp;
348 	struct nfsnode *np;
349 	int lockparent, wantparent, flag;
350 	dev_t rdev;
351 
352 	ndp->ni_dvp = vp;
353 	ndp->ni_vp = NULL;
354 	if (vp->v_type != VDIR)
355 		return (ENOTDIR);
356 	lockparent = ndp->ni_nameiop & LOCKPARENT;
357 	flag = ndp->ni_nameiop & OPFLAG;
358 	wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
359 #ifdef notyet
360 	if (vdp = cache_lookup(ndp)) {
361 		nfsstats.lookupcache_hits++;
362 		/*
363 		 * Get the next vnode in the path.
364 		 * See comment above `IUNLOCK' code for
365 		 * an explaination of the locking protocol.
366 		 */
367 		if (vp == vdp) {
368 			vdp->v_count++;
369 		} else if (ndp->ni_isdotdot) {
370 			nfs_unlock(vp);
371 			nfs_ngrab(VTONFS(vdp));
372 		} else {
373 			nfs_ngrab(VTONFS(vdp));
374 			nfs_unlock(vp);
375 		}
376 		ndp->ni_vp = vdp;
377 		return (0);
378 	}
379 	nfsstats.lookupcache_misses++;
380 #endif notyet
381 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
382 	len = ndp->ni_namelen;
383 	nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
384 	nfsm_fhtom(vp);
385 	nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
386 	nfsm_request(vp);
387 nfsmout:
388 	if (error) {
389 		if ((flag == CREATE || flag == RENAME) &&
390 			*ndp->ni_next == 0) {
391 			if (!lockparent)
392 				nfs_unlock(vp);
393 		}
394 		return (ENOENT);
395 	}
396 	nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH);
397 
398 	/*
399 	 * Handle DELETE and RENAME cases...
400 	 */
401 	if (flag == DELETE && *ndp->ni_next == 0) {
402 		if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
403 			vp->v_count++;
404 			newvp = vp;
405 			np = VTONFS(vp);
406 		} else {
407 			if (error = nfs_nget(vp->v_mount, fhp, &np)) {
408 				m_freem(mrep);
409 				return (error);
410 			}
411 			newvp = NFSTOV(np);
412 		}
413 		if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) {
414 			if (newvp != vp)
415 				nfs_nput(newvp);
416 			else
417 				vp->v_count--;
418 			m_freem(mrep);
419 			return (error);
420 		}
421 		newvp->v_type = np->n_vattr.va_type;
422 		ndp->ni_vp = newvp;
423 		if (!lockparent)
424 			nfs_unlock(vp);
425 		m_freem(mrep);
426 		return (0);
427 	}
428 
429 	if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
430 		if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
431 			m_freem(mrep);
432 			return (EISDIR);
433 		}
434 		if (error = nfs_nget(vp->v_mount, fhp, &np)) {
435 			m_freem(mrep);
436 			return (error);
437 		}
438 		newvp = NFSTOV(np);
439 		if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) {
440 			if (newvp != vp)
441 				nfs_nput(newvp);
442 			else
443 				vp->v_count--;
444 			m_freem(mrep);
445 			return (error);
446 		}
447 		ndp->ni_vp = newvp;
448 		if (!lockparent)
449 			nfs_unlock(vp);
450 		return (0);
451 	}
452 
453 	if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
454 		vp->v_count++;
455 		newvp = vp;
456 		np = VTONFS(vp);
457 	} else if (ndp->ni_isdotdot) {
458 		nfs_unlock(vp);
459 		if (error = nfs_nget(vp->v_mount, fhp, &np)) {
460 			nfs_lock(vp);
461 			m_freem(mrep);
462 			return (error);
463 		}
464 		nfs_lock(vp);
465 		newvp = NFSTOV(np);
466 	} else {
467 		if (error = nfs_nget(vp->v_mount, fhp, &np)) {
468 			m_freem(mrep);
469 			return (error);
470 		}
471 		newvp = NFSTOV(np);
472 	}
473 	if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) {
474 		if (newvp != vp)
475 			nfs_nput(newvp);
476 		else
477 			vp->v_count--;
478 		m_freem(mrep);
479 		return (error);
480 	}
481 	m_freem(mrep);
482 	newvp->v_type = np->n_vattr.va_type;
483 
484 	/*
485 	 * Handling special files...
486 	 * For VCHR, use the nfs_node, but with the nfsv2chr_vnodeops
487 	 * that are a mix of nfs and blk vnode ops.
488 	 * For VBLK, get a block dev. inode using bdevvp() and release
489 	 * the nfs_node. This means that ufs_inactive() had better know
490 	 * how to release inodes that do not have an underlying ufs.
491 	 * (i_fs == 0)
492 	 * Also, returns right away to avoid loading the name cache
493 	 */
494 	if (newvp->v_type == VCHR) {
495 		newvp->v_rdev = np->n_vattr.va_rdev;
496 		newvp->v_op = &nfsv2chr_vnodeops;
497 	} else if (newvp->v_type == VBLK) {
498 		rdev = np->n_vattr.va_rdev;
499 		nfs_nput(newvp);
500 		if (error = bdevvp(rdev, &newvp))
501 			return (error);
502 	}
503 	if (vp != newvp && (!lockparent || *ndp->ni_next != '\0'))
504 		nfs_unlock(vp);
505 	ndp->ni_vp = newvp;
506 #ifdef notyet
507 	if (error == 0 && ndp->ni_makeentry)
508 		cache_enter(ndp);
509 #endif notyet
510 	return (error);
511 }
512 
513 /*
514  * nfs readlink call
515  */
516 nfs_readlink(vp, uiop, cred)
517 	struct vnode *vp;
518 	struct uio *uiop;
519 	struct ucred *cred;
520 {
521 	nfsm_vars;
522 	long len;
523 
524 	nfsstats.rpccnt[NFSPROC_READLINK]++;
525 	nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH);
526 	nfsm_fhtom(vp);
527 	nfsm_request(vp);
528 	nfsm_strsiz(len, NFS_MAXPATHLEN);
529 	nfsm_mtouio(uiop, len);
530 	nfsm_reqdone;
531 	return (error);
532 }
533 
534 /*
535  * nfs read call
536  */
537 nfs_read(vp, uiop, offp, ioflag, cred)
538 	struct vnode *vp;
539 	struct uio *uiop;
540 	off_t *offp;
541 	int ioflag;
542 	struct ucred *cred;
543 {
544 	nfsm_vars;
545 	struct nfsmount *nmp;
546 	long len, retlen, tsiz;
547 
548 	nmp = vfs_to_nfs(vp->v_mount);
549 	tsiz = uiop->uio_resid;
550 	if (!(ioflag & IO_NODELOCKED))
551 		nfs_lock(vp);
552 	while (tsiz > 0) {
553 		nfsstats.rpccnt[NFSPROC_READ]++;
554 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
555 		nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3);
556 		nfsm_fhtom(vp);
557 		nfsm_build(p, u_long *, NFSX_UNSIGNED*3);
558 		*p++ = txdr_unsigned(*offp);
559 		*p++ = txdr_unsigned(len);
560 		*p = 0;
561 		nfsm_request(vp);
562 		nfsm_loadattr(vp, (struct vattr *)0);
563 		nfsm_strsiz(retlen, nmp->nm_rsize);
564 		nfsm_mtouio(uiop, retlen);
565 		m_freem(mrep);
566 		*offp += retlen;
567 		if (retlen < len)
568 			tsiz = 0;
569 		else
570 			tsiz -= len;
571 	}
572 nfsmout:
573 	if (!(ioflag & IO_NODELOCKED))
574 		nfs_unlock(vp);
575 	return (error);
576 }
577 
578 /*
579  * nfs write call
580  */
581 nfs_write(vp, uiop, offp, ioflag, cred)
582 	struct vnode *vp;
583 	struct uio *uiop;
584 	off_t *offp;
585 	int ioflag;
586 	struct ucred *cred;
587 {
588 	nfsm_vars;
589 	struct nfsmount *nmp;
590 	long len, tsiz;
591 	u_long osize;
592 	off_t ooff;
593 	struct vattr va;
594 
595 	nmp = vfs_to_nfs(vp->v_mount);
596 	tsiz = uiop->uio_resid;
597 	if (!(ioflag & IO_NODELOCKED))
598 		nfs_lock(vp);
599 	if ((ioflag&IO_UNIT) || (vp->v_type == VREG && (ioflag&IO_APPEND))) {
600 		if (error = nfs_getattr(vp, &va, cred))
601 			goto nfsmout;
602 		osize = va.va_size;
603 		if (vp->v_type == VREG && (ioflag & IO_APPEND))
604 			*offp = osize;
605 		ooff = *offp;
606 	}
607 	while (tsiz > 0) {
608 		nfsstats.rpccnt[NFSPROC_WRITE]++;
609 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
610 		nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred,
611 			NFSX_FH+NFSX_UNSIGNED*4);
612 		nfsm_fhtom(vp);
613 		nfsm_build(p, u_long *, NFSX_UNSIGNED*4);
614 		*(p+1) = txdr_unsigned(*offp);
615 		*(p+3) = txdr_unsigned(len);
616 		nfsm_uiotom(uiop, len);
617 		nfsm_request(vp);
618 		nfsm_loadattr(vp, (struct vattr *)0);
619 		m_freem(mrep);
620 		tsiz -= len;
621 		*offp += len;
622 	}
623 nfsmout:
624 	if (error && (ioflag & IO_UNIT)) {
625 		vattr_null(&va);
626 		va.va_size = osize;
627 		nfs_setattr(vp, &va, cred);
628 		*offp = ooff;
629 	}
630 	if (!(ioflag & IO_NODELOCKED))
631 		nfs_unlock(vp);
632 	return (error);
633 }
634 
635 /*
636  * nfs file create call
637  */
638 nfs_create(ndp, vap)
639 	register struct nameidata *ndp;
640 	register struct vattr *vap;
641 {
642 	nfsm_vars;
643 
644 	nfsstats.rpccnt[NFSPROC_CREATE]++;
645 	nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
646 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR);
647 	nfsm_fhtom(ndp->ni_dvp);
648 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
649 	nfsm_build(p, u_long *, NFSX_UNSIGNED*8);
650 	*p++ = vtonfs_mode(VREG, vap->va_mode);
651 	*p++ = txdr_unsigned(ndp->ni_cred->cr_uid);
652 	*p++ = txdr_unsigned(ndp->ni_cred->cr_gid);
653 	*p++ = txdr_unsigned(0);
654 	/* or should these be VNOVAL ?? */
655 	txdr_time(&(vap->va_atime), p);
656 	txdr_time(&(vap->va_mtime), p+2);
657 	nfsm_request(ndp->ni_dvp);
658 	nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
659 	nfsm_reqdone;
660 	nfs_nput(ndp->ni_dvp);
661 	return (error);
662 }
663 
664 /*
665  * nfs file remove call
666  */
667 nfs_remove(ndp)
668 	register struct nameidata *ndp;
669 {
670 	nfsm_vars;
671 
672 	if (ndp->ni_vp->v_count > 1)
673 		error = nfs_sillyrename(ndp, REMOVE);
674 	else {
675 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
676 		nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
677 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
678 		nfsm_fhtom(ndp->ni_dvp);
679 		nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
680 		nfsm_request(ndp->ni_dvp);
681 		nfsm_reqdone;
682 	}
683 	if (ndp->ni_dvp == ndp->ni_vp)
684 		vrele(ndp->ni_dvp);
685 	else
686 		nfs_nput(ndp->ni_dvp);
687 	nfs_nput(ndp->ni_vp);
688 	return (error);
689 }
690 
691 /*
692  * nfs file remove rpc called from nfs_inactive
693  */
694 nfs_removeit(ndp)
695 	register struct nameidata *ndp;
696 {
697 	nfsm_vars;
698 
699 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
700 	nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
701 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
702 	nfsm_fhtom(ndp->ni_dvp);
703 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
704 	nfsm_request(ndp->ni_dvp);
705 	nfsm_reqdone;
706 	return (error);
707 }
708 
709 /*
710  * nfs file rename call
711  */
712 nfs_rename(sndp, tndp)
713 	register struct nameidata *sndp, *tndp;
714 {
715 	nfsm_vars;
716 
717 	nfsstats.rpccnt[NFSPROC_RENAME]++;
718 	nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
719 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+
720 		nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/
721 	nfsm_fhtom(sndp->ni_dvp);
722 	nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
723 	nfsm_fhtom(tndp->ni_dvp);
724 	nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
725 	nfsm_request(sndp->ni_dvp);
726 	nfsm_reqdone;
727 #ifdef notyet
728 	if (sndp->ni_vp->v_type == VDIR) {
729 		if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
730 			cache_purge(tndp->ni_dvp);
731 		cache_purge(sndp->ni_dvp);
732 	}
733 #endif
734 	nfs_abortop(sndp);
735 	nfs_abortop(tndp);
736 	return (error);
737 }
738 
739 /*
740  * nfs file rename rpc called from above
741  */
742 nfs_renameit(sndp, tndp)
743 	register struct nameidata *sndp, *tndp;
744 {
745 	nfsm_vars;
746 
747 	nfsstats.rpccnt[NFSPROC_RENAME]++;
748 	nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
749 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+
750 		nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/
751 	nfsm_fhtom(sndp->ni_dvp);
752 	nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
753 	nfsm_fhtom(tndp->ni_dvp);
754 	nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
755 	nfsm_request(sndp->ni_dvp);
756 	nfsm_reqdone;
757 	return (error);
758 }
759 
760 /*
761  * nfs hard link create call
762  */
763 nfs_link(vp, ndp)
764 	struct vnode *vp;
765 	register struct nameidata *ndp;
766 {
767 	nfsm_vars;
768 
769 	nfsstats.rpccnt[NFSPROC_LINK]++;
770 	nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred,
771 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
772 	nfsm_fhtom(vp);
773 	nfsm_fhtom(ndp->ni_dvp);
774 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
775 	nfsm_request(vp);
776 	nfsm_reqdone;
777 	nfs_nput(ndp->ni_dvp);
778 	return (error);
779 }
780 
781 /*
782  * nfs symbolic link create call
783  */
784 nfs_symlink(ndp, vap, nm)
785 	struct nameidata *ndp;
786 	struct vattr *vap;
787 	char *nm;		/* is this the path ?? */
788 {
789 	nfsm_vars;
790 
791 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
792 	nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred,
793 	NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED);
794 	nfsm_fhtom(ndp->ni_dvp);
795 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
796 	nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN);
797 	nfsm_build(p, u_long *, NFSX_SATTR);
798 	*p++ = vtonfs_mode(VLNK, vap->va_mode);
799 	*p++ = txdr_unsigned(ndp->ni_cred->cr_uid);
800 	*p++ = txdr_unsigned(ndp->ni_cred->cr_gid);
801 	*p++ = txdr_unsigned(VNOVAL);
802 	txdr_time(&(vap->va_atime), p);		/* or VNOVAL ?? */
803 	txdr_time(&(vap->va_mtime), p+2);	/* or VNOVAL ?? */
804 	nfsm_request(ndp->ni_dvp);
805 	nfsm_reqdone;
806 	nfs_nput(ndp->ni_dvp);
807 	return (error);
808 }
809 
810 /*
811  * nfs make dir call
812  */
813 nfs_mkdir(ndp, vap)
814 	struct nameidata *ndp;
815 	struct vattr *vap;
816 {
817 	nfsm_vars;
818 
819 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
820 	nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred,
821 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR);
822 	nfsm_fhtom(ndp->ni_dvp);
823 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
824 	nfsm_build(p, u_long *, NFSX_SATTR);
825 	*p++ = vtonfs_mode(VDIR, vap->va_mode);
826 	*p++ = txdr_unsigned(ndp->ni_cred->cr_uid);
827 	*p++ = txdr_unsigned(ndp->ni_cred->cr_gid);
828 	*p++ = txdr_unsigned(VNOVAL);
829 	txdr_time(&(vap->va_atime), p);		/* or VNOVAL ?? */
830 	txdr_time(&(vap->va_mtime), p+2);	/* or VNOVAL ?? */
831 	nfsm_request(ndp->ni_dvp);
832 	nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
833 	nfsm_reqdone;
834 	if (error)
835 		nfs_nput(ndp->ni_vp);
836 	nfs_nput(ndp->ni_dvp);
837 	return (error);
838 }
839 
840 /*
841  * nfs remove directory call
842  */
843 nfs_rmdir(ndp)
844 	register struct nameidata *ndp;
845 {
846 	nfsm_vars;
847 
848 	if (ndp->ni_dvp == ndp->ni_vp) {
849 		vrele(ndp->ni_dvp);
850 		nfs_nput(ndp->ni_dvp);
851 		return (EINVAL);
852 	}
853 	if (ndp->ni_vp->v_count > 1)
854 		error = nfs_sillyrename(ndp, RMDIR);
855 	else {
856 		nfsstats.rpccnt[NFSPROC_RMDIR]++;
857 		nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred,
858 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
859 		nfsm_fhtom(ndp->ni_dvp);
860 		nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
861 		nfsm_request(ndp->ni_dvp);
862 		nfsm_reqdone;
863 	}
864 #ifdef notyet
865 	cache_purge(ndp->ni_dvp);
866 	cache_purge(ndp->ni_vp);
867 #endif
868 	nfs_nput(ndp->ni_vp);
869 	nfs_nput(ndp->ni_dvp);
870 	return (error);
871 }
872 
873 /*
874  * nfs remove dir rpc called from above
875  */
876 nfs_rmdirit(ndp)
877 	register struct nameidata *ndp;
878 {
879 	nfsm_vars;
880 
881 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
882 	nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred,
883 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
884 	nfsm_fhtom(ndp->ni_dvp);
885 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
886 	nfsm_request(ndp->ni_dvp);
887 	nfsm_reqdone;
888 	return (error);
889 }
890 
891 /*
892  * nfs readdir call
893  * Although cookie is defined as opaque, I translate it to/from net byte
894  * order so that it looks more sensible. This appears consistent with the
895  * Ultrix implementation of NFS.
896  */
897 nfs_readdir(vp, uiop, offp, cred)
898 	struct vnode *vp;
899 	struct uio *uiop;
900 	off_t *offp;
901 	struct ucred *cred;
902 {
903 	register long len;
904 	register struct direct *dp;
905 	nfsm_vars;
906 	struct mbuf *md2;
907 	caddr_t dpos2;
908 	int siz;
909 	int more_dirs, eofflg;
910 	off_t off, savoff;
911 	struct direct *savdp;
912 
913 	nfs_lock(vp);
914 	nfsstats.rpccnt[NFSPROC_READDIR]++;
915 	nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
916 	nfsm_fhtom(vp);
917 	nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
918 	off = *offp;
919 	*p++ = txdr_unsigned(off);
920 	*p = txdr_unsigned(uiop->uio_resid);
921 	nfsm_request(vp);
922 	siz = 0;
923 	nfsm_disect(p, u_long *, NFSX_UNSIGNED);
924 	more_dirs = fxdr_unsigned(int, *p);
925 
926 	/* Save the position so that we can do nfsm_mtouio() later */
927 	dpos2 = dpos;
928 	md2 = md;
929 
930 	/* loop thru the dir entries, doctoring them to 4bsd form */
931 	while (more_dirs && siz < uiop->uio_resid) {
932 		savoff = off;		/* Hold onto offset and dp */
933 		savdp = dp;
934 		nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
935 		dp = (struct direct *)p;
936 		dp->d_ino = fxdr_unsigned(u_long, *p++);
937 		len = fxdr_unsigned(int, *p);
938 		if (len <= 0 || len > NFS_MAXNAMLEN) {
939 			error = EBADRPC;
940 			m_freem(mrep);
941 			goto nfsmout;
942 		}
943 		dp->d_namlen = (u_short)len;
944 		len = nfsm_rndup(len);
945 		nfsm_adv(len);
946 		nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
947 		off = fxdr_unsigned(off_t, *p);
948 		*p++ = 0;		/* Ensures null termination of name */
949 		more_dirs = fxdr_unsigned(int, *p);
950 		dp->d_reclen = len+4*NFSX_UNSIGNED;
951 		siz += dp->d_reclen;
952 	}
953 	/*
954 	 * If at end of rpc data, get the eof boolean
955 	 */
956 	if (!more_dirs) {
957 		nfsm_disecton(p, u_long *, NFSX_UNSIGNED);
958 		eofflg = fxdr_unsigned(long, *p);
959 	}
960 	/*
961 	 * If there is too much to fit in the data buffer, use savoff and
962 	 * savdp to trim off the last record.
963 	 * --> we are not at eof
964 	 */
965 	if (siz > uiop->uio_resid) {
966 		eofflg = FALSE;
967 		off = savoff;
968 		siz -= dp->d_reclen;
969 		dp = savdp;
970 	}
971 	if (siz > 0) {
972 #ifdef notdef
973 		if (!eofflg)
974 			dp->d_reclen += (uiop->uio_resid-siz);
975 #endif
976 		md = md2;
977 		dpos = dpos2;
978 		nfsm_mtouio(uiop, siz);
979 #ifdef notdef
980 		if (!eofflg)
981 			uiop->uio_resid = 0;
982 #endif
983 		*offp = off;
984 	}
985 	nfsm_reqdone;
986 	nfs_unlock(vp);
987 	return (error);
988 }
989 
990 /*
991  * nfs statfs call
992  * (Actually a vfsop, not a vnode op)
993  */
994 nfs_statfs(mp, sbp)
995 	struct mount *mp;
996 	register struct statfs *sbp;
997 {
998 	register struct nfsmount *nmp;
999 	nfsm_vars;
1000 	struct ucred *cred;
1001 	struct nfsnode *np;
1002 	struct vnode *vp;
1003 
1004 	nmp = vfs_to_nfs(mp);
1005 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
1006 		return (error);
1007 	vp = NFSTOV(np);
1008 	nfsstats.rpccnt[NFSPROC_STATFS]++;
1009 	cred = crget();
1010 	cred->cr_ngroups = 1;
1011 	nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
1012 	nfsm_fhtom(vp);
1013 	nfsm_request(vp);
1014 	nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED);
1015 	sbp->f_type = MOUNT_NFS;
1016 	sbp->f_flags = nmp->nm_flag;
1017 	sbp->f_bsize = fxdr_unsigned(long, *p++);
1018 	sbp->f_fsize = fxdr_unsigned(long, *p++);
1019 	sbp->f_blocks = fxdr_unsigned(long, *p++);
1020 	sbp->f_bfree = fxdr_unsigned(long, *p++);
1021 	sbp->f_bavail = fxdr_unsigned(long, *p);
1022 	sbp->f_files = 0x7fffffff;
1023 	sbp->f_ffree = 0x7fffffff;
1024 	sbp->f_fsid.val[0] = mp->m_fsid.val[0];
1025 	sbp->f_fsid.val[1] = mp->m_fsid.val[1];
1026 	bcopy(nmp->nm_path, sbp->f_mntonname, MNAMELEN);
1027 	bcopy(nmp->nm_host, sbp->f_mntfromname, MNAMELEN);
1028 	nfsm_reqdone;
1029 	nfs_nput(vp);
1030 	crfree(cred);
1031 	return (error);
1032 }
1033 
1034 #define	HEXTOASC(x)	"0123456789abcdef"[x]
1035 
1036 /*
1037  * Silly rename. To make the NFS filesystem that is stateless look a little
1038  * more like the "ufs" a remove of an active vnode is translated to a rename
1039  * to a funny looking filename that is removed by nfs_inactive on the
1040  * nfsnode. There is the potential for another process on a different client
1041  * to create the same funny name between the nfs_lookitup() fails and the
1042  * nfs_rename() completes, but...
1043  */
1044 nfs_sillyrename(ndp, flag)
1045 	struct nameidata *ndp;
1046 	int flag;
1047 {
1048 	register struct nfsnode *np;
1049 	register struct sillyrename *sp;
1050 	register struct nameidata *tndp;
1051 	int error;
1052 	short pid;
1053 
1054 	np = VTONFS(ndp->ni_dvp);
1055 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
1056 		M_WAITOK, M_TEMP);
1057 	sp->s_flag = flag;
1058 	bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH);
1059 	np = VTONFS(ndp->ni_vp);
1060 	tndp = &sp->s_namei;
1061 	tndp->ni_cred = crdup(ndp->ni_cred);
1062 
1063 	/* Fudge together a funny name */
1064 	pid = u.u_procp->p_pid;
1065 	bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13);
1066 	tndp->ni_dent.d_namlen = 12;
1067 	tndp->ni_dent.d_name[8] = HEXTOASC(pid & 0xf);
1068 	tndp->ni_dent.d_name[7] = HEXTOASC((pid >> 4) & 0xf);
1069 	tndp->ni_dent.d_name[6] = HEXTOASC((pid >> 8) & 0xf);
1070 	tndp->ni_dent.d_name[5] = HEXTOASC((pid >> 12) & 0xf);
1071 
1072 	/* Try lookitups until we get one that isn't there */
1073 	while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) {
1074 		tndp->ni_dent.d_name[4]++;
1075 		if (tndp->ni_dent.d_name[4] > 'z') {
1076 			error = EINVAL;
1077 			goto bad;
1078 		}
1079 	}
1080 	if (error = nfs_renameit(ndp, tndp))
1081 		goto bad;
1082 	nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh);
1083 	np->n_sillyrename = sp;
1084 	return (0);
1085 bad:
1086 	crfree(ndp->ni_cred);
1087 	free((caddr_t)sp, M_TEMP);
1088 	return (error);
1089 }
1090 
1091 /*
1092  * Look up a file name for silly rename stuff.
1093  * Just like nfs_lookup() except that it doesn't load returned values
1094  * into the nfsnode table.
1095  * If fhp != NULL it copies the returned file handle out
1096  */
1097 nfs_lookitup(vp, ndp, fhp)
1098 	register struct vnode *vp;
1099 	register struct nameidata *ndp;
1100 	nfsv2fh_t *fhp;
1101 {
1102 	nfsm_vars;
1103 	long len;
1104 
1105 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1106 	ndp->ni_dvp = vp;
1107 	ndp->ni_vp = NULL;
1108 	len = ndp->ni_dent.d_namlen;
1109 	nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
1110 	nfsm_fhtom(vp);
1111 	nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN);
1112 	nfsm_request(vp);
1113 	if (fhp != NULL) {
1114 		nfsm_disect(cp, caddr_t, NFSX_FH);
1115 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
1116 	}
1117 	nfsm_reqdone;
1118 	return (error);
1119 }
1120 
1121 /*
1122  * Kludge City..
1123  * - make nfs_bmap() essentially a no-op that does no translation
1124  * - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit
1125  *   after mapping the physical addresses into Kernel Virtual space in the
1126  *   nfsiobuf area.
1127  *   (Maybe I could use the process's page mapping, but I was concerned that
1128  *    Kernel Write might not be enabled and also figured copyout() would do
1129  *    a lot more work than bcopy() and also it currently happens in the
1130  *    context of the swapper process (2).
1131  */
1132 nfs_bmap(vp, bn, vpp, bnp)
1133 	struct vnode *vp;
1134 	daddr_t bn;
1135 	struct vnode **vpp;
1136 	daddr_t *bnp;
1137 {
1138 	if (vpp != NULL)
1139 		*vpp = vp;
1140 	if (bnp != NULL)
1141 		*bnp = bn * btodb(vp->v_mount->m_bsize);
1142 	return (0);
1143 }
1144 
1145 /*
1146  * Fun and games with phys i/o
1147  */
1148 nfs_strategy(bp)
1149 	register struct buf *bp;
1150 {
1151 	register struct pte *pte, *ppte;
1152 	register caddr_t vaddr;
1153 	register struct uio *uiop;
1154 	register struct ucred *cr;
1155 	register struct vnode *vp;
1156 	int npf;
1157 	unsigned v;
1158 	struct proc *rp;
1159 	int o, error;
1160 	off_t off;
1161 	struct uio uio;
1162 	struct iovec io;
1163 
1164 	vp = bp->b_vp;
1165 	cr = crget();
1166 	cr->cr_gid = 10;	/* Pick anything ?? */
1167 	cr->cr_ngroups = 1;
1168 	uiop = &uio;
1169 	uiop->uio_iov = &io;
1170 	uiop->uio_iovcnt = 1;
1171 	io.iov_len = uiop->uio_resid = bp->b_bcount;
1172 	uiop->uio_segflg = UIO_SYSSPACE;
1173 	uiop->uio_offset = off = bp->b_blkno*DEV_BSIZE;
1174 	o = (int)bp->b_un.b_addr & PGOFSET;
1175 	npf = btoc(bp->b_bcount + o);
1176 	rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc;
1177 	cr->cr_uid = rp->p_uid;
1178 	if ((bp->b_flags & B_PHYS) == 0)
1179 		panic("nfs strategy Not PHYS IO");
1180 	if (bp->b_flags & B_PAGET)
1181 		pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
1182 	else {
1183 		v = btop(bp->b_un.b_addr);
1184 		if (bp->b_flags & B_UAREA)
1185 			pte = &rp->p_addr[v];
1186 		else
1187 			pte = vtopte(rp, v);
1188 	}
1189 	/*
1190 	 * Play vmaccess() but with the Nfsiomap page table
1191 	 */
1192 	ppte = &Nfsiomap[0];
1193 	vaddr = nfsiobuf;
1194 	while (npf != 0) {
1195 		mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW));
1196 #if defined(tahoe)
1197 		mtpr(P1DC, vaddr);
1198 #endif
1199 		ppte++;
1200 		pte++;
1201 		vaddr += NBPG;
1202 		--npf;
1203 	}
1204 	io.iov_base = nfsiobuf+o;
1205 	if (bp->b_flags & B_READ) {
1206 		uiop->uio_rw = UIO_READ;
1207 		bp->b_error = error = nfs_read(vp, uiop, &off, 0, cr);
1208 	} else {
1209 		uiop->uio_rw = UIO_WRITE;
1210 		bp->b_error = error = nfs_write(vp, uiop, &off, 0, cr);
1211 	}
1212 	bp->b_resid = uiop->uio_resid;
1213 	biodone(bp);
1214 	crfree(cr);
1215 	return (error);
1216 }
1217