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