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