coda_vnops.c revision 176139
1/*-
2 *             Coda: an Experimental Distributed File System
3 *                              Release 3.1
4 *
5 *           Copyright (c) 1987-1998 Carnegie Mellon University
6 *                          All Rights Reserved
7 *
8 * Permission  to  use, copy, modify and distribute this software and its
9 * documentation is hereby granted,  provided  that  both  the  copyright
10 * notice  and  this  permission  notice  appear  in  all  copies  of the
11 * software, derivative works or  modified  versions,  and  any  portions
12 * thereof, and that both notices appear in supporting documentation, and
13 * that credit is given to Carnegie Mellon University  in  all  documents
14 * and publicity pertaining to direct or indirect use of this code or its
15 * derivatives.
16 *
17 * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
18 * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
19 * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
20 * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
21 * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
22 * ANY DERIVATIVE WORK.
23 *
24 * Carnegie  Mellon  encourages  users  of  this  software  to return any
25 * improvements or extensions that  they  make,  and  to  grant  Carnegie
26 * Mellon the rights to redistribute these changes without encumbrance.
27 *
28 *  	@(#) src/sys/coda/coda_vnops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
29 */
30/*
31 * Mach Operating System
32 * Copyright (c) 1990 Carnegie-Mellon University
33 * Copyright (c) 1989 Carnegie-Mellon University
34 * All rights reserved.  The CMU software License Agreement specifies
35 * the terms and conditions for use and redistribution.
36 */
37
38/*
39 * This code was written for the Coda filesystem at Carnegie Mellon
40 * University.  Contributers include David Steere, James Kistler, and
41 * M. Satyanarayanan.
42 */
43
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD: head/sys/fs/coda/coda_vnops.c 176139 2008-02-10 11:18:12Z rwatson $");
46
47#include <sys/param.h>
48#include <sys/systm.h>
49#include <sys/acct.h>
50#include <sys/errno.h>
51#include <sys/fcntl.h>
52#include <sys/kernel.h>
53#include <sys/lock.h>
54#include <sys/malloc.h>
55#include <sys/file.h>		/* Must come after sys/malloc.h */
56#include <sys/mount.h>
57#include <sys/mutex.h>
58#include <sys/namei.h>
59#include <sys/proc.h>
60#include <sys/uio.h>
61#include <sys/unistd.h>
62
63#include <vm/vm.h>
64#include <vm/vm_object.h>
65#include <vm/vm_extern.h>
66
67#include <fs/coda/coda.h>
68#include <fs/coda/cnode.h>
69#include <fs/coda/coda_vnops.h>
70#include <fs/coda/coda_venus.h>
71#include <fs/coda/coda_opstats.h>
72#include <fs/coda/coda_subr.h>
73#include <fs/coda/coda_namecache.h>
74#include <fs/coda/coda_pioctl.h>
75
76/*
77 * These flags select various performance enhancements.
78 */
79static int coda_attr_cache = 1;		/* Set to cache attributes. */
80static int coda_symlink_cache = 1;	/* Set to cache symbolic links. */
81static int coda_access_cache = 1;	/* Set to cache some access checks. */
82
83/*
84 * Structure to keep track of vfs calls.
85 */
86static struct coda_op_stats coda_vnodeopstats[CODA_VNODEOPS_SIZE];
87
88#define	MARK_ENTRY(op)		(coda_vnodeopstats[op].entries++)
89#define	MARK_INT_SAT(op)	(coda_vnodeopstats[op].sat_intrn++)
90#define	MARK_INT_FAIL(op)	(coda_vnodeopstats[op].unsat_intrn++)
91#define	MARK_INT_GEN(op)	(coda_vnodeopstats[op].gen_intrn++)
92
93/*
94 * What we are delaying for in printf.
95 */
96int coda_printf_delay = 0;	/* In microseconds */
97int coda_vnop_print_entry = 0;
98static int coda_lockdebug = 0;
99
100/*
101 * Some FreeBSD details:
102 *
103 * codadev_modevent is called at boot time or module load time.
104 */
105#define	ENTRY do {							\
106	if (coda_vnop_print_entry)					\
107		myprintf(("Entered %s\n", __func__));			\
108} while (0)
109
110/*
111 * Definition of the vnode operation vector.
112 */
113struct vop_vector coda_vnodeops = {
114	.vop_default = &default_vnodeops,
115	.vop_lookup = coda_lookup,		/* lookup */
116	.vop_create = coda_create,		/* create */
117	.vop_open = coda_open,			/* open */
118	.vop_close = coda_close,		/* close */
119	.vop_access = coda_access,		/* access */
120	.vop_getattr = coda_getattr,		/* getattr */
121	.vop_setattr = coda_setattr,		/* setattr */
122	.vop_read = coda_read,			/* read */
123	.vop_write = coda_write,		/* write */
124	.vop_ioctl = coda_ioctl,		/* ioctl */
125	.vop_fsync = coda_fsync,		/* fsync */
126	.vop_remove = coda_remove,		/* remove */
127	.vop_link = coda_link,			/* link */
128	.vop_rename = coda_rename,		/* rename */
129	.vop_mkdir = coda_mkdir,		/* mkdir */
130	.vop_rmdir = coda_rmdir,		/* rmdir */
131	.vop_symlink = coda_symlink,		/* symlink */
132	.vop_readdir = coda_readdir,		/* readdir */
133	.vop_readlink = coda_readlink,		/* readlink */
134	.vop_inactive = coda_inactive,		/* inactive */
135	.vop_reclaim = coda_reclaim,		/* reclaim */
136	.vop_lock1 = coda_lock,			/* lock */
137	.vop_unlock = coda_unlock,		/* unlock */
138	.vop_bmap = VOP_EOPNOTSUPP,		/* bmap */
139	.vop_print = VOP_NULL,			/* print */
140	.vop_islocked = coda_islocked,		/* islocked */
141	.vop_pathconf = coda_pathconf,		/* pathconf */
142	.vop_poll = vop_stdpoll,
143	.vop_getpages = vop_stdgetpages,	/* pager intf.*/
144	.vop_putpages = vop_stdputpages,	/* pager intf.*/
145	.vop_getwritemount = vop_stdgetwritemount,
146#if 0
147	/* missing */
148	.vop_cachedlookup = ufs_lookup,
149	.vop_whiteout =	ufs_whiteout,
150#endif
151
152};
153
154static void	coda_print_vattr(struct vattr *attr);
155
156int
157coda_vnodeopstats_init(void)
158{
159	int i;
160
161	for(i=0; i<CODA_VNODEOPS_SIZE; i++) {
162		coda_vnodeopstats[i].opcode = i;
163		coda_vnodeopstats[i].entries = 0;
164		coda_vnodeopstats[i].sat_intrn = 0;
165		coda_vnodeopstats[i].unsat_intrn = 0;
166		coda_vnodeopstats[i].gen_intrn = 0;
167	}
168	return (0);
169}
170
171/*
172 * coda_open calls Venus which returns an open file descriptor the cache file
173 * holding the data.  We get the vnode while we are still in the context of
174 * the venus process in coda_psdev.c.  This vnode is then passed back to the
175 * caller and opened.
176 */
177int
178coda_open(struct vop_open_args *ap)
179{
180
181	/*
182	 * FreeBSD can pass the O_EXCL flag in mode, even though the check
183	 * has already happened.  Venus defensively assumes that if open is
184	 * passed the EXCL, it must be a bug.  We strip the flag here.
185	 */
186	/* true args */
187	struct vnode **vpp = &(ap->a_vp);
188	struct cnode *cp = VTOC(*vpp);
189	int flag = ap->a_mode & (~O_EXCL);
190	struct ucred *cred = ap->a_cred;
191	struct thread *td = ap->a_td;
192	/* locals */
193	int error;
194	struct vnode *vp;
195
196	MARK_ENTRY(CODA_OPEN_STATS);
197
198	/*
199	 * Check for open of control file.
200	 */
201	if (IS_CTL_VP(*vpp)) {
202		/* XXX */
203		/* if (WRITEABLE(flag)) */
204		if (flag & (FWRITE | O_TRUNC | O_CREAT | O_EXCL)) {
205			MARK_INT_FAIL(CODA_OPEN_STATS);
206			return (EACCES);
207		}
208		MARK_INT_SAT(CODA_OPEN_STATS);
209		return (0);
210	}
211	error = venus_open(vtomi((*vpp)), &cp->c_fid, flag, cred,
212	    td->td_proc, &vp);
213	if (error)
214		return (error);
215	CODADEBUG(CODA_OPEN, myprintf(("open: vp %p result %d\n", vp,
216	    error)););
217
218	/*
219	 * Save the vnode pointer for the cache file.
220	 */
221	if (cp->c_ovp == NULL) {
222		cp->c_ovp = vp;
223	} else {
224		if (cp->c_ovp != vp)
225			panic("coda_open: cp->c_ovp != ITOV(ip)");
226	}
227	cp->c_ocount++;
228
229	/*
230	 * Flush the attribute cached if writing the file.
231	 */
232	if (flag & FWRITE) {
233		cp->c_owrite++;
234		cp->c_flags &= ~C_VATTR;
235	}
236
237	/*
238	 * Open the cache file.
239	 */
240	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
241	error = VOP_OPEN(vp, flag, cred, td, NULL);
242	if (error) {
243		VOP_UNLOCK(vp, 0);
244    		printf("coda_open: VOP_OPEN on container failed %d\n", error);
245		return (error);
246	}
247	(*vpp)->v_object = vp->v_object;
248	VOP_UNLOCK(vp, 0);
249	return (0);
250}
251
252/*
253 * Close the cache file used for I/O and notify Venus.
254 */
255int
256coda_close(struct vop_close_args *ap)
257{
258	/* true args */
259	struct vnode *vp = ap->a_vp;
260	struct cnode *cp = VTOC(vp);
261	int flag = ap->a_fflag;
262	struct ucred *cred = ap->a_cred;
263	struct thread *td = ap->a_td;
264	/* locals */
265	int error;
266
267	MARK_ENTRY(CODA_CLOSE_STATS);
268
269	/*
270	 * Check for close of control file.
271	 */
272	if (IS_CTL_VP(vp)) {
273		MARK_INT_SAT(CODA_CLOSE_STATS);
274		return (0);
275	}
276	if (cp->c_ovp) {
277		vn_lock(cp->c_ovp, LK_EXCLUSIVE | LK_RETRY);
278		/* Do errors matter here? */
279		VOP_CLOSE(cp->c_ovp, flag, cred, td);
280		vput(cp->c_ovp);
281	}
282#ifdef CODA_VERBOSE
283	else
284		printf("coda_close: NO container vp %p/cp %p\n", vp, cp);
285#endif
286	if (--cp->c_ocount == 0)
287		cp->c_ovp = NULL;
288
289	/*
290	 * File was opened for write.
291	 */
292	if (flag & FWRITE)
293		--cp->c_owrite;
294	if (!IS_UNMOUNTING(cp))
295		error = venus_close(vtomi(vp), &cp->c_fid, flag, cred,
296		    td->td_proc);
297	else
298		error = ENODEV;
299	CODADEBUG(CODA_CLOSE, myprintf(("close: result %d\n",error)););
300	return (error);
301}
302
303int
304coda_read(struct vop_read_args *ap)
305{
306
307	ENTRY;
308	return (coda_rdwr(ap->a_vp, ap->a_uio, UIO_READ, ap->a_ioflag,
309	    ap->a_cred, ap->a_uio->uio_td));
310}
311
312int
313coda_write(struct vop_write_args *ap)
314{
315
316	ENTRY;
317	return (coda_rdwr(ap->a_vp, ap->a_uio, UIO_WRITE, ap->a_ioflag,
318	    ap->a_cred, ap->a_uio->uio_td));
319}
320
321int
322coda_rdwr(struct vnode *vp, struct uio *uiop, enum uio_rw rw, int ioflag,
323    struct ucred *cred, struct thread *td)
324{
325	/* upcall decl */
326	/* NOTE: container file operation!!! */
327	/* locals */
328	struct cnode *cp = VTOC(vp);
329	struct vnode *cfvp = cp->c_ovp;
330	int opened_internally = 0;
331	int error = 0;
332
333	MARK_ENTRY(CODA_RDWR_STATS);
334	CODADEBUG(CODA_RDWR, myprintf(("coda_rdwr(%d, %p, %d, %lld, %d)\n",
335	    rw, (void *)uiop->uio_iov->iov_base, uiop->uio_resid,
336	    (long long)uiop->uio_offset, uiop->uio_segflg)););
337
338	/*
339	 * Check for rdwr of control object.
340	 */
341	if (IS_CTL_VP(vp)) {
342		MARK_INT_FAIL(CODA_RDWR_STATS);
343		return (EINVAL);
344	}
345
346	/*
347	 * If file is not already open this must be a page {read,write}
348	 * request and we should open it internally.
349	 */
350	if (cfvp == NULL) {
351		opened_internally = 1;
352		MARK_INT_GEN(CODA_OPEN_STATS);
353		error = VOP_OPEN(vp, (rw == UIO_READ ? FREAD : FWRITE), cred,
354		    td, NULL);
355#ifdef CODA_VERBOSE
356		printf("coda_rdwr: Internally Opening %p\n", vp);
357#endif
358		if (error) {
359			printf("coda_rdwr: VOP_OPEN on container failed "
360			    "%d\n", error);
361			return (error);
362		}
363		cfvp = cp->c_ovp;
364	}
365
366	/*
367	 * Have UFS handle the call.
368	 */
369	CODADEBUG(CODA_RDWR, myprintf(("indirect rdwr: fid = %s, refcnt = "
370	    "%d\n", coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount)););
371	vn_lock(cfvp, LK_EXCLUSIVE | LK_RETRY);
372	if (rw == UIO_READ) {
373		error = VOP_READ(cfvp, uiop, ioflag, cred);
374	} else {
375		error = VOP_WRITE(cfvp, uiop, ioflag, cred);
376		/*
377		 * ufs_write updates the vnode_pager_setsize for the
378		 * vnode/object.
379		 *
380		 * XXX: Since we now share vm objects between layers, this is
381		 * probably unnecessary.
382		 */
383		{
384			struct vattr attr;
385			if (VOP_GETATTR(cfvp, &attr, cred, td) == 0)
386				vnode_pager_setsize(vp, attr.va_size);
387		}
388	}
389	VOP_UNLOCK(cfvp, 0);
390	if (error)
391		MARK_INT_FAIL(CODA_RDWR_STATS);
392	else
393		MARK_INT_SAT(CODA_RDWR_STATS);
394
395	/*
396	 * Do an internal close if necessary.
397	 */
398	if (opened_internally) {
399		MARK_INT_GEN(CODA_CLOSE_STATS);
400		(void)VOP_CLOSE(vp, (rw == UIO_READ ? FREAD : FWRITE), cred,
401		    td);
402	}
403
404	/*
405	 * Invalidate cached attributes if writing.
406	 */
407	if (rw == UIO_WRITE)
408		cp->c_flags &= ~C_VATTR;
409	return (error);
410}
411
412int
413coda_ioctl(struct vop_ioctl_args *ap)
414{
415	/* true args */
416	struct vnode *vp = ap->a_vp;
417	int com = ap->a_command;
418	caddr_t data = ap->a_data;
419	int flag = ap->a_fflag;
420	struct ucred *cred = ap->a_cred;
421	struct thread *td = ap->a_td;
422	/* locals */
423	int error;
424	struct vnode *tvp;
425	struct nameidata ndp;
426	struct PioctlData *iap = (struct PioctlData *)data;
427
428	MARK_ENTRY(CODA_IOCTL_STATS);
429	CODADEBUG(CODA_IOCTL, myprintf(("in coda_ioctl on %s\n", iap->path)););
430
431	/*
432	 * Don't check for operation on a dying object, for ctlvp it
433	 * shouldn't matter.
434	 *
435	 * Must be control object to succeed.
436	 */
437	if (!IS_CTL_VP(vp)) {
438		MARK_INT_FAIL(CODA_IOCTL_STATS);
439		CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: vp != "
440		    "ctlvp")););
441		return (EOPNOTSUPP);
442	}
443
444	/*
445	 * Look up the pathname.
446	 *
447	 * Should we use the name cache here? It would get it from lookupname
448	 * sooner or later anyway, right?
449	 */
450	NDINIT(&ndp, LOOKUP, (iap->follow ? FOLLOW : NOFOLLOW),
451	    UIO_USERSPACE, iap->path, td);
452	error = namei(&ndp);
453	tvp = ndp.ni_vp;
454	if (error) {
455		MARK_INT_FAIL(CODA_IOCTL_STATS);
456		CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: lookup "
457		    "returns %d\n", error)););
458		return (error);
459	}
460
461	/*
462	 * Make sure this is a coda style cnode, but it may be a different
463	 * vfsp.
464	 */
465	if (tvp->v_op != &coda_vnodeops) {
466		vrele(tvp);
467		NDFREE(&ndp, NDF_ONLY_PNBUF);
468		MARK_INT_FAIL(CODA_IOCTL_STATS);
469		CODADEBUG(CODA_IOCTL,
470		myprintf(("coda_ioctl error: %s not a coda object\n",
471		    iap->path)););
472		return (EINVAL);
473	}
474	if (iap->vi.in_size > VC_MAXDATASIZE) {
475		NDFREE(&ndp, 0);
476		return (EINVAL);
477	}
478	error = venus_ioctl(vtomi(tvp), &((VTOC(tvp))->c_fid), com, flag,
479	    data, cred, td->td_proc);
480	if (error)
481		MARK_INT_FAIL(CODA_IOCTL_STATS);
482	else
483		CODADEBUG(CODA_IOCTL, myprintf(("Ioctl returns %d \n",
484		    error)););
485	vrele(tvp);
486	NDFREE(&ndp, NDF_ONLY_PNBUF);
487	return (error);
488}
489
490/*
491 * To reduce the cost of a user-level venus;we cache attributes in the
492 * kernel.  Each cnode has storage allocated for an attribute.  If c_vattr is
493 * valid, return a reference to it.  Otherwise, get the attributes from venus
494 * and store them in the cnode.  There is some question if this method is a
495 * security leak.  But I think that in order to make this call, the user must
496 * have done a lookup and opened the file, and therefore should already have
497 * access.
498 */
499int
500coda_getattr(struct vop_getattr_args *ap)
501{
502	/* true args */
503	struct vnode *vp = ap->a_vp;
504	struct cnode *cp = VTOC(vp);
505	struct vattr *vap = ap->a_vap;
506	struct ucred *cred = ap->a_cred;
507	struct thread *td = ap->a_td;
508	/* locals */
509    	struct vnode *convp;
510	int error, size;
511
512	MARK_ENTRY(CODA_GETATTR_STATS);
513	if (IS_UNMOUNTING(cp))
514		return (ENODEV);
515
516	/*
517	 * Check for getattr of control object.
518	 */
519	if (IS_CTL_VP(vp)) {
520		MARK_INT_FAIL(CODA_GETATTR_STATS);
521		return (ENOENT);
522	}
523
524	/*
525	 * Check to see if the attributes have already been cached.
526	 */
527	if (VALID_VATTR(cp)) {
528		CODADEBUG(CODA_GETATTR, myprintf(("attr cache hit: %s\n",
529		    coda_f2s(&cp->c_fid))););
530		CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
531		    coda_print_vattr(&cp->c_vattr););
532		*vap = cp->c_vattr;
533		MARK_INT_SAT(CODA_GETATTR_STATS);
534		return (0);
535	}
536    	error = venus_getattr(vtomi(vp), &cp->c_fid, cred, td->td_proc, vap);
537	if (!error) {
538		CODADEBUG(CODA_GETATTR, myprintf(("getattr miss %s: result "
539		    "%d\n", coda_f2s(&cp->c_fid), error)););
540		CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
541		    coda_print_vattr(vap););
542
543		/*
544		 * XXX: Since we now share vm objects between layers, this is
545		 * probably unnecessary.
546		 */
547		size = vap->va_size;
548    		convp = cp->c_ovp;
549		if (convp != NULL)
550			vnode_pager_setsize(convp, size);
551
552		/*
553		 * If not open for write, store attributes in cnode.
554		 */
555		if ((cp->c_owrite == 0) && (coda_attr_cache)) {
556			cp->c_vattr = *vap;
557			cp->c_flags |= C_VATTR;
558		}
559	}
560	return (error);
561}
562
563int
564coda_setattr(struct vop_setattr_args *ap)
565{
566	/* true args */
567	struct vnode *vp = ap->a_vp;
568	struct cnode *cp = VTOC(vp);
569	struct vattr *vap = ap->a_vap;
570	struct ucred *cred = ap->a_cred;
571	struct thread *td = ap->a_td;
572	/* locals */
573    	struct vnode *convp;
574	int error, size;
575
576	MARK_ENTRY(CODA_SETATTR_STATS);
577
578	/*
579	 * Check for setattr of control object.
580	 */
581	if (IS_CTL_VP(vp)) {
582		MARK_INT_FAIL(CODA_SETATTR_STATS);
583		return (ENOENT);
584	}
585	if (codadebug & CODADBGMSK(CODA_SETATTR))
586		coda_print_vattr(vap);
587	error = venus_setattr(vtomi(vp), &cp->c_fid, vap, cred, td->td_proc);
588	if (!error)
589		cp->c_flags &= ~C_VATTR;
590
591	/*
592	 * XXX: Since we now share vm objects between layers, this is
593	 * probably unnecessary.
594	 *
595	 * XXX: Shouldn't we only be doing this "set" if C_VATTR remains
596	 * valid after venus_setattr()?
597	 */
598	size = vap->va_size;
599    	convp = cp->c_ovp;
600	if (size != VNOVAL && convp != NULL)
601		vnode_pager_setsize(convp, size);
602	CODADEBUG(CODA_SETATTR,	myprintf(("setattr %d\n", error)););
603	return (error);
604}
605
606int
607coda_access(struct vop_access_args *ap)
608{
609	/* true args */
610	struct vnode *vp = ap->a_vp;
611	struct cnode *cp = VTOC(vp);
612	int mode = ap->a_mode;
613	struct ucred *cred = ap->a_cred;
614	struct thread *td = ap->a_td;
615	/* locals */
616	int error;
617
618	MARK_ENTRY(CODA_ACCESS_STATS);
619
620	/*
621	 * Check for access of control object.  Only read access is allowed
622	 * on it.
623	 */
624	if (IS_CTL_VP(vp)) {
625		/*
626		 * Bogus hack - all will be marked as successes.
627		 */
628		MARK_INT_SAT(CODA_ACCESS_STATS);
629		return (((mode & VREAD) && !(mode & (VWRITE | VEXEC)))
630		    ? 0 : EACCES);
631	}
632
633	/*
634	 * if the file is a directory, and we are checking exec (eg lookup)
635	 * access, and the file is in the namecache, then the user must have
636	 * lookup access to it.
637	 */
638	if (coda_access_cache) {
639		if ((vp->v_type == VDIR) && (mode & VEXEC)) {
640			if (coda_nc_lookup(cp, ".", 1, cred)) {
641				MARK_INT_SAT(CODA_ACCESS_STATS);
642				return (0);
643			}
644		}
645	}
646	error = venus_access(vtomi(vp), &cp->c_fid, mode, cred, td->td_proc);
647	return (error);
648}
649
650int
651coda_readlink(struct vop_readlink_args *ap)
652{
653	/* true args */
654	struct vnode *vp = ap->a_vp;
655	struct cnode *cp = VTOC(vp);
656	struct uio *uiop = ap->a_uio;
657	struct ucred *cred = ap->a_cred;
658	struct thread *td = ap->a_uio->uio_td;
659	/* locals */
660	int error;
661	char *str;
662	int len;
663
664	MARK_ENTRY(CODA_READLINK_STATS);
665
666	/*
667	 * Check for readlink of control object.
668	 */
669	if (IS_CTL_VP(vp)) {
670		MARK_INT_FAIL(CODA_READLINK_STATS);
671		return (ENOENT);
672	}
673	if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) {
674		/*
675		 * Symlink was cached.
676		 */
677		uiop->uio_rw = UIO_READ;
678		error = uiomove(cp->c_symlink, (int)cp->c_symlen, uiop);
679		if (error)
680			MARK_INT_FAIL(CODA_READLINK_STATS);
681		else
682			MARK_INT_SAT(CODA_READLINK_STATS);
683		return (error);
684	}
685	error = venus_readlink(vtomi(vp), &cp->c_fid, cred, td != NULL ?
686	    td->td_proc : NULL, &str, &len);
687	if (!error) {
688		uiop->uio_rw = UIO_READ;
689		error = uiomove(str, len, uiop);
690		if (coda_symlink_cache) {
691			cp->c_symlink = str;
692			cp->c_symlen = len;
693			cp->c_flags |= C_SYMLINK;
694		} else
695			CODA_FREE(str, len);
696	}
697	CODADEBUG(CODA_READLINK, myprintf(("in readlink result %d\n",
698	    error)););
699	return (error);
700}
701
702int
703coda_fsync(struct vop_fsync_args *ap)
704{
705	/* true args */
706	struct vnode *vp = ap->a_vp;
707	struct cnode *cp = VTOC(vp);
708	struct thread *td = ap->a_td;
709	/* locals */
710	struct vnode *convp = cp->c_ovp;
711	int error;
712
713	MARK_ENTRY(CODA_FSYNC_STATS);
714
715	/*
716	 * Check for fsync on an unmounting object.
717	 *
718	 * XXX: Is this comment true on FreeBSD?  It seems likely, since
719	 * unmounting is fairly non-atomic.
720	 *
721	 * The NetBSD kernel, in it's infinite wisdom, can try to fsync after
722	 * an unmount has been initiated.  This is a Bad Thing, which we have
723	 * to avoid.  Not a legitimate failure for stats.
724	 */
725	if (IS_UNMOUNTING(cp))
726		return (ENODEV);
727
728	/*
729	 * Check for fsync of control object.
730	 */
731	if (IS_CTL_VP(vp)) {
732		MARK_INT_SAT(CODA_FSYNC_STATS);
733		return (0);
734	}
735	if (convp != NULL) {
736		vn_lock(convp, LK_EXCLUSIVE | LK_RETRY);
737		VOP_FSYNC(convp, MNT_WAIT, td);
738		VOP_UNLOCK(convp, 0);
739	}
740
741	/*
742	 * We see fsyncs with usecount == 1 then usecount == 0.  For now we
743	 * ignore them.
744	 */
745#if 0
746	VI_LOCK(vp);
747	if (!vp->v_usecount) {
748		printf("coda_fsync on vnode %p with %d usecount.  "
749		    "c_flags = %x (%x)\n", vp, vp->v_usecount, cp->c_flags,
750		    cp->c_flags&C_PURGING);
751	}
752	VI_UNLOCK(vp);
753#endif
754
755	/*
756	 * We can expect fsync on any vnode at all if venus is purging it.
757	 * Venus can't very well answer the fsync request, now can it?
758	 * Hopefully, it won't have to, because hopefully, venus preserves
759	 * the (possibly untrue) invariant that it never purges an open
760	 * vnode.  Hopefully.
761	 */
762	if (cp->c_flags & C_PURGING)
763		return (0);
764
765	/* XXX: needs research */
766	return (0);
767	error = venus_fsync(vtomi(vp), &cp->c_fid, td->td_proc);
768	CODADEBUG(CODA_FSYNC, myprintf(("in fsync result %d\n", error)););
769	return (error);
770}
771
772int
773coda_inactive(struct vop_inactive_args *ap)
774{
775	/*
776	 * XXX - at the moment, inactive doesn't look at cred, and doesn't
777	 * have a proc pointer.  Oops.
778	 */
779	/* true args */
780	struct vnode *vp = ap->a_vp;
781	struct cnode *cp = VTOC(vp);
782	struct ucred *cred __attribute__((unused)) = NULL;
783	struct thread *td __attribute__((unused)) = curthread;
784	/* upcall decl */
785	/* locals */
786
787	/*
788	 * We don't need to send inactive to venus - DCS.
789	 */
790	MARK_ENTRY(CODA_INACTIVE_STATS);
791	CODADEBUG(CODA_INACTIVE, myprintf(("in inactive, %s, vfsp %p\n",
792	    coda_f2s(&cp->c_fid), vp->v_mount)););
793	vp->v_object = NULL;
794
795	/*
796	 * If an array has been allocated to hold the symlink, deallocate it.
797	 */
798	if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) {
799		if (cp->c_symlink == NULL)
800			panic("coda_inactive: null symlink pointer in cnode");
801		CODA_FREE(cp->c_symlink, cp->c_symlen);
802		cp->c_flags &= ~C_SYMLINK;
803		cp->c_symlen = 0;
804	}
805
806	/*
807	 * Remove it from the table so it can't be found.
808	 */
809	coda_unsave(cp);
810	if ((struct coda_mntinfo *)(vp->v_mount->mnt_data) == NULL) {
811		myprintf(("Help! vfsp->vfs_data was NULL, but vnode %p "
812		    "wasn't dying\n", vp));
813		panic("badness in coda_inactive\n");
814	}
815	if (IS_UNMOUNTING(cp)) {
816#ifdef	DEBUG
817		printf("coda_inactive: IS_UNMOUNTING use %d: vp %p, cp %p\n",
818		    vrefcnt(vp), vp, cp);
819		if (cp->c_ovp != NULL)
820			printf("coda_inactive: cp->ovp != NULL use %d: vp "
821			    "%p, cp %p\n", vrefcnt(vp), vp, cp);
822#endif
823	} else {
824#ifdef OLD_DIAGNOSTIC
825		if (vrefcnt(CTOV(cp)))
826			panic("coda_inactive: nonzero reference count");
827		if (cp->c_ovp != NULL)
828			panic("coda_inactive:  cp->ovp != NULL");
829#endif
830		vgone(vp);
831	}
832	MARK_INT_SAT(CODA_INACTIVE_STATS);
833	return (0);
834}
835
836/*
837 * Remote filesystem operations having to do with directory manipulation.
838 */
839
840/*
841 * In FreeBSD, lookup returns the vnode locked.
842 */
843int
844coda_lookup(struct vop_lookup_args *ap)
845{
846	/* true args */
847	struct vnode *dvp = ap->a_dvp;
848	struct cnode *dcp = VTOC(dvp);
849	struct vnode **vpp = ap->a_vpp;
850	/*
851	 * It looks as though ap->a_cnp->ni_cnd->cn_nameptr holds the rest of
852	 * the string to xlate, and that we must try to get at least
853	 * ap->a_cnp->ni_cnd->cn_namelen of those characters to macth.  I
854	 * could be wrong.
855	 */
856	struct componentname  *cnp = ap->a_cnp;
857	struct ucred *cred = cnp->cn_cred;
858	struct thread *td = cnp->cn_thread;
859	/* locals */
860	struct cnode *cp;
861	const char *nm = cnp->cn_nameptr;
862	int len = cnp->cn_namelen;
863	CodaFid VFid;
864	int vtype;
865	int error = 0;
866
867	MARK_ENTRY(CODA_LOOKUP_STATS);
868	CODADEBUG(CODA_LOOKUP, myprintf(("lookup: %s in %s\n", nm,
869	    coda_f2s(&dcp->c_fid))););
870
871	/*
872	 * Check for lookup of control object.
873	 */
874	if (IS_CTL_NAME(dvp, nm, len)) {
875		*vpp = coda_ctlvp;
876		vref(*vpp);
877		MARK_INT_SAT(CODA_LOOKUP_STATS);
878		goto exit;
879	}
880	if (len+1 > CODA_MAXNAMLEN) {
881		MARK_INT_FAIL(CODA_LOOKUP_STATS);
882		CODADEBUG(CODA_LOOKUP, myprintf(("name too long: lookup, "
883		    "%s (%s)\n", coda_f2s(&dcp->c_fid), nm)););
884		*vpp = NULL;
885		error = EINVAL;
886		goto exit;
887	}
888
889	/*
890	 * First try to look the file up in the cfs name cache.
891	 *
892	 * XXX: lock the parent vnode?
893	 */
894	cp = coda_nc_lookup(dcp, nm, len, cred);
895	if (cp) {
896		*vpp = CTOV(cp);
897		vref(*vpp);
898		CODADEBUG(CODA_LOOKUP, myprintf(("lookup result %d vpp %p\n",
899		    error,*vpp)););
900	} else {
901		/*
902		 * The name wasn't cached, so we need to contact Venus.
903		 */
904		error = venus_lookup(vtomi(dvp), &dcp->c_fid, nm, len, cred,
905		    td->td_proc, &VFid, &vtype);
906		if (error) {
907			MARK_INT_FAIL(CODA_LOOKUP_STATS);
908			CODADEBUG(CODA_LOOKUP, myprintf(("lookup error on "
909			    "%s (%s)%d\n", coda_f2s(&dcp->c_fid), nm,
910			    error)););
911			*vpp = NULL;
912		} else {
913			MARK_INT_SAT(CODA_LOOKUP_STATS);
914			CODADEBUG(CODA_LOOKUP, myprintf(("lookup: %s type %o "
915			    "result %d\n", coda_f2s(&VFid), vtype, error)););
916	    		cp = make_coda_node(&VFid, dvp->v_mount, vtype);
917	    		*vpp = CTOV(cp);
918
919	    		/*
920			 * Enter the new vnode in the Name Cache only if the
921			 * top bit isn't set.
922			 *
923			 * And don't enter a new vnode for an invalid one!
924			 */
925			if (!(vtype & CODA_NOCACHE))
926				coda_nc_enter(VTOC(dvp), nm, len, cred,
927				    VTOC(*vpp));
928		}
929	}
930exit:
931	/*
932	 * If we are creating, and this was the last name to be looked up,
933	 * and the error was ENOENT, then there really shouldn't be an error
934	 * and we can make the leaf NULL and return success.  Since this is
935	 * supposed to work under Mach as well as FreeBSD, we're leaving this
936	 * fn wrapped.  We also must tell lookup/namei that we need to save
937	 * the last component of the name.  (Create will have to free the
938	 * name buffer later...lucky us...).
939	 */
940	if (((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME))
941	    && (cnp->cn_flags & ISLASTCN) && (error == ENOENT)) {
942		error = EJUSTRETURN;
943		cnp->cn_flags |= SAVENAME;
944		*ap->a_vpp = NULL;
945	}
946
947	/*
948	 * If we are removing, and we are at the last element, and we found
949	 * it, then we need to keep the name around so that the removal will
950	 * go ahead as planned.  Unfortunately, this will probably also lock
951	 * the to-be-removed vnode, which may or may not be a good idea.
952	 * I'll have to look at the bits of coda_remove to make sure.  We'll
953	 * only save the name if we did in fact find the name, otherwise
954	 * coda_remove won't have a chance to free the pathname.
955	 */
956	if ((cnp->cn_nameiop == DELETE) && (cnp->cn_flags & ISLASTCN)
957	    && !error)
958		cnp->cn_flags |= SAVENAME;
959
960	/*
961	 * If the lookup went well, we need to (potentially?) unlock the
962	 * parent, and lock the child.  We are only responsible for checking
963	 * to see if the parent is supposed to be unlocked before we return.
964	 * We must always lock the child (provided there is one, and (the
965	 * parent isn't locked or it isn't the same as the parent.)  Simple,
966	 * huh?  We can never leave the parent locked unless we are ISLASTCN.
967	 */
968	if (!error || (error == EJUSTRETURN)) {
969		if (cnp->cn_flags & ISDOTDOT) {
970			VOP_UNLOCK(dvp, 0);
971			/*
972			 * The parent is unlocked.  As long as there is a
973			 * child, lock it without bothering to check anything
974			 * else.
975			 */
976			if (*ap->a_vpp)
977				vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY);
978			vn_lock(dvp, LK_RETRY|LK_EXCLUSIVE);
979		} else {
980			/*
981			 * The parent is locked, and may be the same as the
982			 * child.  If different, go ahead and lock it.
983			 */
984			if (*ap->a_vpp && (*ap->a_vpp != dvp))
985				vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY);
986		}
987	} else {
988		/*
989		 * If the lookup failed, we need to ensure that the leaf is
990		 * NULL.
991		 *
992		 * Don't change any locking?
993		 */
994		*ap->a_vpp = NULL;
995	}
996	return (error);
997}
998
999/*ARGSUSED*/
1000int
1001coda_create(struct vop_create_args *ap)
1002{
1003	/* true args */
1004	struct vnode *dvp = ap->a_dvp;
1005	struct cnode *dcp = VTOC(dvp);
1006	struct vattr *va = ap->a_vap;
1007	int exclusive = 1;
1008	int mode = ap->a_vap->va_mode;
1009	struct vnode **vpp = ap->a_vpp;
1010	struct componentname  *cnp = ap->a_cnp;
1011	struct ucred *cred = cnp->cn_cred;
1012	struct thread *td = cnp->cn_thread;
1013	/* locals */
1014	int error;
1015	struct cnode *cp;
1016	const char *nm = cnp->cn_nameptr;
1017	int len = cnp->cn_namelen;
1018	CodaFid VFid;
1019	struct vattr attr;
1020
1021	MARK_ENTRY(CODA_CREATE_STATS);
1022
1023	/*
1024	 * All creates are exclusive XXX.
1025	 *
1026	 * I'm assuming the 'mode' argument is the file mode bits XXX.
1027	 *
1028	 * Check for create of control object.
1029	 */
1030	if (IS_CTL_NAME(dvp, nm, len)) {
1031		*vpp = (struct vnode *)0;
1032		MARK_INT_FAIL(CODA_CREATE_STATS);
1033		return (EACCES);
1034	}
1035	error = venus_create(vtomi(dvp), &dcp->c_fid, nm, len, exclusive,
1036	    mode, va, cred, td->td_proc, &VFid, &attr);
1037	if (!error) {
1038		/*
1039		 * If this is an exclusive create, panic if the file already
1040		 * exists.
1041		 *
1042		 * Venus should have detected the file and reported EEXIST.
1043		 */
1044		if ((exclusive == 1) && (coda_find(&VFid) != NULL))
1045	  	  	panic("cnode existed for newly created file!");
1046		cp = make_coda_node(&VFid, dvp->v_mount, attr.va_type);
1047		*vpp = CTOV(cp);
1048
1049		/*
1050		 * Update va to reflect the new attributes.
1051		 */
1052		(*va) = attr;
1053
1054		/*
1055		 * Update the attribute cache and mark it as valid.
1056		 */
1057		if (coda_attr_cache) {
1058			VTOC(*vpp)->c_vattr = attr;
1059			VTOC(*vpp)->c_flags |= C_VATTR;
1060		}
1061
1062		/*
1063		 * Invalidate the parent's attr cache, the modification time
1064		 * has changed.
1065		 */
1066		VTOC(dvp)->c_flags &= ~C_VATTR;
1067
1068		/*
1069		 * Enter the new vnode in the Name Cache.
1070		 */
1071		coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
1072		CODADEBUG(CODA_CREATE, myprintf(("create: %s, result %d\n",
1073		    coda_f2s(&VFid), error)););
1074	} else {
1075		*vpp = (struct vnode *)0;
1076		CODADEBUG(CODA_CREATE, myprintf(("create error %d\n",
1077		    error)););
1078	}
1079	if (!error) {
1080		if (cnp->cn_flags & LOCKLEAF)
1081			vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY);
1082#ifdef OLD_DIAGNOSTIC
1083		else
1084			printf("coda_create: LOCKLEAF not set!\n");
1085#endif
1086	}
1087	return (error);
1088}
1089
1090int
1091coda_remove(struct vop_remove_args *ap)
1092{
1093	/* true args */
1094	struct vnode *dvp = ap->a_dvp;
1095	struct cnode *cp = VTOC(dvp);
1096	struct componentname  *cnp = ap->a_cnp;
1097	struct ucred *cred = cnp->cn_cred;
1098	struct thread *td = cnp->cn_thread;
1099	/* locals */
1100	int error;
1101	const char *nm = cnp->cn_nameptr;
1102	int len = cnp->cn_namelen;
1103	struct cnode *tp;
1104
1105	MARK_ENTRY(CODA_REMOVE_STATS);
1106	CODADEBUG(CODA_REMOVE, myprintf(("remove: %s in %s\n", nm,
1107	    coda_f2s(&cp->c_fid))););
1108
1109	/*
1110	 * Remove the file's entry from the CODA Name Cache.
1111	 *
1112	 * We're being conservative here, it might be that this person
1113	 * doesn't really have sufficient access to delete the file but we
1114	 * feel zapping the entry won't really hurt anyone -- dcs.
1115	 *
1116	 * I'm gonna go out on a limb here.  If a file and a hardlink to it
1117	 * exist, and one is removed, the link count on the other will be off
1118	 * by 1. We could either invalidate the attrs if cached, orfix them.
1119	 * I'll try to fix them. DCS 11/8/94
1120	 */
1121	tp = coda_nc_lookup(VTOC(dvp), nm, len, cred);
1122	if (tp!= NULL) {
1123		if (VALID_VATTR(tp)) {
1124			if (tp->c_vattr.va_nlink > 1)
1125				tp->c_vattr.va_nlink--;
1126		}
1127		coda_nc_zapfile(VTOC(dvp), nm, len);
1128	}
1129
1130	/*
1131	 * Invalidate the parent's attr cache, the modification time has
1132	 * changed.
1133	 */
1134	VTOC(dvp)->c_flags &= ~C_VATTR;
1135
1136	/*
1137	 * Check for remove of control object.
1138	 */
1139	if (IS_CTL_NAME(dvp, nm, len)) {
1140		MARK_INT_FAIL(CODA_REMOVE_STATS);
1141		return (ENOENT);
1142	}
1143	error = venus_remove(vtomi(dvp), &cp->c_fid, nm, len, cred,
1144	    td->td_proc);
1145	CODADEBUG(CODA_REMOVE, myprintf(("in remove result %d\n",error)););
1146	return (error);
1147}
1148
1149int
1150coda_link(struct vop_link_args *ap)
1151{
1152	/* true args */
1153	struct vnode *vp = ap->a_vp;
1154	struct cnode *cp = VTOC(vp);
1155	struct vnode *tdvp = ap->a_tdvp;
1156	struct cnode *tdcp = VTOC(tdvp);
1157	struct componentname *cnp = ap->a_cnp;
1158	struct ucred *cred = cnp->cn_cred;
1159	struct thread *td = cnp->cn_thread;
1160	/* locals */
1161	int error;
1162	const char *nm = cnp->cn_nameptr;
1163	int len = cnp->cn_namelen;
1164
1165	MARK_ENTRY(CODA_LINK_STATS);
1166
1167	if (codadebug & CODADBGMSK(CODA_LINK)) {
1168		myprintf(("nb_link:   vp fid: %s\n", coda_f2s(&cp->c_fid)));
1169		myprintf(("nb_link: tdvp fid: %s)\n",
1170		    coda_f2s(&tdcp->c_fid)));
1171	}
1172	if (codadebug & CODADBGMSK(CODA_LINK)) {
1173		myprintf(("link:   vp fid: %s\n", coda_f2s(&cp->c_fid)));
1174		myprintf(("link: tdvp fid: %s\n", coda_f2s(&tdcp->c_fid)));
1175	}
1176
1177	/*
1178	 * Check for link to/from control object.
1179	 */
1180	if (IS_CTL_NAME(tdvp, nm, len) || IS_CTL_VP(vp)) {
1181		MARK_INT_FAIL(CODA_LINK_STATS);
1182		return (EACCES);
1183	}
1184	error = venus_link(vtomi(vp), &cp->c_fid, &tdcp->c_fid, nm, len,
1185	    cred, td->td_proc);
1186
1187	/*
1188	 * Invalidate the parent's attr cache, the modification time has
1189	 * changed.
1190	 */
1191	VTOC(tdvp)->c_flags &= ~C_VATTR;
1192	VTOC(vp)->c_flags &= ~C_VATTR;
1193	CODADEBUG(CODA_LINK, myprintf(("in link result %d\n",error)););
1194	return (error);
1195}
1196
1197int
1198coda_rename(struct vop_rename_args *ap)
1199{
1200	/* true args */
1201	struct vnode *odvp = ap->a_fdvp;
1202	struct cnode *odcp = VTOC(odvp);
1203	struct componentname  *fcnp = ap->a_fcnp;
1204	struct vnode *ndvp = ap->a_tdvp;
1205	struct cnode *ndcp = VTOC(ndvp);
1206	struct componentname  *tcnp = ap->a_tcnp;
1207	struct ucred *cred = fcnp->cn_cred;
1208	struct thread *td = fcnp->cn_thread;
1209	/* true args */
1210	int error;
1211	const char *fnm = fcnp->cn_nameptr;
1212	int flen = fcnp->cn_namelen;
1213	const char *tnm = tcnp->cn_nameptr;
1214	int tlen = tcnp->cn_namelen;
1215
1216	MARK_ENTRY(CODA_RENAME_STATS);
1217
1218	/*
1219	 * Hmmm.  The vnodes are already looked up.  Perhaps they are locked?
1220	 * This could be Bad. XXX
1221	 */
1222#ifdef OLD_DIAGNOSTIC
1223	if ((fcnp->cn_cred != tcnp->cn_cred) ||
1224	    (fcnp->cn_thread != tcnp->cn_thread))
1225		panic("coda_rename: component names don't agree");
1226#endif
1227
1228	/*
1229	 * Check for rename involving control object.
1230	 */
1231	if (IS_CTL_NAME(odvp, fnm, flen) || IS_CTL_NAME(ndvp, tnm, tlen)) {
1232		MARK_INT_FAIL(CODA_RENAME_STATS);
1233		return (EACCES);
1234	}
1235
1236	/*
1237	 * Problem with moving directories -- need to flush entry for ..
1238	 */
1239	if (odvp != ndvp) {
1240		struct cnode *ovcp = coda_nc_lookup(VTOC(odvp), fnm, flen,
1241		    cred);
1242
1243		if (ovcp) {
1244			struct vnode *ovp = CTOV(ovcp);
1245
1246			if ((ovp) && (ovp->v_type == VDIR))
1247				coda_nc_zapfile(VTOC(ovp),"..", 2);
1248		}
1249	}
1250
1251	/*
1252	 * Remove the entries for both source and target files.
1253	 */
1254	coda_nc_zapfile(VTOC(odvp), fnm, flen);
1255	coda_nc_zapfile(VTOC(ndvp), tnm, tlen);
1256
1257	/*
1258	 * Invalidate the parent's attr cache, the modification time has
1259	 * changed.
1260	 */
1261	VTOC(odvp)->c_flags &= ~C_VATTR;
1262	VTOC(ndvp)->c_flags &= ~C_VATTR;
1263	if (flen+1 > CODA_MAXNAMLEN) {
1264		MARK_INT_FAIL(CODA_RENAME_STATS);
1265		error = EINVAL;
1266		goto exit;
1267	}
1268	if (tlen+1 > CODA_MAXNAMLEN) {
1269		MARK_INT_FAIL(CODA_RENAME_STATS);
1270		error = EINVAL;
1271		goto exit;
1272	}
1273	error = venus_rename(vtomi(odvp), &odcp->c_fid, &ndcp->c_fid, fnm,
1274	    flen, tnm, tlen, cred, td->td_proc);
1275exit:
1276	CODADEBUG(CODA_RENAME, myprintf(("in rename result %d\n",error)););
1277
1278	/*
1279	 * XXX - do we need to call cache pureg on the moved vnode?
1280	 */
1281	cache_purge(ap->a_fvp);
1282
1283	/*
1284	 * Release parents first, then children.
1285	 */
1286	vrele(odvp);
1287	if (ap->a_tvp) {
1288		if (ap->a_tvp == ndvp)
1289			vrele(ndvp);
1290		else
1291			vput(ndvp);
1292		vput(ap->a_tvp);
1293	} else
1294		vput(ndvp);
1295	vrele(ap->a_fvp);
1296	return (error);
1297}
1298
1299int
1300coda_mkdir(struct vop_mkdir_args *ap)
1301{
1302	/* true args */
1303	struct vnode *dvp = ap->a_dvp;
1304	struct cnode *dcp = VTOC(dvp);
1305	struct componentname  *cnp = ap->a_cnp;
1306	struct vattr *va = ap->a_vap;
1307	struct vnode **vpp = ap->a_vpp;
1308	struct ucred *cred = cnp->cn_cred;
1309	struct thread *td = cnp->cn_thread;
1310	/* locals */
1311	int error;
1312	const char *nm = cnp->cn_nameptr;
1313	int len = cnp->cn_namelen;
1314	struct cnode *cp;
1315	CodaFid VFid;
1316	struct vattr ova;
1317
1318	MARK_ENTRY(CODA_MKDIR_STATS);
1319
1320	/*
1321	 * Check for mkdir of target object.
1322	 */
1323	if (IS_CTL_NAME(dvp, nm, len)) {
1324		*vpp = (struct vnode *)0;
1325		MARK_INT_FAIL(CODA_MKDIR_STATS);
1326		return (EACCES);
1327	}
1328	if (len+1 > CODA_MAXNAMLEN) {
1329		*vpp = (struct vnode *)0;
1330		MARK_INT_FAIL(CODA_MKDIR_STATS);
1331		return (EACCES);
1332	}
1333	error = venus_mkdir(vtomi(dvp), &dcp->c_fid, nm, len, va, cred,
1334	    td->td_proc, &VFid, &ova);
1335	if (!error) {
1336		if (coda_find(&VFid) != NULL)
1337			panic("cnode existed for newly created directory!");
1338		cp =  make_coda_node(&VFid, dvp->v_mount, va->va_type);
1339		*vpp = CTOV(cp);
1340
1341		/*
1342		 * Enter the new vnode in the Name Cache.
1343		 */
1344		coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
1345
1346		/*
1347		 * As a side effect, enter "." and ".." for the directory.
1348		 */
1349		coda_nc_enter(VTOC(*vpp), ".", 1, cred, VTOC(*vpp));
1350		coda_nc_enter(VTOC(*vpp), "..", 2, cred, VTOC(dvp));
1351		if (coda_attr_cache) {
1352			/*
1353			 * Update the attr cache and mark as valid.
1354			 */
1355			VTOC(*vpp)->c_vattr = ova;
1356			VTOC(*vpp)->c_flags |= C_VATTR;
1357		}
1358
1359		/*
1360		 * Invalidate the parent's attr cache, the modification time
1361		 * has changed.
1362		 */
1363		VTOC(dvp)->c_flags &= ~C_VATTR;
1364		vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
1365		CODADEBUG( CODA_MKDIR, myprintf(("mkdir: %s result %d\n",
1366		    coda_f2s(&VFid), error)););
1367	} else {
1368		*vpp = NULL;
1369		CODADEBUG(CODA_MKDIR, myprintf(("mkdir error %d\n",error)););
1370	}
1371	return (error);
1372}
1373
1374int
1375coda_rmdir(struct vop_rmdir_args *ap)
1376{
1377	/* true args */
1378	struct vnode *dvp = ap->a_dvp;
1379	struct cnode *dcp = VTOC(dvp);
1380	struct componentname  *cnp = ap->a_cnp;
1381	struct ucred *cred = cnp->cn_cred;
1382	struct thread *td = cnp->cn_thread;
1383	/* true args */
1384	int error;
1385	const char *nm = cnp->cn_nameptr;
1386	int len = cnp->cn_namelen;
1387	struct cnode *cp;
1388
1389	MARK_ENTRY(CODA_RMDIR_STATS);
1390
1391	/*
1392	 * Check for rmdir of control object.
1393	 */
1394	if (IS_CTL_NAME(dvp, nm, len)) {
1395		MARK_INT_FAIL(CODA_RMDIR_STATS);
1396		return (ENOENT);
1397	}
1398
1399	/*
1400	 * We're being conservative here, it might be that this person
1401	 * doesn't really have sufficient access to delete the file but we
1402	 * feel zapping the entry won't really hurt anyone -- dcs
1403	 *
1404	 * As a side effect of the rmdir, remove any entries for children of
1405	 * the directory, especially "." and "..".
1406	 */
1407	cp = coda_nc_lookup(dcp, nm, len, cred);
1408	if (cp)
1409		coda_nc_zapParentfid(&(cp->c_fid), NOT_DOWNCALL);
1410
1411	/*
1412	 * Remove the file's entry from the CODA Name Cache.
1413	 */
1414	coda_nc_zapfile(dcp, nm, len);
1415
1416	/*
1417	 * Invalidate the parent's attr cache, the modification time has
1418	 * changed.
1419	 */
1420	dcp->c_flags &= ~C_VATTR;
1421	error = venus_rmdir(vtomi(dvp), &dcp->c_fid, nm, len, cred,
1422	    td->td_proc);
1423	CODADEBUG(CODA_RMDIR, myprintf(("in rmdir result %d\n", error)););
1424	return (error);
1425}
1426
1427int
1428coda_symlink(struct vop_symlink_args *ap)
1429{
1430	/* true args */
1431	struct vnode *tdvp = ap->a_dvp;
1432	struct cnode *tdcp = VTOC(tdvp);
1433	struct componentname *cnp = ap->a_cnp;
1434	struct vattr *tva = ap->a_vap;
1435	char *path = ap->a_target;
1436	struct ucred *cred = cnp->cn_cred;
1437	struct thread *td = cnp->cn_thread;
1438	struct vnode **vpp = ap->a_vpp;
1439	/* locals */
1440	int error;
1441
1442	/*-
1443	 * XXX I'm assuming the following things about coda_symlink's
1444	 * arguments:
1445	 *       t(foo) is the new name/parent/etc being created.
1446	 *       lname is the contents of the new symlink.
1447	 */
1448	char *nm = cnp->cn_nameptr;
1449	int len = cnp->cn_namelen;
1450	int plen = strlen(path);
1451
1452	/*
1453	 * Here's the strategy for the moment: perform the symlink, then do a
1454	 * lookup to grab the resulting vnode.  I know this requires two
1455	 * communications with Venus for a new sybolic link, but that's the
1456	 * way the ball bounces.  I don't yet want to change the way the Mach
1457	 * symlink works.  When Mach support is deprecated, we should change
1458	 * symlink so that the common case returns the resultant vnode in a
1459	 * vpp argument.
1460	 */
1461	MARK_ENTRY(CODA_SYMLINK_STATS);
1462
1463	/*
1464	 * Check for symlink of control object.
1465	 */
1466	if (IS_CTL_NAME(tdvp, nm, len)) {
1467		MARK_INT_FAIL(CODA_SYMLINK_STATS);
1468		return (EACCES);
1469	}
1470	if (plen+1 > CODA_MAXPATHLEN) {
1471		MARK_INT_FAIL(CODA_SYMLINK_STATS);
1472		return (EINVAL);
1473	}
1474	if (len+1 > CODA_MAXNAMLEN) {
1475		MARK_INT_FAIL(CODA_SYMLINK_STATS);
1476		error = EINVAL;
1477		goto exit;
1478	}
1479	error = venus_symlink(vtomi(tdvp), &tdcp->c_fid, path, plen, nm, len,
1480	    tva, cred, td->td_proc);
1481
1482	/*
1483	 * Invalidate the parent's attr cache, the modification time has
1484	 * changed.
1485	 */
1486	tdcp->c_flags &= ~C_VATTR;
1487	if (error == 0)
1488		error = VOP_LOOKUP(tdvp, vpp, cnp);
1489exit:
1490	CODADEBUG(CODA_SYMLINK, myprintf(("in symlink result %d\n",error)););
1491	return (error);
1492}
1493
1494/*
1495 * Read directory entries.
1496 *
1497 * XXX: This forwards the operator straight to the cache vnode using
1498 * VOP_READDIR(), rather than calling venus_readdir().  Why?
1499 */
1500int
1501coda_readdir(struct vop_readdir_args *ap)
1502{
1503	/* true args */
1504	struct vnode *vp = ap->a_vp;
1505	struct cnode *cp = VTOC(vp);
1506	struct uio *uiop = ap->a_uio;
1507	struct ucred *cred = ap->a_cred;
1508	int *eofflag = ap->a_eofflag;
1509	u_long **cookies = ap->a_cookies;
1510	int *ncookies = ap->a_ncookies;
1511	struct thread *td = ap->a_uio->uio_td;
1512	/* upcall decl */
1513	/* locals */
1514	int error = 0;
1515	int opened_internally = 0;
1516
1517	MARK_ENTRY(CODA_READDIR_STATS);
1518	CODADEBUG(CODA_READDIR, myprintf(("coda_readdir(%p, %d, %lld, %d)\n",
1519	    (void *)uiop->uio_iov->iov_base, uiop->uio_resid,
1520	    (long long)uiop->uio_offset, uiop->uio_segflg)););
1521
1522	/*
1523	 * Check for readdir of control object.
1524	 */
1525	if (IS_CTL_VP(vp)) {
1526		MARK_INT_FAIL(CODA_READDIR_STATS);
1527		return (ENOENT);
1528	}
1529
1530	/*
1531	 * If directory is not already open do an "internal open" on it.
1532	 *
1533	 * XXX: Why would this happen?  For files, there's memory mapping,
1534	 * execution, and other kernel access paths such as ktrace.  For
1535	 * directories, it is less clear.
1536	 */
1537	if (cp->c_ovp == NULL) {
1538		opened_internally = 1;
1539		MARK_INT_GEN(CODA_OPEN_STATS);
1540		error = VOP_OPEN(vp, FREAD, cred, td, NULL);
1541		printf("coda_readdir: Internally Opening %p\n", vp);
1542		if (error) {
1543			printf("coda_readdir: VOP_OPEN on container failed "
1544			   "%d\n", error);
1545			return (error);
1546		}
1547	}
1548
1549	/*
1550	 * Have UFS handle the call.
1551	 */
1552	CODADEBUG(CODA_READDIR, myprintf(("indirect readdir: fid = %s, "
1553	    "refcnt = %d\n", coda_f2s(&cp->c_fid), vp->v_usecount)););
1554	vn_lock(cp->c_ovp, LK_EXCLUSIVE | LK_RETRY);
1555	error = VOP_READDIR(cp->c_ovp, uiop, cred, eofflag, ncookies,
1556	    cookies);
1557	VOP_UNLOCK(cp->c_ovp, 0);
1558	if (error)
1559		MARK_INT_FAIL(CODA_READDIR_STATS);
1560	else
1561		MARK_INT_SAT(CODA_READDIR_STATS);
1562
1563	/*
1564	 * Do an "internal close" if necessary.
1565	 */
1566	if (opened_internally) {
1567		MARK_INT_GEN(CODA_CLOSE_STATS);
1568		(void)VOP_CLOSE(vp, FREAD, cred, td);
1569	}
1570	return (error);
1571}
1572
1573int
1574coda_reclaim(struct vop_reclaim_args *ap)
1575{
1576	/* true args */
1577	struct vnode *vp = ap->a_vp;
1578	struct cnode *cp = VTOC(vp);
1579	/* upcall decl */
1580	/* locals */
1581
1582	/*
1583	 * Forced unmount/flush will let vnodes with non-zero use be
1584	 * destroyed!
1585	 */
1586	ENTRY;
1587
1588	if (IS_UNMOUNTING(cp)) {
1589#ifdef	DEBUG
1590		if (VTOC(vp)->c_ovp) {
1591			if (IS_UNMOUNTING(cp))
1592				printf("coda_reclaim: c_ovp not void: vp "
1593				    "%p, cp %p\n", vp, cp);
1594		}
1595#endif
1596	} else {
1597#ifdef OLD_DIAGNOSTIC
1598		if (vrefcnt(vp) != 0)
1599			print("coda_reclaim: pushing active %p\n", vp);
1600		if (VTOC(vp)->c_ovp)
1601			panic("coda_reclaim: c_ovp not void");
1602#endif
1603	}
1604	cache_purge(vp);
1605	coda_free(VTOC(vp));
1606	vp->v_data = NULL;
1607	vp->v_object = NULL;
1608	return (0);
1609}
1610
1611int
1612coda_lock(struct vop_lock1_args *ap)
1613{
1614	/* true args */
1615	struct vnode *vp = ap->a_vp;
1616	struct cnode *cp = VTOC(vp);
1617	/* upcall decl */
1618	/* locals */
1619
1620	ENTRY;
1621	if ((ap->a_flags & LK_INTERLOCK) == 0) {
1622		VI_LOCK(vp);
1623		ap->a_flags |= LK_INTERLOCK;
1624	}
1625	if (coda_lockdebug)
1626		myprintf(("Attempting lock on %s\n", coda_f2s(&cp->c_fid)));
1627	return (vop_stdlock(ap));
1628}
1629
1630int
1631coda_unlock(struct vop_unlock_args *ap)
1632{
1633	/* true args */
1634	struct vnode *vp = ap->a_vp;
1635	struct cnode *cp = VTOC(vp);
1636	/* upcall decl */
1637	/* locals */
1638
1639	ENTRY;
1640	if (coda_lockdebug)
1641		myprintf(("Attempting unlock on %s\n",
1642		    coda_f2s(&cp->c_fid)));
1643	return (vop_stdunlock(ap));
1644}
1645
1646int
1647coda_islocked(struct vop_islocked_args *ap)
1648{
1649	/* true args */
1650
1651	ENTRY;
1652	return (vop_stdislocked(ap));
1653}
1654
1655static void
1656coda_print_vattr(struct vattr *attr)
1657{
1658	char *typestr;
1659
1660	switch (attr->va_type) {
1661	case VNON:
1662		typestr = "VNON";
1663		break;
1664
1665	case VREG:
1666		typestr = "VREG";
1667		break;
1668
1669	case VDIR:
1670		typestr = "VDIR";
1671		break;
1672
1673	case VBLK:
1674		typestr = "VBLK";
1675		break;
1676
1677	case VCHR:
1678		typestr = "VCHR";
1679		break;
1680
1681	case VLNK:
1682		typestr = "VLNK";
1683		break;
1684
1685	case VSOCK:
1686		typestr = "VSCK";
1687		break;
1688
1689	case VFIFO:
1690		typestr = "VFFO";
1691		break;
1692
1693	case VBAD:
1694		typestr = "VBAD";
1695		break;
1696
1697	default:
1698		typestr = "????";
1699		break;
1700	}
1701	myprintf(("attr: type %s mode %d uid %d gid %d fsid %d rdev %d\n",
1702	    typestr, (int)attr->va_mode, (int)attr->va_uid,
1703	    (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev));
1704	myprintf(("      fileid %d nlink %d size %d blocksize %d bytes %d\n",
1705	    (int)attr->va_fileid, (int)attr->va_nlink, (int)attr->va_size,
1706	    (int)attr->va_blocksize,(int)attr->va_bytes));
1707	myprintf(("      gen %ld flags %ld vaflags %d\n", attr->va_gen,
1708	    attr->va_flags, attr->va_vaflags));
1709	myprintf(("      atime sec %d nsec %d\n", (int)attr->va_atime.tv_sec,
1710	    (int)attr->va_atime.tv_nsec));
1711	myprintf(("      mtime sec %d nsec %d\n", (int)attr->va_mtime.tv_sec,
1712	    (int)attr->va_mtime.tv_nsec));
1713	myprintf(("      ctime sec %d nsec %d\n", (int)attr->va_ctime.tv_sec,
1714	    (int)attr->va_ctime.tv_nsec));
1715}
1716
1717/*
1718 * How to print a ucred.
1719 */
1720void
1721coda_print_cred(struct ucred *cred)
1722{
1723	int i;
1724
1725	myprintf(("ref %d\tuid %d\n",cred->cr_ref,cred->cr_uid));
1726	for (i=0; i < cred->cr_ngroups; i++)
1727		myprintf(("\tgroup %d: (%d)\n",i,cred->cr_groups[i]));
1728	myprintf(("\n"));
1729}
1730
1731/*
1732 * Return a vnode for the given fid.  If no cnode exists for this fid create
1733 * one and put it in a table hashed by coda_f2i().  If the cnode for this fid
1734 * is already in the table return it (ref count is incremented by coda_find.
1735 * The cnode will be flushed from the table when coda_inactive calls
1736 * coda_unsave.
1737 */
1738struct cnode *
1739make_coda_node(CodaFid *fid, struct mount *vfsp, short type)
1740{
1741	struct cnode *cp;
1742	int err;
1743
1744	if ((cp = coda_find(fid)) == NULL) {
1745		struct vnode *vp;
1746
1747		cp = coda_alloc();
1748		cp->c_fid = *fid;
1749		err = getnewvnode("coda", vfsp, &coda_vnodeops, &vp);
1750		if (err)
1751			panic("coda: getnewvnode returned error %d\n", err);
1752
1753		/*
1754		 * XXX: Too early for mpsafe fs.
1755		 */
1756		err = insmntque1(vp, vfsp, NULL, NULL);
1757		if (err != 0)
1758			panic("coda: insmntque failed: error %d", err);
1759		vp->v_data = cp;
1760		vp->v_type = type;
1761		cp->c_vnode = vp;
1762		coda_save(cp);
1763	} else
1764		vref(CTOV(cp));
1765	return (cp);
1766}
1767
1768int
1769coda_pathconf(struct vop_pathconf_args *ap)
1770{
1771	int error;
1772	register_t *retval;
1773
1774	retval = ap->a_retval;
1775	error = 0;
1776	switch (ap->a_name) {
1777	case _PC_NAME_MAX:
1778		*retval = CODA_MAXNAMLEN;
1779		break;
1780	case _PC_PATH_MAX:
1781		*retval = CODA_MAXPATHLEN;
1782		break;
1783	default:
1784		error = vop_stdpathconf(ap);
1785		break;
1786	}
1787	return (error);
1788}
1789