xref: /netbsd-src/sys/coda/coda_vnops.c (revision 93f9db1b75d415b78f73ed629beeb86235153473)
1 /*
2 coda_create/vn_open
3 remove/unlink
4 link
5 mkdir
6 rmdir
7 symlink
8 */
9 /*	$NetBSD: coda_vnops.c,v 1.8 1998/11/09 16:36:16 rvb Exp $	*/
10 
11 /*
12  *
13  *             Coda: an Experimental Distributed File System
14  *                              Release 3.1
15  *
16  *           Copyright (c) 1987-1998 Carnegie Mellon University
17  *                          All Rights Reserved
18  *
19  * Permission  to  use, copy, modify and distribute this software and its
20  * documentation is hereby granted,  provided  that  both  the  copyright
21  * notice  and  this  permission  notice  appear  in  all  copies  of the
22  * software, derivative works or  modified  versions,  and  any  portions
23  * thereof, and that both notices appear in supporting documentation, and
24  * that credit is given to Carnegie Mellon University  in  all  documents
25  * and publicity pertaining to direct or indirect use of this code or its
26  * derivatives.
27  *
28  * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
29  * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
30  * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
31  * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
32  * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
33  * ANY DERIVATIVE WORK.
34  *
35  * Carnegie  Mellon  encourages  users  of  this  software  to return any
36  * improvements or extensions that  they  make,  and  to  grant  Carnegie
37  * Mellon the rights to redistribute these changes without encumbrance.
38  *
39  * 	@(#) coda/coda_vnops.c,v 1.1.1.1 1998/08/29 21:26:46 rvb Exp $
40  */
41 
42 /*
43  * Mach Operating System
44  * Copyright (c) 1990 Carnegie-Mellon University
45  * Copyright (c) 1989 Carnegie-Mellon University
46  * All rights reserved.  The CMU software License Agreement specifies
47  * the terms and conditions for use and redistribution.
48  */
49 
50 /*
51  * This code was written for the Coda file system at Carnegie Mellon
52  * University.  Contributers include David Steere, James Kistler, and
53  * M. Satyanarayanan.
54  */
55 
56 /*
57  * HISTORY
58  * $Log: coda_vnops.c,v $
59  * Revision 1.8  1998/11/09 16:36:16  rvb
60  * Change the way unmounting happens to guarantee that the
61  * client programs are allowed to finish up (coda_call is
62  * forced to complete) and release their locks.  Thus there
63  * is a reasonable chance that the vflush implicit in the
64  * unmount will not get hung on held locks.
65  *
66  * Revision 1.7  1998/09/28 17:55:22  rvb
67  * I want to distinguish from DEBUG printouts and CODA_VERBOSE printouts.
68  * The latter are normal informational messages that are sometimes
69  * interesting to view.
70  *
71  * Revision 1.6  1998/09/26 15:24:47  tv
72  * DIAGNOSTIC -> DEBUG for all non-panic messages.  DIAGNOSTIC is only for
73  * sanity checks and should not turn on any messages not already printed
74  * without it.
75  *
76  * Revision 1.5  1998/09/25 15:01:13  rvb
77  * Conditionalize "stray" printouts under DIAGNOSTIC and DEBUG.
78  * Make files compile if DEBUG is on (from  Alan Barrett).  Finally,
79  * make coda an lkm.
80  *
81  * Revision 1.4  1998/09/15 02:03:00  rvb
82  * Final piece of rename cfs->coda
83  *
84  * Revision 1.3  1998/09/12 15:05:49  rvb
85  * Change cfs/CFS in symbols, strings and constants to coda/CODA
86  * to avoid fs conflicts.
87  *
88  * Revision 1.2  1998/09/08 17:12:48  rvb
89  * Pass2 complete
90  *
91  * Revision 1.1.1.1  1998/08/29 21:26:46  rvb
92  * Very Preliminary Coda
93  *
94  * Revision 1.12  1998/08/28 18:28:00  rvb
95  * NetBSD -current is stricter!
96  *
97  * Revision 1.11  1998/08/28 18:12:23  rvb
98  * Now it also works on FreeBSD -current.  This code will be
99  * committed to the FreeBSD -current and NetBSD -current
100  * trees.  It will then be tailored to the particular platform
101  * by flushing conditional code.
102  *
103  * Revision 1.10  1998/08/18 17:05:21  rvb
104  * Don't use __RCSID now
105  *
106  * Revision 1.9  1998/08/18 16:31:46  rvb
107  * Sync the code for NetBSD -current; test on 1.3 later
108  *
109  * Revision 1.8  98/02/24  22:22:50  rvb
110  * Fixes up mainly to flush iopen and friends
111  *
112  * Revision 1.7  98/01/31  20:53:15  rvb
113  * First version that works on FreeBSD 2.2.5
114  *
115  * Revision 1.6  98/01/23  11:53:47  rvb
116  * Bring RVB_CODA1_1 to HEAD
117  *
118  * Revision 1.5.2.8  98/01/23  11:21:11  rvb
119  * Sync with 2.2.5
120  *
121  * Revision 1.5.2.7  97/12/19  14:26:08  rvb
122  * session id
123  *
124  * Revision 1.5.2.6  97/12/16  22:01:34  rvb
125  * Oops add cfs_subr.h cfs_venus.h; sync with peter
126  *
127  * Revision 1.5.2.5  97/12/16  12:40:14  rvb
128  * Sync with 1.3
129  *
130  * Revision 1.5.2.4  97/12/10  14:08:31  rvb
131  * Fix O_ flags; check result in coda_call
132  *
133  * Revision 1.5.2.3  97/12/10  11:40:27  rvb
134  * No more ody
135  *
136  * Revision 1.5.2.2  97/12/09  16:07:15  rvb
137  * Sync with vfs/include/coda.h
138  *
139  * Revision 1.5.2.1  97/12/06  17:41:25  rvb
140  * Sync with peters coda.h
141  *
142  * Revision 1.5  97/12/05  10:39:23  rvb
143  * Read CHANGES
144  *
145  * Revision 1.4.14.10  97/11/25  08:08:48  rvb
146  * cfs_venus ... done; until cred/vattr change
147  *
148  * Revision 1.4.14.9  97/11/24  15:44:48  rvb
149  * Final cfs_venus.c w/o macros, but one locking bug
150  *
151  * Revision 1.4.14.8  97/11/21  11:28:04  rvb
152  * cfs_venus.c is done: first pass
153  *
154  * Revision 1.4.14.7  97/11/20  11:46:51  rvb
155  * Capture current cfs_venus
156  *
157  * Revision 1.4.14.6  97/11/18  10:27:19  rvb
158  * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c
159  * cfs_nb_foo and cfs_foo are joined
160  *
161  * Revision 1.4.14.5  97/11/13  22:03:03  rvb
162  * pass2 cfs_NetBSD.h mt
163  *
164  * Revision 1.4.14.4  97/11/12  12:09:42  rvb
165  * reorg pass1
166  *
167  * Revision 1.4.14.3  97/11/06  21:03:28  rvb
168  * don't include headers in headers
169  *
170  * Revision 1.4.14.2  97/10/29  16:06:30  rvb
171  * Kill DYING
172  *
173  * Revision 1.4.14.1  1997/10/28 23:10:18  rvb
174  * >64Meg; venus can be killed!
175  *
176  * Revision 1.4  1997/02/20 13:54:50  lily
177  * check for NULL return from coda_nc_lookup before CTOV
178  *
179  * Revision 1.3  1996/12/12 22:11:02  bnoble
180  * Fixed the "downcall invokes venus operation" deadlock in all known cases.
181  * There may be more
182  *
183  * Revision 1.2  1996/01/02 16:57:07  bnoble
184  * Added support for Coda MiniCache and raw inode calls (final commit)
185  *
186  * Revision 1.1.2.1  1995/12/20 01:57:34  bnoble
187  * Added CODA-specific files
188  *
189  * Revision 3.1.1.1  1995/03/04  19:08:06  bnoble
190  * Branch for NetBSD port revisions
191  *
192  * Revision 3.1  1995/03/04  19:08:04  bnoble
193  * Bump to major revision 3 to prepare for NetBSD port
194  *
195  * Revision 2.6  1995/02/17  16:25:26  dcs
196  * These versions represent several changes:
197  * 1. Allow venus to restart even if outstanding references exist.
198  * 2. Have only one ctlvp per client, as opposed to one per mounted cfs device.d
199  * 3. Allow ody_expand to return many members, not just one.
200  *
201  * Revision 2.5  94/11/09  20:29:27  dcs
202  * Small bug in remove dealing with hard links and link counts was fixed.
203  *
204  * Revision 2.4  94/10/14  09:58:42  dcs
205  * Made changes 'cause sun4s have braindead compilers
206  *
207  * Revision 2.3  94/10/12  16:46:37  dcs
208  * Cleaned kernel/venus interface by removing XDR junk, plus
209  * so cleanup to allow this code to be more easily ported.
210  *
211  * Revision 2.2  94/09/20  14:12:41  dcs
212  * Fixed bug in rename when moving a directory.
213  *
214  * Revision 2.1  94/07/21  16:25:22  satya
215  * Conversion to C++ 3.0; start of Coda Release 2.0
216  *
217  * Revision 1.4  93/12/17  01:38:01  luqi
218  * Changes made for kernel to pass process info to Venus:
219  *
220  * (1) in file cfs.h
221  * add process id and process group id in most of the cfs argument types.
222  *
223  * (2) in file cfs_vnodeops.c
224  * add process info passing in most of the cfs vnode operations.
225  *
226  * (3) in file cfs_xdr.c
227  * expand xdr routines according changes in (1).
228  * add variable pass_process_info to allow venus for kernel version checking.
229  *
230  * Revision 1.3  93/05/28  16:24:33  bnoble
231  * *** empty log message ***
232  *
233  * Revision 1.2  92/10/27  17:58:25  lily
234  * merge kernel/latest and alpha/src/cfs
235  *
236  * Revision 2.4  92/09/30  14:16:37  mja
237  * 	Redid buffer allocation so that it does kmem_{alloc,free} for all
238  * 	architectures.  Zone allocation, previously used on the 386, caused
239  * 	panics if it was invoked repeatedly.  Stack allocation, previously
240  * 	used on all other architectures, tickled some Mach bug that appeared
241  * 	with large stack frames.
242  * 	[91/02/09            jjk]
243  *
244  * 	Added contributors blurb.
245  * 	[90/12/13            jjk]
246  *
247  * Revision 2.3  90/07/26  15:50:09  mrt
248  * 	    Fixed fix to rename to remove .. from moved directories.
249  * 	[90/06/28            dcs]
250  *
251  * Revision 1.7  90/06/28  16:24:25  dcs
252  * Fixed bug with moving directories, we weren't flushing .. for the moved directory.
253  *
254  * Revision 1.6  90/05/31  17:01:47  dcs
255  * Prepare for merge with facilities kernel.
256  *
257  *
258  */
259 
260 #include <sys/param.h>
261 #include <sys/systm.h>
262 #include <sys/malloc.h>
263 #include <sys/errno.h>
264 #include <sys/acct.h>
265 #include <sys/file.h>
266 #include <sys/uio.h>
267 #include <sys/namei.h>
268 #include <sys/ioctl.h>
269 #include <sys/mount.h>
270 #include <sys/proc.h>
271 #include <sys/select.h>
272 #include <sys/user.h>
273 #include <vm/vm.h>
274 #include <miscfs/genfs/genfs.h>
275 
276 #include <coda/coda.h>
277 #include <coda/cnode.h>
278 #include <coda/coda_vnops.h>
279 #include <coda/coda_venus.h>
280 #include <coda/coda_opstats.h>
281 #include <coda/coda_subr.h>
282 #include <coda/coda_namecache.h>
283 #include <coda/coda_pioctl.h>
284 
285 /*
286  * These flags select various performance enhancements.
287  */
288 int coda_attr_cache  = 1;       /* Set to cache attributes in the kernel */
289 int coda_symlink_cache = 1;     /* Set to cache symbolic link information */
290 int coda_access_cache = 1;      /* Set to handle some access checks directly */
291 
292 /* structure to keep track of vfs calls */
293 
294 struct coda_op_stats coda_vnodeopstats[CODA_VNODEOPS_SIZE];
295 
296 #define MARK_ENTRY(op) (coda_vnodeopstats[op].entries++)
297 #define MARK_INT_SAT(op) (coda_vnodeopstats[op].sat_intrn++)
298 #define MARK_INT_FAIL(op) (coda_vnodeopstats[op].unsat_intrn++)
299 #define MARK_INT_GEN(op) (coda_vnodeopstats[op].gen_intrn++)
300 
301 /* What we are delaying for in printf */
302 int coda_printf_delay = 0;  /* in microseconds */
303 int coda_vnop_print_entry = 0;
304 static int coda_lockdebug = 0;
305 
306 /* Definition of the vfs operation vector */
307 
308 /*
309  * Some NetBSD details:
310  *
311  *   coda_start is called at the end of the mount syscall.
312  *   coda_init is called at boot time.
313  */
314 
315 #define ENTRY if(coda_vnop_print_entry) myprintf(("Entered %s\n",__FUNCTION__))
316 
317 /* Definition of the vnode operation vector */
318 
319 struct vnodeopv_entry_desc coda_vnodeop_entries[] = {
320     { &vop_default_desc, coda_vop_error },
321     { &vop_lookup_desc, coda_lookup },		/* lookup */
322     { &vop_create_desc, coda_create },		/* create */
323     { &vop_mknod_desc, coda_vop_error },	/* mknod */
324     { &vop_open_desc, coda_open },		/* open */
325     { &vop_close_desc, coda_close },		/* close */
326     { &vop_access_desc, coda_access },		/* access */
327     { &vop_getattr_desc, coda_getattr },	/* getattr */
328     { &vop_setattr_desc, coda_setattr },	/* setattr */
329     { &vop_read_desc, coda_read },		/* read */
330     { &vop_write_desc, coda_write },		/* write */
331     { &vop_ioctl_desc, coda_ioctl },		/* ioctl */
332 /* 1.3    { &vop_select_desc, coda_select },	select */
333     { &vop_mmap_desc, coda_vop_error },		/* mmap */
334     { &vop_fsync_desc, coda_fsync },		/* fsync */
335     { &vop_remove_desc, coda_remove },		/* remove */
336     { &vop_link_desc, coda_link },		/* link */
337     { &vop_rename_desc, coda_rename },		/* rename */
338     { &vop_mkdir_desc, coda_mkdir },		/* mkdir */
339     { &vop_rmdir_desc, coda_rmdir },		/* rmdir */
340     { &vop_symlink_desc, coda_symlink },	/* symlink */
341     { &vop_readdir_desc, coda_readdir },	/* readdir */
342     { &vop_readlink_desc, coda_readlink },	/* readlink */
343     { &vop_abortop_desc, coda_abortop },	/* abortop */
344     { &vop_inactive_desc, coda_inactive },	/* inactive */
345     { &vop_reclaim_desc, coda_reclaim },	/* reclaim */
346     { &vop_lock_desc, coda_lock },		/* lock */
347     { &vop_unlock_desc, coda_unlock },		/* unlock */
348     { &vop_bmap_desc, coda_bmap },		/* bmap */
349     { &vop_strategy_desc, coda_strategy },	/* strategy */
350     { &vop_print_desc, coda_vop_error },	/* print */
351     { &vop_islocked_desc, coda_islocked },	/* islocked */
352     { &vop_pathconf_desc, coda_vop_error },	/* pathconf */
353     { &vop_advlock_desc, coda_vop_nop },	/* advlock */
354     { &vop_bwrite_desc, coda_vop_error },	/* bwrite */
355     { &vop_lease_desc, coda_vop_nop },		/* lease */
356     { &vop_blkatoff_desc, coda_vop_error },	/* blkatoff */
357     { &vop_valloc_desc, coda_vop_error },	/* valloc */
358     { &vop_vfree_desc, coda_vop_error },	/* vfree */
359     { &vop_truncate_desc, coda_vop_error },	/* truncate */
360     { &vop_update_desc, coda_vop_error },	/* update */
361     { &vop_seek_desc, genfs_seek },		/* seek */
362     { &vop_poll_desc, genfs_poll },		/* poll */
363 
364     { (struct vnodeop_desc*)NULL, (int(*)(void *))NULL }
365 };
366 
367 struct vnodeopv_desc coda_vnodeop_opv_desc =
368         { &coda_vnodeop_p, coda_vnodeop_entries };
369 
370 /* Definitions of NetBSD vnodeop interfaces */
371 
372 /* A generic panic: we were called with something we didn't define yet */
373 int
374 coda_vop_error(void *anon) {
375     struct vnodeop_desc **desc = (struct vnodeop_desc **)anon;
376 
377     myprintf(("Vnode operation %s called, but not defined\n",
378 	      (*desc)->vdesc_name));
379     panic("coda_nbsd_vop_error");
380     return 0;
381 }
382 
383 /* A generic do-nothing.  For lease_check, advlock */
384 int
385 coda_vop_nop(void *anon) {
386     struct vnodeop_desc **desc = (struct vnodeop_desc **)anon;
387 
388     if (codadebug) {
389 	myprintf(("Vnode operation %s called, but unsupported\n",
390 		  (*desc)->vdesc_name));
391     }
392    return (0);
393 }
394 
395 int
396 coda_vnodeopstats_init(void)
397 {
398 	register int i;
399 
400 	for(i=0;i<CODA_VNODEOPS_SIZE;i++) {
401 		coda_vnodeopstats[i].opcode = i;
402 		coda_vnodeopstats[i].entries = 0;
403 		coda_vnodeopstats[i].sat_intrn = 0;
404 		coda_vnodeopstats[i].unsat_intrn = 0;
405 		coda_vnodeopstats[i].gen_intrn = 0;
406 	}
407 
408 	return 0;
409 }
410 
411 /*
412  * coda_open calls Venus to return the device, inode pair of the cache
413  * file holding the data. Using iget, coda_open finds the vnode of the
414  * cache file, and then opens it.
415  */
416 int
417 coda_open(v)
418     void *v;
419 {
420     /*
421      * NetBSD can pass the O_EXCL flag in mode, even though the check
422      * has already happened.  Venus defensively assumes that if open
423      * is passed the EXCL, it must be a bug.  We strip the flag here.
424      */
425 /* true args */
426     struct vop_open_args *ap = v;
427     register struct vnode **vpp = &(ap->a_vp);
428     struct cnode *cp = VTOC(*vpp);
429     int flag = ap->a_mode & (~O_EXCL);
430     struct ucred *cred = ap->a_cred;
431     struct proc *p = ap->a_p;
432 /* locals */
433     int error;
434     struct vnode *vp;
435     dev_t dev;
436     ino_t inode;
437 
438     MARK_ENTRY(CODA_OPEN_STATS);
439 
440     /* Check for open of control file. */
441     if (IS_CTL_VP(*vpp)) {
442 	/* XXX */
443 	/* if (WRITEABLE(flag)) */
444 	if (flag & (FWRITE | O_TRUNC | O_CREAT | O_EXCL)) {
445 	    MARK_INT_FAIL(CODA_OPEN_STATS);
446 	    return(EACCES);
447 	}
448 	MARK_INT_SAT(CODA_OPEN_STATS);
449 	return(0);
450     }
451 
452     error = venus_open(vtomi((*vpp)), &cp->c_fid, flag, cred, p, &dev, &inode);
453     if (error)
454 	return (error);
455     if (!error) {
456 	CODADEBUG( CODA_OPEN,myprintf(("open: dev %d inode %d result %d\n",
457 				  dev, inode, error)); )
458     }
459 
460     /* Translate the <device, inode> pair for the cache file into
461        an inode pointer. */
462     error = coda_grab_vnode(dev, inode, &vp);
463     if (error)
464 	return (error);
465 
466     /* We get the vnode back locked in both Mach and NetBSD.  Needs unlocked */
467     VOP_UNLOCK(vp, 0);
468     /* Keep a reference until the close comes in. */
469     vref(*vpp);
470 
471     /* Save the vnode pointer for the cache file. */
472     if (cp->c_ovp == NULL) {
473 	cp->c_ovp = vp;
474     } else {
475 	if (cp->c_ovp != vp)
476 	    panic("coda_open:  cp->c_ovp != ITOV(ip)");
477     }
478     cp->c_ocount++;
479 
480     /* Flush the attribute cached if writing the file. */
481     if (flag & FWRITE) {
482 	cp->c_owrite++;
483 	cp->c_flags &= ~C_VATTR;
484     }
485 
486     /* Save the <device, inode> pair for the cache file to speed
487        up subsequent page_read's. */
488     cp->c_device = dev;
489     cp->c_inode = inode;
490 
491     /* Open the cache file. */
492     error = VOP_OPEN(vp, flag, cred, p);
493     return(error);
494 }
495 
496 /*
497  * Close the cache file used for I/O and notify Venus.
498  */
499 int
500 coda_close(v)
501     void *v;
502 {
503 /* true args */
504     struct vop_close_args *ap = v;
505     struct vnode *vp = ap->a_vp;
506     struct cnode *cp = VTOC(vp);
507     int flag = ap->a_fflag;
508     struct ucred *cred = ap->a_cred;
509     struct proc *p = ap->a_p;
510 /* locals */
511     int error;
512 
513     MARK_ENTRY(CODA_CLOSE_STATS);
514 
515     /* Check for close of control file. */
516     if (IS_CTL_VP(vp)) {
517 	MARK_INT_SAT(CODA_CLOSE_STATS);
518 	return(0);
519     }
520 
521     if (IS_UNMOUNTING(cp)) {
522 	if (cp->c_ovp) {
523 #ifdef	CODA_VERBOSE
524 	    printf("coda_close: destroying container ref %d, ufs vp %p of vp %p/cp %p\n",
525 		    vp->v_usecount, cp->c_ovp, vp, cp);
526 #endif
527 #ifdef	hmm
528 	    vgone(cp->c_ovp);
529 #else
530 	    VOP_CLOSE(cp->c_ovp, flag, cred, p); /* Do errors matter here? */
531 	    vrele(cp->c_ovp);
532 #endif
533 	} else {
534 #ifdef	CODA_VERBOSE
535 	    printf("coda_close: NO container vp %p/cp %p\n", vp, cp);
536 #endif
537 	}
538 	return ENODEV;
539     } else {
540 	VOP_CLOSE(cp->c_ovp, flag, cred, p); /* Do errors matter here? */
541 	vrele(cp->c_ovp);
542     }
543 
544     if (--cp->c_ocount == 0)
545 	cp->c_ovp = NULL;
546 
547     if (flag & FWRITE)                    /* file was opened for write */
548 	--cp->c_owrite;
549 
550     error = venus_close(vtomi(vp), &cp->c_fid, flag, cred, p);
551     vrele(CTOV(cp));
552 
553     CODADEBUG(CODA_CLOSE, myprintf(("close: result %d\n",error)); )
554     return(error);
555 }
556 
557 int
558 coda_read(v)
559     void *v;
560 {
561     struct vop_read_args *ap = v;
562 
563     ENTRY;
564     return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_READ,
565 		    ap->a_ioflag, ap->a_cred, ap->a_uio->uio_procp));
566 }
567 
568 int
569 coda_write(v)
570     void *v;
571 {
572     struct vop_write_args *ap = v;
573 
574     ENTRY;
575     return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_WRITE,
576 		    ap->a_ioflag, ap->a_cred, ap->a_uio->uio_procp));
577 }
578 
579 int
580 coda_rdwr(vp, uiop, rw, ioflag, cred, p)
581     struct vnode *vp;
582     struct uio *uiop;
583     enum uio_rw rw;
584     int ioflag;
585     struct ucred *cred;
586     struct proc *p;
587 {
588 /* upcall decl */
589   /* NOTE: container file operation!!! */
590 /* locals */
591     struct cnode *cp = VTOC(vp);
592     struct vnode *cfvp = cp->c_ovp;
593     int igot_internally = 0;
594     int opened_internally = 0;
595     int error = 0;
596 
597     MARK_ENTRY(CODA_RDWR_STATS);
598 
599     CODADEBUG(CODA_RDWR, myprintf(("coda_rdwr(%d, %p, %d, %qd, %d)\n", rw,
600 			      uiop->uio_iov->iov_base, uiop->uio_resid,
601 			      uiop->uio_offset, uiop->uio_segflg)); )
602 
603     /* Check for rdwr of control object. */
604     if (IS_CTL_VP(vp)) {
605 	MARK_INT_FAIL(CODA_RDWR_STATS);
606 	return(EINVAL);
607     }
608 
609     /* Redirect the request to UFS. */
610 
611     /*
612      * If file is not already open this must be a page
613      * {read,write} request.  Iget the cache file's inode
614      * pointer if we still have its <device, inode> pair.
615      * Otherwise, we must do an internal open to derive the
616      * pair.
617      */
618     if (cfvp == NULL) {
619 	/*
620 	 * If we're dumping core, do the internal open. Otherwise
621 	 * venus won't have the correct size of the core when
622 	 * it's completely written.
623 	 */
624 	if (cp->c_inode != 0 && !(p && (p->p_acflag & ACORE))) {
625 	    igot_internally = 1;
626 	    error = coda_grab_vnode(cp->c_device, cp->c_inode, &cfvp);
627 	    if (error) {
628 		MARK_INT_FAIL(CODA_RDWR_STATS);
629 		return(error);
630 	    }
631 	    /*
632 	     * We get the vnode back locked in both Mach and
633 	     * NetBSD.  Needs unlocked
634 	     */
635 	    VOP_UNLOCK(cfvp, 0);
636 	}
637 	else {
638 	    opened_internally = 1;
639 	    MARK_INT_GEN(CODA_OPEN_STATS);
640 	    error = VOP_OPEN(vp, (rw == UIO_READ ? FREAD : FWRITE),
641 			     cred, p);
642 printf("coda_rdwr: Internally Opening %p\n", vp);
643 	    if (error) {
644 		MARK_INT_FAIL(CODA_RDWR_STATS);
645 		return(error);
646 	    }
647 	    cfvp = cp->c_ovp;
648 	}
649     }
650 
651     /* Have UFS handle the call. */
652     CODADEBUG(CODA_RDWR, myprintf(("indirect rdwr: fid = (%lx.%lx.%lx), refcnt = %d\n",
653 			      cp->c_fid.Volume, cp->c_fid.Vnode,
654 			      cp->c_fid.Unique, CTOV(cp)->v_usecount)); )
655 
656     if (rw == UIO_READ) {
657 	error = VOP_READ(cfvp, uiop, ioflag, cred);
658     } else {
659 	error = VOP_WRITE(cfvp, uiop, ioflag, cred);
660     }
661 
662     if (error)
663 	MARK_INT_FAIL(CODA_RDWR_STATS);
664     else
665 	MARK_INT_SAT(CODA_RDWR_STATS);
666 
667     /* Do an internal close if necessary. */
668     if (opened_internally) {
669 	MARK_INT_GEN(CODA_CLOSE_STATS);
670 	(void)VOP_CLOSE(vp, (rw == UIO_READ ? FREAD : FWRITE), cred, p);
671     }
672 
673     /* Invalidate cached attributes if writing. */
674     if (rw == UIO_WRITE)
675 	cp->c_flags &= ~C_VATTR;
676     return(error);
677 }
678 
679 int
680 coda_ioctl(v)
681     void *v;
682 {
683 /* true args */
684     struct vop_ioctl_args *ap = v;
685     struct vnode *vp = ap->a_vp;
686     int com = ap->a_command;
687     caddr_t data = ap->a_data;
688     int flag = ap->a_fflag;
689     struct ucred *cred = ap->a_cred;
690     struct proc  *p = ap->a_p;
691 /* locals */
692     int error;
693     struct vnode *tvp;
694     struct nameidata ndp;
695     struct PioctlData *iap = (struct PioctlData *)data;
696 
697     MARK_ENTRY(CODA_IOCTL_STATS);
698 
699     CODADEBUG(CODA_IOCTL, myprintf(("in coda_ioctl on %s\n", iap->path));)
700 
701     /* Don't check for operation on a dying object, for ctlvp it
702        shouldn't matter */
703 
704     /* Must be control object to succeed. */
705     if (!IS_CTL_VP(vp)) {
706 	MARK_INT_FAIL(CODA_IOCTL_STATS);
707 	CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: vp != ctlvp"));)
708 	    return (EOPNOTSUPP);
709     }
710     /* Look up the pathname. */
711 
712     /* Should we use the name cache here? It would get it from
713        lookupname sooner or later anyway, right? */
714 
715     NDINIT(&ndp, LOOKUP, (iap->follow ? FOLLOW : NOFOLLOW), UIO_USERSPACE, ((caddr_t)iap->path), p);
716     error = namei(&ndp);
717     tvp = ndp.ni_vp;
718 
719     if (error) {
720 	MARK_INT_FAIL(CODA_IOCTL_STATS);
721 	CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: lookup returns %d\n",
722 				   error));)
723 	return(error);
724     }
725 
726     /*
727      * Make sure this is a coda style cnode, but it may be a
728      * different vfsp
729      */
730     /* XXX: this totally violates the comment about vtagtype in vnode.h */
731     if (tvp->v_tag != VT_CODA) {
732 	vrele(tvp);
733 	MARK_INT_FAIL(CODA_IOCTL_STATS);
734 	CODADEBUG(CODA_IOCTL,
735 		 myprintf(("coda_ioctl error: %s not a coda object\n",
736 			iap->path));)
737 	return(EINVAL);
738     }
739 
740     if (iap->vi.in_size > VC_MAXDATASIZE) {
741 	vrele(tvp);
742 	return(EINVAL);
743     }
744     error = venus_ioctl(vtomi(tvp), &((VTOC(tvp))->c_fid), com, flag, data, cred, p);
745 
746     if (error)
747 	MARK_INT_FAIL(CODA_IOCTL_STATS);
748     else
749 	CODADEBUG(CODA_IOCTL, myprintf(("Ioctl returns %d \n", error)); )
750 
751     vrele(tvp);
752     return(error);
753 }
754 
755 /*
756  * To reduce the cost of a user-level venus;we cache attributes in
757  * the kernel.  Each cnode has storage allocated for an attribute. If
758  * c_vattr is valid, return a reference to it. Otherwise, get the
759  * attributes from venus and store them in the cnode.  There is some
760  * question if this method is a security leak. But I think that in
761  * order to make this call, the user must have done a lookup and
762  * opened the file, and therefore should already have access.
763  */
764 int
765 coda_getattr(v)
766     void *v;
767 {
768 /* true args */
769     struct vop_getattr_args *ap = v;
770     struct vnode *vp = ap->a_vp;
771     struct cnode *cp = VTOC(vp);
772     struct vattr *vap = ap->a_vap;
773     struct ucred *cred = ap->a_cred;
774     struct proc *p = ap->a_p;
775 /* locals */
776     int error;
777 
778     MARK_ENTRY(CODA_GETATTR_STATS);
779 
780     /* Check for getattr of control object. */
781     if (IS_CTL_VP(vp)) {
782 	MARK_INT_FAIL(CODA_GETATTR_STATS);
783 	return(ENOENT);
784     }
785 
786     /* Check to see if the attributes have already been cached */
787     if (VALID_VATTR(cp)) {
788 	CODADEBUG(CODA_GETATTR, { myprintf(("attr cache hit: (%lx.%lx.%lx)\n",
789 				       cp->c_fid.Volume,
790 				       cp->c_fid.Vnode,
791 				       cp->c_fid.Unique));});
792 	CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
793 		 print_vattr(&cp->c_vattr); );
794 
795 	*vap = cp->c_vattr;
796 	MARK_INT_SAT(CODA_GETATTR_STATS);
797 	return(0);
798     }
799 
800     error = venus_getattr(vtomi(vp), &cp->c_fid, cred, p, vap);
801 
802     if (!error) {
803 	CODADEBUG(CODA_GETATTR, myprintf(("getattr miss (%lx.%lx.%lx): result %d\n",
804 				     cp->c_fid.Volume,
805 				     cp->c_fid.Vnode,
806 				     cp->c_fid.Unique,
807 				     error)); )
808 
809 	CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
810 		 print_vattr(vap);	);
811 
812 	/* If not open for write, store attributes in cnode */
813 	if ((cp->c_owrite == 0) && (coda_attr_cache)) {
814 	    cp->c_vattr = *vap;
815 	    cp->c_flags |= C_VATTR;
816 	}
817 
818     }
819     return(error);
820 }
821 
822 int
823 coda_setattr(v)
824     void *v;
825 {
826 /* true args */
827     struct vop_setattr_args *ap = v;
828     register struct vnode *vp = ap->a_vp;
829     struct cnode *cp = VTOC(vp);
830     register struct vattr *vap = ap->a_vap;
831     struct ucred *cred = ap->a_cred;
832     struct proc *p = ap->a_p;
833 /* locals */
834     int error;
835 
836     MARK_ENTRY(CODA_SETATTR_STATS);
837 
838     /* Check for setattr of control object. */
839     if (IS_CTL_VP(vp)) {
840 	MARK_INT_FAIL(CODA_SETATTR_STATS);
841 	return(ENOENT);
842     }
843 
844     if (codadebug & CODADBGMSK(CODA_SETATTR)) {
845 	print_vattr(vap);
846     }
847     error = venus_setattr(vtomi(vp), &cp->c_fid, vap, cred, p);
848 
849     if (!error)
850 	cp->c_flags &= ~C_VATTR;
851 
852     CODADEBUG(CODA_SETATTR,	myprintf(("setattr %d\n", error)); )
853     return(error);
854 }
855 
856 int
857 coda_access(v)
858     void *v;
859 {
860 /* true args */
861     struct vop_access_args *ap = v;
862     struct vnode *vp = ap->a_vp;
863     struct cnode *cp = VTOC(vp);
864     int mode = ap->a_mode;
865     struct ucred *cred = ap->a_cred;
866     struct proc *p = ap->a_p;
867 /* locals */
868     int error;
869 
870     MARK_ENTRY(CODA_ACCESS_STATS);
871 
872     /* Check for access of control object.  Only read access is
873        allowed on it. */
874     if (IS_CTL_VP(vp)) {
875 	/* bogus hack - all will be marked as successes */
876 	MARK_INT_SAT(CODA_ACCESS_STATS);
877 	return(((mode & VREAD) && !(mode & (VWRITE | VEXEC)))
878 	       ? 0 : EACCES);
879     }
880 
881     /*
882      * if the file is a directory, and we are checking exec (eg lookup)
883      * access, and the file is in the namecache, then the user must have
884      * lookup access to it.
885      */
886     if (coda_access_cache) {
887 	if ((vp->v_type == VDIR) && (mode & VEXEC)) {
888 	    if (coda_nc_lookup(cp, ".", 1, cred)) {
889 		MARK_INT_SAT(CODA_ACCESS_STATS);
890 		return(0);                     /* it was in the cache */
891 	    }
892 	}
893     }
894 
895     error = venus_access(vtomi(vp), &cp->c_fid, mode, cred, p);
896 
897     return(error);
898 }
899 
900 /*
901  * CODA abort op, called after namei() when a CREATE/DELETE isn't actually
902  * done. If a buffer has been saved in anticipation of a coda_create or
903  * a coda_remove, delete it.
904  */
905 /* ARGSUSED */
906 int
907 coda_abortop(v)
908     void *v;
909 {
910 /* true args */
911     struct vop_abortop_args /* {
912 	struct vnode *a_dvp;
913 	struct componentname *a_cnp;
914     } */ *ap = v;
915 /* upcall decl */
916 /* locals */
917 
918     if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
919 	FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
920     return (0);
921 }
922 
923 int
924 coda_readlink(v)
925     void *v;
926 {
927 /* true args */
928     struct vop_readlink_args *ap = v;
929     struct vnode *vp = ap->a_vp;
930     struct cnode *cp = VTOC(vp);
931     struct uio *uiop = ap->a_uio;
932     struct ucred *cred = ap->a_cred;
933     struct proc *p = ap->a_uio->uio_procp;
934 /* locals */
935     int error;
936     char *str;
937     int len;
938 
939     MARK_ENTRY(CODA_READLINK_STATS);
940 
941     /* Check for readlink of control object. */
942     if (IS_CTL_VP(vp)) {
943 	MARK_INT_FAIL(CODA_READLINK_STATS);
944 	return(ENOENT);
945     }
946 
947     if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) { /* symlink was cached */
948 	uiop->uio_rw = UIO_READ;
949 	error = uiomove(cp->c_symlink, (int)cp->c_symlen, uiop);
950 	if (error)
951 	    MARK_INT_FAIL(CODA_READLINK_STATS);
952 	else
953 	    MARK_INT_SAT(CODA_READLINK_STATS);
954 	return(error);
955     }
956 
957     error = venus_readlink(vtomi(vp), &cp->c_fid, cred, p, &str, &len);
958 
959     if (!error) {
960 	uiop->uio_rw = UIO_READ;
961 	error = uiomove(str, len, uiop);
962 
963 	if (coda_symlink_cache) {
964 	    cp->c_symlink = str;
965 	    cp->c_symlen = len;
966 	    cp->c_flags |= C_SYMLINK;
967 	} else
968 	    CODA_FREE(str, len);
969     }
970 
971     CODADEBUG(CODA_READLINK, myprintf(("in readlink result %d\n",error));)
972     return(error);
973 }
974 
975 int
976 coda_fsync(v)
977     void *v;
978 {
979 /* true args */
980     struct vop_fsync_args *ap = v;
981     struct vnode *vp = ap->a_vp;
982     struct cnode *cp = VTOC(vp);
983     struct ucred *cred = ap->a_cred;
984     struct proc *p = ap->a_p;
985 /* locals */
986     struct vnode *convp = cp->c_ovp;
987     int error;
988 
989     MARK_ENTRY(CODA_FSYNC_STATS);
990 
991     /* Check for fsync on an unmounting object */
992     /* The NetBSD kernel, in it's infinite wisdom, can try to fsync
993      * after an unmount has been initiated.  This is a Bad Thing,
994      * which we have to avoid.  Not a legitimate failure for stats.
995      */
996     if (IS_UNMOUNTING(cp)) {
997 	return(ENODEV);
998     }
999 
1000     /* Check for fsync of control object. */
1001     if (IS_CTL_VP(vp)) {
1002 	MARK_INT_SAT(CODA_FSYNC_STATS);
1003 	return(0);
1004     }
1005 
1006     if (convp)
1007     	VOP_FSYNC(convp, cred, MNT_WAIT, p);
1008 
1009     /*
1010      * We can expect fsync on any vnode at all if venus is pruging it.
1011      * Venus can't very well answer the fsync request, now can it?
1012      * Hopefully, it won't have to, because hopefully, venus preserves
1013      * the (possibly untrue) invariant that it never purges an open
1014      * vnode.  Hopefully.
1015      */
1016     if (cp->c_flags & C_PURGING) {
1017 	return(0);
1018     }
1019 
1020     error = venus_fsync(vtomi(vp), &cp->c_fid, cred, p);
1021 
1022     CODADEBUG(CODA_FSYNC, myprintf(("in fsync result %d\n",error)); );
1023     return(error);
1024 }
1025 
1026 int
1027 coda_inactive(v)
1028     void *v;
1029 {
1030     /* XXX - at the moment, inactive doesn't look at cred, and doesn't
1031        have a proc pointer.  Oops. */
1032 /* true args */
1033     struct vop_inactive_args *ap = v;
1034     struct vnode *vp = ap->a_vp;
1035     struct cnode *cp = VTOC(vp);
1036     struct ucred *cred __attribute__((unused)) = NULL;
1037     struct proc *p __attribute__((unused)) = curproc;
1038 /* upcall decl */
1039 /* locals */
1040 
1041     /* We don't need to send inactive to venus - DCS */
1042     MARK_ENTRY(CODA_INACTIVE_STATS);
1043 
1044     if (IS_CTL_VP(vp)) {
1045 	MARK_INT_SAT(CODA_INACTIVE_STATS);
1046 	return 0;
1047     }
1048 
1049     CODADEBUG(CODA_INACTIVE, myprintf(("in inactive, %lx.%lx.%lx. vfsp %p\n",
1050 				  cp->c_fid.Volume, cp->c_fid.Vnode,
1051 				  cp->c_fid.Unique, vp->v_mount));)
1052 
1053     /* If an array has been allocated to hold the symlink, deallocate it */
1054     if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) {
1055 	if (cp->c_symlink == NULL)
1056 	    panic("coda_inactive: null symlink pointer in cnode");
1057 
1058 	CODA_FREE(cp->c_symlink, cp->c_symlen);
1059 	cp->c_flags &= ~C_SYMLINK;
1060 	cp->c_symlen = 0;
1061     }
1062 
1063     /* Remove it from the table so it can't be found. */
1064     coda_unsave(cp);
1065     if ((struct coda_mntinfo *)(vp->v_mount->mnt_data) == NULL) {
1066 	myprintf(("Help! vfsp->vfs_data was NULL, but vnode %p wasn't dying\n", vp));
1067 	panic("badness in coda_inactive\n");
1068     }
1069 
1070     if (IS_UNMOUNTING(cp)) {
1071 #ifdef	DEBUG
1072 	printf("coda_inactive: IS_UNMOUNTING use %d: vp %p, cp %p\n", vp->v_usecount, vp, cp);
1073 	if (cp->c_ovp != NULL)
1074 	    printf("coda_inactive: cp->ovp != NULL use %d: vp %p, cp %p\n",
1075 	    	   vp->v_usecount, vp, cp);
1076 #endif
1077 	lockmgr(&cp->c_lock, LK_RELEASE, &vp->v_interlock);
1078     } else {
1079 #ifdef OLD_DIAGNOSTIC
1080 	if (CTOV(cp)->v_usecount) {
1081 	    panic("coda_inactive: nonzero reference count");
1082 	}
1083 	if (cp->c_ovp != NULL) {
1084 	    panic("coda_inactive:  cp->ovp != NULL");
1085 	}
1086 #endif
1087 	VOP_UNLOCK(vp, 0);
1088 	vgone(vp);
1089     }
1090 
1091     MARK_INT_SAT(CODA_INACTIVE_STATS);
1092     return(0);
1093 }
1094 
1095 /*
1096  * Remote file system operations having to do with directory manipulation.
1097  */
1098 
1099 /*
1100  * It appears that in NetBSD, lookup is supposed to return the vnode locked
1101  */
1102 int
1103 coda_lookup(v)
1104     void *v;
1105 {
1106 /* true args */
1107     struct vop_lookup_args *ap = v;
1108     struct vnode *dvp = ap->a_dvp;
1109     struct cnode *dcp = VTOC(dvp);
1110     struct vnode **vpp = ap->a_vpp;
1111     /*
1112      * It looks as though ap->a_cnp->ni_cnd->cn_nameptr holds the rest
1113      * of the string to xlate, and that we must try to get at least
1114      * ap->a_cnp->ni_cnd->cn_namelen of those characters to macth.  I
1115      * could be wrong.
1116      */
1117     struct componentname  *cnp = ap->a_cnp;
1118     struct ucred *cred = cnp->cn_cred;
1119     struct proc *p = cnp->cn_proc;
1120 /* locals */
1121     struct cnode *cp;
1122     const char *nm = cnp->cn_nameptr;
1123     int len = cnp->cn_namelen;
1124     ViceFid VFid;
1125     int	vtype;
1126     int error = 0;
1127 
1128     MARK_ENTRY(CODA_LOOKUP_STATS);
1129 
1130     CODADEBUG(CODA_LOOKUP, myprintf(("lookup: %s in %lx.%lx.%lx\n",
1131 				   nm, dcp->c_fid.Volume,
1132 				   dcp->c_fid.Vnode, dcp->c_fid.Unique)););
1133 
1134     /* Check for lookup of control object. */
1135     if (IS_CTL_NAME(dvp, nm, len)) {
1136 	*vpp = coda_ctlvp;
1137 	vref(*vpp);
1138 	MARK_INT_SAT(CODA_LOOKUP_STATS);
1139 	goto exit;
1140     }
1141 
1142     if (len+1 > CODA_MAXNAMLEN) {
1143 	MARK_INT_FAIL(CODA_LOOKUP_STATS);
1144 	CODADEBUG(CODA_LOOKUP, myprintf(("name too long: lookup, %lx.%lx.%lx(%s)\n",
1145 				    dcp->c_fid.Volume, dcp->c_fid.Vnode,
1146 				    dcp->c_fid.Unique, nm)););
1147 	*vpp = (struct vnode *)0;
1148 	error = EINVAL;
1149 	goto exit;
1150     }
1151     /* First try to look the file up in the cfs name cache */
1152     /* lock the parent vnode? */
1153     cp = coda_nc_lookup(dcp, nm, len, cred);
1154     if (cp) {
1155 	*vpp = CTOV(cp);
1156 	vref(*vpp);
1157 	CODADEBUG(CODA_LOOKUP,
1158 		 myprintf(("lookup result %d vpp %p\n",error,*vpp));)
1159     } else {
1160 
1161 	/* The name wasn't cached, so we need to contact Venus */
1162 	error = venus_lookup(vtomi(dvp), &dcp->c_fid, nm, len, cred, p, &VFid, &vtype);
1163 
1164 	if (error) {
1165 	    MARK_INT_FAIL(CODA_LOOKUP_STATS);
1166 	    CODADEBUG(CODA_LOOKUP, myprintf(("lookup error on %lx.%lx.%lx(%s)%d\n",
1167 					dcp->c_fid.Volume, dcp->c_fid.Vnode, dcp->c_fid.Unique, nm, error));)
1168 	    *vpp = (struct vnode *)0;
1169 	} else {
1170 	    MARK_INT_SAT(CODA_LOOKUP_STATS);
1171 	    CODADEBUG(CODA_LOOKUP,
1172 		     myprintf(("lookup: vol %lx vno %lx uni %lx type %o result %d\n",
1173 			    VFid.Volume, VFid.Vnode, VFid.Unique, vtype,
1174 			    error)); )
1175 
1176 	    cp = make_coda_node(&VFid, dvp->v_mount, vtype);
1177 	    *vpp = CTOV(cp);
1178 
1179 	    /* enter the new vnode in the Name Cache only if the top bit isn't set */
1180 	    /* And don't enter a new vnode for an invalid one! */
1181 	    if (!(vtype & CODA_NOCACHE))
1182 		coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
1183 	}
1184     }
1185 
1186  exit:
1187     /*
1188      * If we are creating, and this was the last name to be looked up,
1189      * and the error was ENOENT, then there really shouldn't be an
1190      * error and we can make the leaf NULL and return success.  Since
1191      * this is supposed to work under Mach as well as NetBSD, we're
1192      * leaving this fn wrapped.  We also must tell lookup/namei that
1193      * we need to save the last component of the name.  (Create will
1194      * have to free the name buffer later...lucky us...)
1195      */
1196     if (((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME))
1197 	&& (cnp->cn_flags & ISLASTCN)
1198 	&& (error == ENOENT))
1199     {
1200 	error = EJUSTRETURN;
1201 	cnp->cn_flags |= SAVENAME;
1202 	*ap->a_vpp = NULL;
1203     }
1204 
1205     /*
1206      * If we are removing, and we are at the last element, and we
1207      * found it, then we need to keep the name around so that the
1208      * removal will go ahead as planned.  Unfortunately, this will
1209      * probably also lock the to-be-removed vnode, which may or may
1210      * not be a good idea.  I'll have to look at the bits of
1211      * coda_remove to make sure.  We'll only save the name if we did in
1212      * fact find the name, otherwise coda_remove won't have a chance
1213      * to free the pathname.
1214      */
1215     if ((cnp->cn_nameiop == DELETE)
1216 	&& (cnp->cn_flags & ISLASTCN)
1217 	&& !error)
1218     {
1219 	cnp->cn_flags |= SAVENAME;
1220     }
1221 
1222     /*
1223      * If the lookup went well, we need to (potentially?) unlock the
1224      * parent, and lock the child.  We are only responsible for
1225      * checking to see if the parent is supposed to be unlocked before
1226      * we return.  We must always lock the child (provided there is
1227      * one, and (the parent isn't locked or it isn't the same as the
1228      * parent.)  Simple, huh?  We can never leave the parent locked unless
1229      * we are ISLASTCN
1230      */
1231     if (!error || (error == EJUSTRETURN)) {
1232 	if (!(cnp->cn_flags & LOCKPARENT) || !(cnp->cn_flags & ISLASTCN)) {
1233 	    if ((error = VOP_UNLOCK(dvp, 0))) {
1234 		return error;
1235 	    }
1236 	    /*
1237 	     * The parent is unlocked.  As long as there is a child,
1238 	     * lock it without bothering to check anything else.
1239 	     */
1240 	    if (*ap->a_vpp) {
1241 		if ((error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE))) {
1242 		    printf("coda_lookup: ");
1243 		    panic("unlocked parent but couldn't lock child");
1244 		}
1245 	    }
1246 	} else {
1247 	    /* The parent is locked, and may be the same as the child */
1248 	    if (*ap->a_vpp && (*ap->a_vpp != dvp)) {
1249 		/* Different, go ahead and lock it. */
1250 		if ((error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE))) {
1251 		    printf("coda_lookup: ");
1252 		    panic("unlocked parent but couldn't lock child");
1253 		}
1254 	    }
1255 	}
1256     } else {
1257 	/* If the lookup failed, we need to ensure that the leaf is NULL */
1258 	/* Don't change any locking? */
1259 	*ap->a_vpp = NULL;
1260     }
1261     return(error);
1262 }
1263 
1264 /*ARGSUSED*/
1265 int
1266 coda_create(v)
1267     void *v;
1268 {
1269 /* true args */
1270     struct vop_create_args *ap = v;
1271     struct vnode *dvp = ap->a_dvp;
1272     struct cnode *dcp = VTOC(dvp);
1273     struct vattr *va = ap->a_vap;
1274     int exclusive = 1;
1275     int mode = ap->a_vap->va_mode;
1276     struct vnode **vpp = ap->a_vpp;
1277     struct componentname  *cnp = ap->a_cnp;
1278     struct ucred *cred = cnp->cn_cred;
1279     struct proc *p = cnp->cn_proc;
1280 /* locals */
1281     int error;
1282     struct cnode *cp;
1283     const char *nm = cnp->cn_nameptr;
1284     int len = cnp->cn_namelen;
1285     ViceFid VFid;
1286     struct vattr attr;
1287 
1288     MARK_ENTRY(CODA_CREATE_STATS);
1289 
1290     /* All creates are exclusive XXX */
1291     /* I'm assuming the 'mode' argument is the file mode bits XXX */
1292 
1293     /* Check for create of control object. */
1294     if (IS_CTL_NAME(dvp, nm, len)) {
1295 	*vpp = (struct vnode *)0;
1296 	MARK_INT_FAIL(CODA_CREATE_STATS);
1297 	return(EACCES);
1298     }
1299 
1300     error = venus_create(vtomi(dvp), &dcp->c_fid, nm, len, exclusive, mode, va, cred, p, &VFid, &attr);
1301 
1302     if (!error) {
1303 
1304 	/* If this is an exclusive create, panic if the file already exists. */
1305 	/* Venus should have detected the file and reported EEXIST. */
1306 
1307 	if ((exclusive == 1) &&
1308 	    (coda_find(&VFid) != NULL))
1309 	    panic("cnode existed for newly created file!");
1310 
1311 	cp = make_coda_node(&VFid, dvp->v_mount, attr.va_type);
1312 	*vpp = CTOV(cp);
1313 
1314 	/* Update va to reflect the new attributes. */
1315 	(*va) = attr;
1316 
1317 	/* Update the attribute cache and mark it as valid */
1318 	if (coda_attr_cache) {
1319 	    VTOC(*vpp)->c_vattr = attr;
1320 	    VTOC(*vpp)->c_flags |= C_VATTR;
1321 	}
1322 
1323 	/* Invalidate the parent's attr cache, the modification time has changed */
1324 	VTOC(dvp)->c_flags &= ~C_VATTR;
1325 
1326 	/* enter the new vnode in the Name Cache */
1327 	coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
1328 
1329 	CODADEBUG(CODA_CREATE,
1330 		 myprintf(("create: (%lx.%lx.%lx), result %d\n",
1331 			VFid.Volume, VFid.Vnode, VFid.Unique, error)); )
1332     } else {
1333 	*vpp = (struct vnode *)0;
1334 	CODADEBUG(CODA_CREATE, myprintf(("create error %d\n", error));)
1335     }
1336 
1337     /* Locking strategy. */
1338     /*
1339      * In NetBSD, all creates must explicitly vput their dvp's.  We'll
1340      * go ahead and use the LOCKLEAF flag of the cnp argument.
1341      * However, I'm pretty sure that create must return the leaf
1342      * locked; so there is a DIAGNOSTIC check to ensure that this is
1343      * true.
1344      */
1345     vput(dvp);
1346     if (!error) {
1347 	if (cnp->cn_flags & LOCKLEAF) {
1348 	    if ((error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE))) {
1349 		printf("coda_create: ");
1350 		panic("unlocked parent but couldn't lock child");
1351 	    }
1352 	}
1353 #ifdef OLD_DIAGNOSTIC
1354 	else {
1355 	    printf("coda_create: LOCKLEAF not set!\n");
1356 	}
1357 #endif
1358     }
1359     /* Have to free the previously saved name */
1360     /*
1361      * This condition is stolen from ufs_makeinode.  I have no idea
1362      * why it's here, but what the hey...
1363      */
1364     if ((cnp->cn_flags & SAVESTART) == 0) {
1365 	FREE(cnp->cn_pnbuf, M_NAMEI);
1366     }
1367     return(error);
1368 }
1369 
1370 int
1371 coda_remove(v)
1372     void *v;
1373 {
1374 /* true args */
1375     struct vop_remove_args *ap = v;
1376     struct vnode *dvp = ap->a_dvp;
1377     struct cnode *cp = VTOC(dvp);
1378     struct componentname  *cnp = ap->a_cnp;
1379     struct ucred *cred = cnp->cn_cred;
1380     struct proc *p = cnp->cn_proc;
1381 /* locals */
1382     int error;
1383     const char *nm = cnp->cn_nameptr;
1384     int len = cnp->cn_namelen;
1385     struct cnode *tp;
1386 
1387     MARK_ENTRY(CODA_REMOVE_STATS);
1388 
1389     CODADEBUG(CODA_REMOVE, myprintf(("remove: %s in %lx.%lx.%lx\n",
1390 				   nm, cp->c_fid.Volume, cp->c_fid.Vnode,
1391 				   cp->c_fid.Unique)););
1392 
1393     /* Remove the file's entry from the CODA Name Cache */
1394     /* We're being conservative here, it might be that this person
1395      * doesn't really have sufficient access to delete the file
1396      * but we feel zapping the entry won't really hurt anyone -- dcs
1397      */
1398     /* I'm gonna go out on a limb here. If a file and a hardlink to it
1399      * exist, and one is removed, the link count on the other will be
1400      * off by 1. We could either invalidate the attrs if cached, or
1401      * fix them. I'll try to fix them. DCS 11/8/94
1402      */
1403     tp = coda_nc_lookup(VTOC(dvp), nm, len, cred);
1404     if (tp) {
1405 	if (VALID_VATTR(tp)) {	/* If attrs are cached */
1406 	    if (tp->c_vattr.va_nlink > 1) {	/* If it's a hard link */
1407 		tp->c_vattr.va_nlink--;
1408 	    }
1409 	}
1410 
1411 	coda_nc_zapfile(VTOC(dvp), nm, len);
1412 	/* No need to flush it if it doesn't exist! */
1413     }
1414     /* Invalidate the parent's attr cache, the modification time has changed */
1415     VTOC(dvp)->c_flags &= ~C_VATTR;
1416 
1417     /* Check for remove of control object. */
1418     if (IS_CTL_NAME(dvp, nm, len)) {
1419 	MARK_INT_FAIL(CODA_REMOVE_STATS);
1420 	return(ENOENT);
1421     }
1422 
1423     error = venus_remove(vtomi(dvp), &cp->c_fid, nm, len, cred, p);
1424 
1425     CODADEBUG(CODA_REMOVE, myprintf(("in remove result %d\n",error)); )
1426 
1427     /*
1428      * Regardless of what happens, we have to unconditionally drop
1429      * locks/refs on parent and child.  (I hope).  This is based on
1430      * what ufs_remove seems to be doing.
1431      */
1432     if (dvp == ap->a_vp) {
1433 	vrele(ap->a_vp);
1434     } else {
1435 	vput(ap->a_vp);
1436     }
1437     vput(dvp);
1438 
1439     if ((cnp->cn_flags & SAVESTART) == 0) {
1440 	FREE(cnp->cn_pnbuf, M_NAMEI);
1441     }
1442     return(error);
1443 }
1444 
1445 int
1446 coda_link(v)
1447     void *v;
1448 {
1449 /* true args */
1450     struct vop_link_args *ap = v;
1451     struct vnode *vp = ap->a_vp;
1452     struct cnode *cp = VTOC(vp);
1453     struct vnode *tdvp = ap->a_dvp;
1454     struct cnode *tdcp = VTOC(tdvp);
1455     struct componentname *cnp = ap->a_cnp;
1456     struct ucred *cred = cnp->cn_cred;
1457     struct proc *p = cnp->cn_proc;
1458 /* locals */
1459     int error;
1460     const char *nm = cnp->cn_nameptr;
1461     int len = cnp->cn_namelen;
1462 
1463     MARK_ENTRY(CODA_LINK_STATS);
1464 
1465     if (codadebug & CODADBGMSK(CODA_LINK)) {
1466 
1467 	myprintf(("nb_link:   vp fid: (%lx.%lx.%lx)\n",
1468 		  cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique));
1469 	myprintf(("nb_link: tdvp fid: (%lx.%lx.%lx)\n",
1470 		  tdcp->c_fid.Volume, tdcp->c_fid.Vnode, tdcp->c_fid.Unique));
1471 
1472     }
1473     if (codadebug & CODADBGMSK(CODA_LINK)) {
1474 	myprintf(("link:   vp fid: (%lx.%lx.%lx)\n",
1475 		  cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique));
1476 	myprintf(("link: tdvp fid: (%lx.%lx.%lx)\n",
1477 		  tdcp->c_fid.Volume, tdcp->c_fid.Vnode, tdcp->c_fid.Unique));
1478 
1479     }
1480 
1481     /* Check for link to/from control object. */
1482     if (IS_CTL_NAME(tdvp, nm, len) || IS_CTL_VP(vp)) {
1483 	MARK_INT_FAIL(CODA_LINK_STATS);
1484 	return(EACCES);
1485     }
1486 
1487     /*
1488      * According to the ufs_link operation here's the locking situation:
1489      *     We enter with the thing called "dvp" (the directory) locked.
1490      *     We must unconditionally drop locks on "dvp"
1491      *
1492      *     We enter with the thing called "vp" (the linked-to) unlocked,
1493      *       but ref'd (?)
1494      *     We seem to need to lock it before calling coda_link, and
1495      *       unconditionally unlock it after.
1496      */
1497 
1498     if ((ap->a_vp != tdvp) && (error = vn_lock(ap->a_vp, LK_EXCLUSIVE))) {
1499 	goto exit;
1500     }
1501 
1502     error = venus_link(vtomi(vp), &cp->c_fid, &tdcp->c_fid, nm, len, cred, p);
1503 
1504     /* Invalidate the parent's attr cache, the modification time has changed */
1505     VTOC(tdvp)->c_flags &= ~C_VATTR;
1506     VTOC(vp)->c_flags &= ~C_VATTR;
1507 
1508     CODADEBUG(CODA_LINK,	myprintf(("in link result %d\n",error)); )
1509 
1510 exit:
1511 
1512     if (ap->a_vp != tdvp) {
1513 	VOP_UNLOCK(ap->a_vp, 0);
1514     }
1515     vput(tdvp);
1516 
1517     /* Drop the name buffer if we don't need to SAVESTART */
1518     if ((cnp->cn_flags & SAVESTART) == 0) {
1519 	FREE(cnp->cn_pnbuf, M_NAMEI);
1520     }
1521     return(error);
1522 }
1523 
1524 int
1525 coda_rename(v)
1526     void *v;
1527 {
1528 /* true args */
1529     struct vop_rename_args *ap = v;
1530     struct vnode *odvp = ap->a_fdvp;
1531     struct cnode *odcp = VTOC(odvp);
1532     struct componentname  *fcnp = ap->a_fcnp;
1533     struct vnode *ndvp = ap->a_tdvp;
1534     struct cnode *ndcp = VTOC(ndvp);
1535     struct componentname  *tcnp = ap->a_tcnp;
1536     struct ucred *cred = fcnp->cn_cred;
1537     struct proc *p = fcnp->cn_proc;
1538 /* true args */
1539     int error;
1540     const char *fnm = fcnp->cn_nameptr;
1541     int flen = fcnp->cn_namelen;
1542     const char *tnm = tcnp->cn_nameptr;
1543     int tlen = tcnp->cn_namelen;
1544 
1545     MARK_ENTRY(CODA_RENAME_STATS);
1546 
1547     /* Hmmm.  The vnodes are already looked up.  Perhaps they are locked?
1548        This could be Bad. XXX */
1549 #ifdef OLD_DIAGNOSTIC
1550     if ((fcnp->cn_cred != tcnp->cn_cred)
1551 	|| (fcnp->cn_proc != tcnp->cn_proc))
1552     {
1553 	panic("coda_rename: component names don't agree");
1554     }
1555 #endif
1556 
1557     /* Check for rename involving control object. */
1558     if (IS_CTL_NAME(odvp, fnm, flen) || IS_CTL_NAME(ndvp, tnm, tlen)) {
1559 	MARK_INT_FAIL(CODA_RENAME_STATS);
1560 	return(EACCES);
1561     }
1562 
1563     /* Problem with moving directories -- need to flush entry for .. */
1564     if (odvp != ndvp) {
1565 	struct cnode *ovcp = coda_nc_lookup(VTOC(odvp), fnm, flen, cred);
1566 	if (ovcp) {
1567 	    struct vnode *ovp = CTOV(ovcp);
1568 	    if ((ovp) &&
1569 		(ovp->v_type == VDIR)) /* If it's a directory */
1570 		coda_nc_zapfile(VTOC(ovp),"..", 2);
1571 	}
1572     }
1573 
1574     /* Remove the entries for both source and target files */
1575     coda_nc_zapfile(VTOC(odvp), fnm, flen);
1576     coda_nc_zapfile(VTOC(ndvp), tnm, tlen);
1577 
1578     /* Invalidate the parent's attr cache, the modification time has changed */
1579     VTOC(odvp)->c_flags &= ~C_VATTR;
1580     VTOC(ndvp)->c_flags &= ~C_VATTR;
1581 
1582     if (flen+1 > CODA_MAXNAMLEN) {
1583 	MARK_INT_FAIL(CODA_RENAME_STATS);
1584 	error = EINVAL;
1585 	goto exit;
1586     }
1587 
1588     if (tlen+1 > CODA_MAXNAMLEN) {
1589 	MARK_INT_FAIL(CODA_RENAME_STATS);
1590 	error = EINVAL;
1591 	goto exit;
1592     }
1593 
1594     error = venus_rename(vtomi(odvp), &odcp->c_fid, &ndcp->c_fid, fnm, flen, tnm, tlen, cred, p);
1595 
1596  exit:
1597     CODADEBUG(CODA_RENAME, myprintf(("in rename result %d\n",error));)
1598     /* XXX - do we need to call cache pureg on the moved vnode? */
1599     cache_purge(ap->a_fvp);
1600 
1601     /* It seems to be incumbent on us to drop locks on all four vnodes */
1602     /* From-vnodes are not locked, only ref'd.  To-vnodes are locked. */
1603 
1604     vrele(ap->a_fvp);
1605     vrele(odvp);
1606 
1607     if (ap->a_tvp) {
1608 	if (ap->a_tvp == ndvp) {
1609 	    vrele(ap->a_tvp);
1610 	} else {
1611 	    vput(ap->a_tvp);
1612 	}
1613     }
1614 
1615     vput(ndvp);
1616     return(error);
1617 }
1618 
1619 int
1620 coda_mkdir(v)
1621     void *v;
1622 {
1623 /* true args */
1624     struct vop_mkdir_args *ap = v;
1625     struct vnode *dvp = ap->a_dvp;
1626     struct cnode *dcp = VTOC(dvp);
1627     struct componentname  *cnp = ap->a_cnp;
1628     register struct vattr *va = ap->a_vap;
1629     struct vnode **vpp = ap->a_vpp;
1630     struct ucred *cred = cnp->cn_cred;
1631     struct proc *p = cnp->cn_proc;
1632 /* locals */
1633     int error;
1634     const char *nm = cnp->cn_nameptr;
1635     int len = cnp->cn_namelen;
1636     struct cnode *cp;
1637     ViceFid VFid;
1638     struct vattr ova;
1639 
1640     MARK_ENTRY(CODA_MKDIR_STATS);
1641 
1642     /* Check for mkdir of target object. */
1643     if (IS_CTL_NAME(dvp, nm, len)) {
1644 	*vpp = (struct vnode *)0;
1645 	MARK_INT_FAIL(CODA_MKDIR_STATS);
1646 	return(EACCES);
1647     }
1648 
1649     if (len+1 > CODA_MAXNAMLEN) {
1650 	*vpp = (struct vnode *)0;
1651 	MARK_INT_FAIL(CODA_MKDIR_STATS);
1652 	return(EACCES);
1653     }
1654 
1655     error = venus_mkdir(vtomi(dvp), &dcp->c_fid, nm, len, va, cred, p, &VFid, &ova);
1656 
1657     if (!error) {
1658 	if (coda_find(&VFid) != NULL)
1659 	    panic("cnode existed for newly created directory!");
1660 
1661 
1662 	cp =  make_coda_node(&VFid, dvp->v_mount, va->va_type);
1663 	*vpp = CTOV(cp);
1664 
1665 	/* enter the new vnode in the Name Cache */
1666 	coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
1667 
1668 	/* as a side effect, enter "." and ".." for the directory */
1669 	coda_nc_enter(VTOC(*vpp), ".", 1, cred, VTOC(*vpp));
1670 	coda_nc_enter(VTOC(*vpp), "..", 2, cred, VTOC(dvp));
1671 
1672 	if (coda_attr_cache) {
1673 	    VTOC(*vpp)->c_vattr = ova;		/* update the attr cache */
1674 	    VTOC(*vpp)->c_flags |= C_VATTR;	/* Valid attributes in cnode */
1675 	}
1676 
1677 	/* Invalidate the parent's attr cache, the modification time has changed */
1678 	VTOC(dvp)->c_flags &= ~C_VATTR;
1679 
1680 	CODADEBUG( CODA_MKDIR, myprintf(("mkdir: (%lx.%lx.%lx) result %d\n",
1681 				    VFid.Volume, VFid.Vnode, VFid.Unique, error)); )
1682     } else {
1683 	*vpp = (struct vnode *)0;
1684 	CODADEBUG(CODA_MKDIR, myprintf(("mkdir error %d\n",error));)
1685     }
1686 
1687     /*
1688      * Currently, all mkdirs explicitly vput their dvp's.
1689      * It also appears that we *must* lock the vpp, since
1690      * lockleaf isn't set, but someone down the road is going
1691      * to try to unlock the new directory.
1692      */
1693     vput(dvp);
1694     if (!error) {
1695 	if ((error = vn_lock(*ap->a_vpp, LK_EXCLUSIVE))) {
1696 	    panic("coda_mkdir: couldn't lock child");
1697 	}
1698     }
1699 
1700     /* Have to free the previously saved name */
1701     /*
1702      * ufs_mkdir doesn't check for SAVESTART before freeing the
1703      * pathname buffer, but ufs_create does.  For the moment, I'll
1704      * follow their lead, but this seems like it is probably
1705      * incorrect.
1706      */
1707     FREE(cnp->cn_pnbuf, M_NAMEI);
1708     return(error);
1709 }
1710 
1711 int
1712 coda_rmdir(v)
1713     void *v;
1714 {
1715 /* true args */
1716     struct vop_rmdir_args *ap = v;
1717     struct vnode *dvp = ap->a_dvp;
1718     struct cnode *dcp = VTOC(dvp);
1719     struct componentname  *cnp = ap->a_cnp;
1720     struct ucred *cred = cnp->cn_cred;
1721     struct proc *p = cnp->cn_proc;
1722 /* true args */
1723     int error;
1724     const char *nm = cnp->cn_nameptr;
1725     int len = cnp->cn_namelen;
1726     struct cnode *cp;
1727 
1728     MARK_ENTRY(CODA_RMDIR_STATS);
1729 
1730     /* Check for rmdir of control object. */
1731     if (IS_CTL_NAME(dvp, nm, len)) {
1732 	MARK_INT_FAIL(CODA_RMDIR_STATS);
1733 	return(ENOENT);
1734     }
1735 
1736     /* We're being conservative here, it might be that this person
1737      * doesn't really have sufficient access to delete the file
1738      * but we feel zapping the entry won't really hurt anyone -- dcs
1739      */
1740     /*
1741      * As a side effect of the rmdir, remove any entries for children of
1742      * the directory, especially "." and "..".
1743      */
1744     cp = coda_nc_lookup(dcp, nm, len, cred);
1745     if (cp) coda_nc_zapParentfid(&(cp->c_fid), NOT_DOWNCALL);
1746 
1747     /* Remove the file's entry from the CODA Name Cache */
1748     coda_nc_zapfile(dcp, nm, len);
1749 
1750     /* Invalidate the parent's attr cache, the modification time has changed */
1751     dcp->c_flags &= ~C_VATTR;
1752 
1753     error = venus_rmdir(vtomi(dvp), &dcp->c_fid, nm, len, cred, p);
1754 
1755     CODADEBUG(CODA_RMDIR, myprintf(("in rmdir result %d\n", error)); )
1756 
1757     /*
1758      * regardless of what happens, we need to drop locks/refs on the
1759      * parent and child.  I think.
1760      */
1761     if (dvp == ap->a_vp) {
1762 	vrele(ap->a_vp);
1763     } else {
1764 	vput(ap->a_vp);
1765     }
1766     vput(dvp);
1767 
1768     if ((cnp->cn_flags & SAVESTART) == 0) {
1769 	FREE(cnp->cn_pnbuf, M_NAMEI);
1770     }
1771     return(error);
1772 }
1773 
1774 int
1775 coda_symlink(v)
1776     void *v;
1777 {
1778 /* true args */
1779     struct vop_symlink_args *ap = v;
1780     struct vnode *tdvp = ap->a_dvp;
1781     struct cnode *tdcp = VTOC(tdvp);
1782     struct componentname *cnp = ap->a_cnp;
1783     struct vattr *tva = ap->a_vap;
1784     char *path = ap->a_target;
1785     struct ucred *cred = cnp->cn_cred;
1786     struct proc *p = cnp->cn_proc;
1787 /* locals */
1788     int error;
1789     /*
1790      * XXX I'm assuming the following things about coda_symlink's
1791      * arguments:
1792      *       t(foo) is the new name/parent/etc being created.
1793      *       lname is the contents of the new symlink.
1794      */
1795     const char *nm = cnp->cn_nameptr;
1796     int len = cnp->cn_namelen;
1797     int plen = strlen(path);
1798 
1799     /* XXX What about the vpp argument?  Do we need it? */
1800     /*
1801      * Here's the strategy for the moment: perform the symlink, then
1802      * do a lookup to grab the resulting vnode.  I know this requires
1803      * two communications with Venus for a new sybolic link, but
1804      * that's the way the ball bounces.  I don't yet want to change
1805      * the way the Mach symlink works.  When Mach support is
1806      * deprecated, we should change symlink so that the common case
1807      * returns the resultant vnode in a vpp argument.
1808      */
1809 
1810     MARK_ENTRY(CODA_SYMLINK_STATS);
1811 
1812     /* Check for symlink of control object. */
1813     if (IS_CTL_NAME(tdvp, nm, len)) {
1814 	MARK_INT_FAIL(CODA_SYMLINK_STATS);
1815 	return(EACCES);
1816     }
1817 
1818     if (plen+1 > CODA_MAXPATHLEN) {
1819 	MARK_INT_FAIL(CODA_SYMLINK_STATS);
1820 	return(EINVAL);
1821     }
1822 
1823     if (len+1 > CODA_MAXNAMLEN) {
1824 	MARK_INT_FAIL(CODA_SYMLINK_STATS);
1825 	error = EINVAL;
1826 	goto exit;
1827     }
1828 
1829     error = venus_symlink(vtomi(tdvp), &tdcp->c_fid, path, plen, nm, len, tva, cred, p);
1830 
1831     /* Invalidate the parent's attr cache, the modification time has changed */
1832     tdcp->c_flags &= ~C_VATTR;
1833 
1834     if (!error)
1835     {
1836 	struct nameidata nd;
1837 	NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, nm, p);
1838 	nd.ni_cnd.cn_cred = cred;
1839 	nd.ni_loopcnt = 0;
1840 	nd.ni_startdir = tdvp;
1841 	nd.ni_cnd.cn_pnbuf = (char *)nm;
1842 	nd.ni_cnd.cn_nameptr = nd.ni_cnd.cn_pnbuf;
1843 	nd.ni_pathlen = len;
1844 	vput(tdvp);
1845 	error = lookup(&nd);
1846 	*ap->a_vpp = nd.ni_vp;
1847     }
1848 
1849     /*
1850      * Okay, now we have to drop locks on dvp.  vpp is unlocked, but
1851      * ref'd.  It doesn't matter what happens in either symlink or
1852      * lookup.  Furthermore, there isn't any way for (dvp == *vpp), so
1853      * we don't bother checking.
1854      */
1855 /*  vput(ap->a_dvp);		released earlier */
1856     if (*ap->a_vpp) {
1857     	VOP_UNLOCK(*ap->a_vpp, 0);	/* this line is new!! It is necessary because lookup() calls
1858 				   VOP_LOOKUP (coda_lookup) which returns vpp locked.  cfs_nb_lookup
1859 				   merged with coda_lookup() to become coda_lookup so UNLOCK is
1860 				   necessary */
1861     	vrele(*ap->a_vpp);
1862     }
1863 
1864     /*
1865      * Free the name buffer
1866      */
1867     if ((cnp->cn_flags & SAVESTART) == 0) {
1868 	FREE(cnp->cn_pnbuf, M_NAMEI);
1869     }
1870 
1871  exit:
1872     CODADEBUG(CODA_SYMLINK, myprintf(("in symlink result %d\n",error)); )
1873     return(error);
1874 }
1875 
1876 /*
1877  * Read directory entries.
1878  */
1879 int
1880 coda_readdir(v)
1881     void *v;
1882 {
1883 /* true args */
1884     struct vop_readdir_args *ap = v;
1885     struct vnode *vp = ap->a_vp;
1886     struct cnode *cp = VTOC(vp);
1887     register struct uio *uiop = ap->a_uio;
1888     struct ucred *cred = ap->a_cred;
1889     int *eofflag = ap->a_eofflag;
1890     off_t **cookies = ap->a_cookies;
1891     int *ncookies = ap->a_ncookies;
1892     struct proc *p = ap->a_uio->uio_procp;
1893 /* upcall decl */
1894 /* locals */
1895     int error = 0;
1896 
1897     MARK_ENTRY(CODA_READDIR_STATS);
1898 
1899     CODADEBUG(CODA_READDIR, myprintf(("coda_readdir(%p, %d, %qd, %d)\n", uiop->uio_iov->iov_base, uiop->uio_resid, uiop->uio_offset, uiop->uio_segflg)); )
1900 
1901     /* Check for readdir of control object. */
1902     if (IS_CTL_VP(vp)) {
1903 	MARK_INT_FAIL(CODA_READDIR_STATS);
1904 	return(ENOENT);
1905     }
1906 
1907     {
1908 	/* Redirect the request to UFS. */
1909 
1910 	/* If directory is not already open do an "internal open" on it. */
1911 	int opened_internally = 0;
1912 	if (cp->c_ovp == NULL) {
1913 	    opened_internally = 1;
1914 	    MARK_INT_GEN(CODA_OPEN_STATS);
1915 	    error = VOP_OPEN(vp, FREAD, cred, p);
1916 printf("coda_readdir: Internally Opening %p\n", vp);
1917 	    if (error) return(error);
1918 	}
1919 
1920 	/* Have UFS handle the call. */
1921 	CODADEBUG(CODA_READDIR, myprintf(("indirect readdir: fid = (%lx.%lx.%lx), refcnt = %d\n",cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique, vp->v_usecount)); )
1922 	error = VOP_READDIR(cp->c_ovp, uiop, cred, eofflag, cookies,
1923 			       ncookies);
1924 	if (error)
1925 	    MARK_INT_FAIL(CODA_READDIR_STATS);
1926 	else
1927 	    MARK_INT_SAT(CODA_READDIR_STATS);
1928 
1929 	/* Do an "internal close" if necessary. */
1930 	if (opened_internally) {
1931 	    MARK_INT_GEN(CODA_CLOSE_STATS);
1932 	    (void)VOP_CLOSE(vp, FREAD, cred, p);
1933 	}
1934     }
1935 
1936     return(error);
1937 }
1938 
1939 /*
1940  * Convert from file system blocks to device blocks
1941  */
1942 int
1943 coda_bmap(v)
1944     void *v;
1945 {
1946     /* XXX on the global proc */
1947 /* true args */
1948     struct vop_bmap_args *ap = v;
1949     struct vnode *vp __attribute__((unused)) = ap->a_vp;	/* file's vnode */
1950     daddr_t bn __attribute__((unused)) = ap->a_bn;	/* fs block number */
1951     struct vnode **vpp = ap->a_vpp;			/* RETURN vp of device */
1952     daddr_t *bnp __attribute__((unused)) = ap->a_bnp;	/* RETURN device block number */
1953     struct proc *p __attribute__((unused)) = curproc;
1954 /* upcall decl */
1955 /* locals */
1956 
1957 	*vpp = (struct vnode *)0;
1958 	myprintf(("coda_bmap called!\n"));
1959 	return(EINVAL);
1960 }
1961 
1962 /*
1963  * I don't think the following two things are used anywhere, so I've
1964  * commented them out
1965  *
1966  * struct buf *async_bufhead;
1967  * int async_daemon_count;
1968  */
1969 int
1970 coda_strategy(v)
1971     void *v;
1972 {
1973 /* true args */
1974     struct vop_strategy_args *ap = v;
1975     register struct buf *bp __attribute__((unused)) = ap->a_bp;
1976     struct proc *p __attribute__((unused)) = curproc;
1977 /* upcall decl */
1978 /* locals */
1979 
1980 	myprintf(("coda_strategy called!  "));
1981 	return(EINVAL);
1982 }
1983 
1984 int
1985 coda_reclaim(v)
1986     void *v;
1987 {
1988 /* true args */
1989     struct vop_reclaim_args *ap = v;
1990     struct vnode *vp = ap->a_vp;
1991     struct cnode *cp = VTOC(vp);
1992 /* upcall decl */
1993 /* locals */
1994 
1995 /*
1996  * Forced unmount/flush will let vnodes with non zero use be destroyed!
1997  */
1998     ENTRY;
1999 
2000     if (IS_UNMOUNTING(cp)) {
2001 #ifdef	DEBUG
2002 	if (VTOC(vp)->c_ovp) {
2003 	    if (IS_UNMOUNTING(cp))
2004 		printf("coda_reclaim: c_ovp not void: vp %p, cp %p\n", vp, cp);
2005 	}
2006 #endif
2007     } else {
2008 #ifdef OLD_DIAGNOSTIC
2009 	if (vp->v_usecount != 0)
2010 	    print("coda_reclaim: pushing active %p\n", vp);
2011 	if (VTOC(vp)->c_ovp) {
2012 	    panic("coda_reclaim: c_ovp not void");
2013 	}
2014 #endif
2015     }
2016     cache_purge(vp);
2017     coda_free(VTOC(vp));
2018     VTOC(vp) = NULL;
2019     return (0);
2020 }
2021 
2022 int
2023 coda_lock(v)
2024     void *v;
2025 {
2026 /* true args */
2027     struct vop_lock_args *ap = v;
2028     struct vnode *vp = ap->a_vp;
2029     struct cnode *cp = VTOC(vp);
2030 /* upcall decl */
2031 /* locals */
2032 
2033     ENTRY;
2034 
2035     if (coda_lockdebug) {
2036 	myprintf(("Attempting lock on %lx.%lx.%lx\n",
2037 		  cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique));
2038     }
2039 
2040     return (lockmgr(&cp->c_lock, ap->a_flags, &vp->v_interlock));
2041 }
2042 
2043 int
2044 coda_unlock(v)
2045     void *v;
2046 {
2047 /* true args */
2048     struct vop_unlock_args *ap = v;
2049     struct vnode *vp = ap->a_vp;
2050     struct cnode *cp = VTOC(vp);
2051 /* upcall decl */
2052 /* locals */
2053 
2054     ENTRY;
2055     if (coda_lockdebug) {
2056 	myprintf(("Attempting unlock on %lx.%lx.%lx\n",
2057 		  cp->c_fid.Volume, cp->c_fid.Vnode, cp->c_fid.Unique));
2058     }
2059 
2060     return (lockmgr(&cp->c_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock));
2061 }
2062 
2063 int
2064 coda_islocked(v)
2065     void *v;
2066 {
2067 /* true args */
2068     struct vop_islocked_args *ap = v;
2069     struct cnode *cp = VTOC(ap->a_vp);
2070     ENTRY;
2071 
2072     return (lockstatus(&cp->c_lock));
2073 }
2074 
2075 /* How one looks up a vnode given a device/inode pair: */
2076 int
2077 coda_grab_vnode(dev_t dev, ino_t ino, struct vnode **vpp)
2078 {
2079     /* This is like VFS_VGET() or igetinode()! */
2080     int           error;
2081     struct mount *mp;
2082 
2083     if (!(mp = devtomp(dev))) {
2084 	myprintf(("coda_grab_vnode: devtomp(%d) returns NULL\n", dev));
2085 	return(ENXIO);
2086     }
2087 
2088     /* XXX - ensure that nonzero-return means failure */
2089     error = VFS_VGET(mp,ino,vpp);
2090     if (error) {
2091 	myprintf(("coda_grab_vnode: iget/vget(%d, %d) returns %p, err %d\n",
2092 		  dev, ino, *vpp, error));
2093 	return(ENOENT);
2094     }
2095     return(0);
2096 }
2097 
2098 void
2099 print_vattr( attr )
2100 	struct vattr *attr;
2101 {
2102     char *typestr;
2103 
2104     switch (attr->va_type) {
2105     case VNON:
2106 	typestr = "VNON";
2107 	break;
2108     case VREG:
2109 	typestr = "VREG";
2110 	break;
2111     case VDIR:
2112 	typestr = "VDIR";
2113 	break;
2114     case VBLK:
2115 	typestr = "VBLK";
2116 	break;
2117     case VCHR:
2118 	typestr = "VCHR";
2119 	break;
2120     case VLNK:
2121 	typestr = "VLNK";
2122 	break;
2123     case VSOCK:
2124 	typestr = "VSCK";
2125 	break;
2126     case VFIFO:
2127 	typestr = "VFFO";
2128 	break;
2129     case VBAD:
2130 	typestr = "VBAD";
2131 	break;
2132     default:
2133 	typestr = "????";
2134 	break;
2135     }
2136 
2137 
2138     myprintf(("attr: type %s mode %d uid %d gid %d fsid %d rdev %d\n",
2139 	      typestr, (int)attr->va_mode, (int)attr->va_uid,
2140 	      (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev));
2141 
2142     myprintf(("      fileid %d nlink %d size %d blocksize %d bytes %d\n",
2143 	      (int)attr->va_fileid, (int)attr->va_nlink,
2144 	      (int)attr->va_size,
2145 	      (int)attr->va_blocksize,(int)attr->va_bytes));
2146     myprintf(("      gen %ld flags %ld vaflags %d\n",
2147 	      attr->va_gen, attr->va_flags, attr->va_vaflags));
2148     myprintf(("      atime sec %d nsec %d\n",
2149 	      (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec));
2150     myprintf(("      mtime sec %d nsec %d\n",
2151 	      (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec));
2152     myprintf(("      ctime sec %d nsec %d\n",
2153 	      (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec));
2154 }
2155 
2156 /* How to print a ucred */
2157 void
2158 print_cred(cred)
2159 	struct ucred *cred;
2160 {
2161 
2162 	int i;
2163 
2164 	myprintf(("ref %d\tuid %d\n",cred->cr_ref,cred->cr_uid));
2165 
2166 	for (i=0; i < cred->cr_ngroups; i++)
2167 		myprintf(("\tgroup %d: (%d)\n",i,cred->cr_groups[i]));
2168 	myprintf(("\n"));
2169 
2170 }
2171 
2172 /*
2173  * Return a vnode for the given fid.
2174  * If no cnode exists for this fid create one and put it
2175  * in a table hashed by fid.Volume and fid.Vnode.  If the cnode for
2176  * this fid is already in the table return it (ref count is
2177  * incremented by coda_find.  The cnode will be flushed from the
2178  * table when coda_inactive calls coda_unsave.
2179  */
2180 struct cnode *
2181 make_coda_node(fid, vfsp, type)
2182      ViceFid *fid; struct mount *vfsp; short type;
2183 {
2184     struct cnode *cp;
2185     int          err;
2186 
2187     if ((cp = coda_find(fid)) == NULL) {
2188 	struct vnode *vp;
2189 
2190 	cp = coda_alloc();
2191 	lockinit(&cp->c_lock, PINOD, "cnode", 0, 0);
2192 	cp->c_fid = *fid;
2193 
2194 	err = getnewvnode(VT_CODA, vfsp, coda_vnodeop_p, &vp);
2195 	if (err) {
2196 	    panic("coda: getnewvnode returned error %d\n", err);
2197 	}
2198 	vp->v_data = cp;
2199 	vp->v_type = type;
2200 	cp->c_vnode = vp;
2201 	coda_save(cp);
2202 
2203     } else {
2204 	vref(CTOV(cp));
2205     }
2206 
2207     return cp;
2208 }
2209