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