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