1 /*-
2 * Coda: an Experimental Distributed File System
3 * Release 3.1
4 *
5 * Copyright (c) 1987-1998 Carnegie Mellon University
6 * All Rights Reserved
7 *
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation, and
13 * that credit is given to Carnegie Mellon University in all documents
14 * and publicity pertaining to direct or indirect use of this code or its
15 * derivatives.
16 *
17 * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS,
18 * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS
19 * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON
20 * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
21 * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF
22 * ANY DERIVATIVE WORK.
23 *
24 * Carnegie Mellon encourages users of this software to return any
25 * improvements or extensions that they make, and to grant Carnegie
26 * Mellon the rights to redistribute these changes without encumbrance.
27 *
28 * @(#) src/sys/coda/coda_vnops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
29 */
30 /*
31 * Mach Operating System
32 * Copyright (c) 1990 Carnegie-Mellon University
33 * Copyright (c) 1989 Carnegie-Mellon University
34 * All rights reserved. The CMU software License Agreement specifies
35 * the terms and conditions for use and redistribution.
36 */
37
38 /*
39 * This code was written for the Coda filesystem at Carnegie Mellon
40 * University. Contributers include David Steere, James Kistler, and
41 * M. Satyanarayanan.
42 */
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/acct.h>
50 #include <sys/errno.h>
51 #include <sys/fcntl.h>
52 #include <sys/kernel.h>
53 #include <sys/lock.h>
54 #include <sys/malloc.h>
55 #include <sys/file.h> /* Must come after sys/malloc.h */
56 #include <sys/mount.h>
57 #include <sys/mutex.h>
58 #include <sys/namei.h>
59 #include <sys/proc.h>
60 #include <sys/uio.h>
61 #include <sys/unistd.h>
62
63 #include <vm/vm.h>
64 #include <vm/vm_object.h>
65 #include <vm/vm_extern.h>
66
67 #include <fs/coda/coda.h>
68 #include <fs/coda/cnode.h>
69 #include <fs/coda/coda_vnops.h>
70 #include <fs/coda/coda_venus.h>
71 #include <fs/coda/coda_opstats.h>
72 #include <fs/coda/coda_subr.h>
73 #include <fs/coda/coda_namecache.h>
74 #include <fs/coda/coda_pioctl.h>
75
76 /*
77 * These flags select various performance enhancements.
78 */
79 int coda_attr_cache = 1; /* Set to cache attributes in the kernel */
80 int coda_symlink_cache = 1; /* Set to cache symbolic link information */
81 int coda_access_cache = 1; /* Set to handle some access checks directly */
82
83 /* structure to keep track of vfs calls */
84
85 struct coda_op_stats coda_vnodeopstats[CODA_VNODEOPS_SIZE];
86
87 #define MARK_ENTRY(op) (coda_vnodeopstats[op].entries++)
88 #define MARK_INT_SAT(op) (coda_vnodeopstats[op].sat_intrn++)
89 #define MARK_INT_FAIL(op) (coda_vnodeopstats[op].unsat_intrn++)
90 #define MARK_INT_GEN(op) (coda_vnodeopstats[op].gen_intrn++)
91
92 /* What we are delaying for in printf */
93 int coda_printf_delay = 0; /* in microseconds */
94 int coda_vnop_print_entry = 0;
95 static int coda_lockdebug = 0;
96
97 /*
98 * Some NetBSD details:
99 *
100 * coda_start is called at the end of the mount syscall.
101 * coda_init is called at boot time.
102 */
103
104 #define ENTRY if(coda_vnop_print_entry) myprintf(("Entered %s\n",__func__))
105
106 /* Definition of the vnode operation vector */
107
108 struct vop_vector coda_vnodeops = {
109 .vop_default = &default_vnodeops,
110 .vop_lookup = coda_lookup, /* lookup */
111 .vop_create = coda_create, /* create */
112 .vop_open = coda_open, /* open */
113 .vop_close = coda_close, /* close */
114 .vop_access = coda_access, /* access */
115 .vop_getattr = coda_getattr, /* getattr */
116 .vop_setattr = coda_setattr, /* setattr */
117 .vop_read = coda_read, /* read */
118 .vop_write = coda_write, /* write */
119 .vop_ioctl = coda_ioctl, /* ioctl */
120 .vop_fsync = coda_fsync, /* fsync */
121 .vop_remove = coda_remove, /* remove */
122 .vop_link = coda_link, /* link */
123 .vop_rename = coda_rename, /* rename */
124 .vop_mkdir = coda_mkdir, /* mkdir */
125 .vop_rmdir = coda_rmdir, /* rmdir */
126 .vop_symlink = coda_symlink, /* symlink */
127 .vop_readdir = coda_readdir, /* readdir */
128 .vop_readlink = coda_readlink, /* readlink */
129 .vop_inactive = coda_inactive, /* inactive */
130 .vop_reclaim = coda_reclaim, /* reclaim */
131 .vop_lock1 = coda_lock, /* lock */
132 .vop_unlock = coda_unlock, /* unlock */
133 .vop_bmap = coda_bmap, /* bmap */
134 .vop_print = VOP_NULL, /* print */
135 .vop_islocked = coda_islocked, /* islocked */
136 .vop_pathconf = coda_pathconf, /* pathconf */
137 .vop_poll = vop_stdpoll,
138 .vop_getpages = vop_stdgetpages, /* pager intf.*/
139 .vop_putpages = vop_stdputpages, /* pager intf.*/
140 .vop_getwritemount = vop_stdgetwritemount,
141
142 #if 0
143 missing
144 .vop_cachedlookup = ufs_lookup,
145 .vop_whiteout = ufs_whiteout,
146 #endif
147
148 };
149
150 /* A generic do-nothing. For lease_check, advlock */
151 int
152 coda_vop_nop(void *anon) {
153 struct vnodeop_desc **desc = (struct vnodeop_desc **)anon;
154
155 if (codadebug) {
156 myprintf(("Vnode operation %s called, but unsupported\n",
157 (*desc)->vdesc_name));
158 }
159 return (0);
160 }
161
162 int
163 coda_vnodeopstats_init(void)
164 {
165 register int i;
166
167 for(i=0;i<CODA_VNODEOPS_SIZE;i++) {
168 coda_vnodeopstats[i].opcode = i;
169 coda_vnodeopstats[i].entries = 0;
170 coda_vnodeopstats[i].sat_intrn = 0;
171 coda_vnodeopstats[i].unsat_intrn = 0;
172 coda_vnodeopstats[i].gen_intrn = 0;
173 }
174 return 0;
175 }
176
177 /*
178 * coda_open calls Venus which returns an open file descriptor the cache
179 * file holding the data. We get the vnode while we are still in the
180 * context of the venus process in coda_psdev.c. This vnode is then
181 * passed back to the caller and opened.
182 */
183 int
184 coda_open(struct vop_open_args *ap)
185 {
186 /*
187 * NetBSD can pass the O_EXCL flag in mode, even though the check
188 * has already happened. Venus defensively assumes that if open
189 * is passed the EXCL, it must be a bug. We strip the flag here.
190 */
191 /* true args */
192 register struct vnode **vpp = &(ap->a_vp);
193 struct cnode *cp = VTOC(*vpp);
194 int flag = ap->a_mode & (~O_EXCL);
195 struct ucred *cred = ap->a_cred;
196 struct thread *td = ap->a_td;
197 /* locals */
198 int error;
199 struct vnode *vp;
200
201 MARK_ENTRY(CODA_OPEN_STATS);
202
203 /* Check for open of control file. */
204 if (IS_CTL_VP(*vpp)) {
205 /* XXX */
206 /* if (WRITEABLE(flag)) */
207 if (flag & (FWRITE | O_TRUNC | O_CREAT | O_EXCL)) {
208 MARK_INT_FAIL(CODA_OPEN_STATS);
209 return(EACCES);
210 }
211 MARK_INT_SAT(CODA_OPEN_STATS);
212 return(0);
213 }
214
215 error = venus_open(vtomi((*vpp)), &cp->c_fid, flag, cred, td->td_proc, &vp);
216 if (error)
217 return (error);
218
219 CODADEBUG( CODA_OPEN,myprintf(("open: vp %p result %d\n", vp, error));)
220
221 /* Save the vnode pointer for the cache file. */
222 if (cp->c_ovp == NULL) {
223 cp->c_ovp = vp;
224 } else {
225 if (cp->c_ovp != vp)
226 panic("coda_open: cp->c_ovp != ITOV(ip)");
227 }
228 cp->c_ocount++;
229
230 /* Flush the attribute cached if writing the file. */
231 if (flag & FWRITE) {
232 cp->c_owrite++;
233 cp->c_flags &= ~C_VATTR;
234 }
235
236 /* Open the cache file. */
237 error = VOP_OPEN(vp, flag, cred, td, NULL);
238 if (error) {
239 printf("coda_open: VOP_OPEN on container failed %d\n", error);
240 return (error);
241 } else {
242 (*vpp)->v_object = vp->v_object;
243 }
244 /* grab (above) does this when it calls newvnode unless it's in the cache*/
245
246 return(error);
247 }
248
249 /*
250 * Close the cache file used for I/O and notify Venus.
251 */
252 int
253 coda_close(struct vop_close_args *ap)
254 {
255 /* true args */
256 struct vnode *vp = ap->a_vp;
257 struct cnode *cp = VTOC(vp);
258 int flag = ap->a_fflag;
259 struct ucred *cred = ap->a_cred;
260 struct thread *td = ap->a_td;
261 /* locals */
262 int error;
263
264 MARK_ENTRY(CODA_CLOSE_STATS);
265
266 /* Check for close of control file. */
267 if (IS_CTL_VP(vp)) {
268 MARK_INT_SAT(CODA_CLOSE_STATS);
269 return(0);
270 }
271
272 if (cp->c_ovp) {
273 VOP_CLOSE(cp->c_ovp, flag, cred, td); /* Do errors matter here? */
274 vrele(cp->c_ovp);
275 }
276 #ifdef CODA_VERBOSE
277 else printf("coda_close: NO container vp %p/cp %p\n", vp, cp);
278 #endif
279
280 if (--cp->c_ocount == 0)
281 cp->c_ovp = NULL;
282
283 if (flag & FWRITE) /* file was opened for write */
284 --cp->c_owrite;
285
286 if (!IS_UNMOUNTING(cp))
287 error = venus_close(vtomi(vp), &cp->c_fid, flag, cred, td->td_proc);
288 else error = ENODEV;
289
290 CODADEBUG(CODA_CLOSE, myprintf(("close: result %d\n",error)); )
291 return(error);
292 }
293
294 int
295 coda_read(struct vop_read_args *ap)
296 {
297
298 ENTRY;
299 return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_READ,
300 ap->a_ioflag, ap->a_cred, ap->a_uio->uio_td));
301 }
302
303 int
304 coda_write(struct vop_write_args *ap)
305 {
306
307 ENTRY;
308 return(coda_rdwr(ap->a_vp, ap->a_uio, UIO_WRITE,
309 ap->a_ioflag, ap->a_cred, ap->a_uio->uio_td));
310 }
311
312 int
313 coda_rdwr(struct vnode *vp, struct uio *uiop, enum uio_rw rw, int ioflag,
314 struct ucred *cred, struct thread *td)
315 {
316 /* upcall decl */
317 /* NOTE: container file operation!!! */
318 /* locals */
319 struct cnode *cp = VTOC(vp);
320 struct vnode *cfvp = cp->c_ovp;
321 int opened_internally = 0;
322 int error = 0;
323
324 MARK_ENTRY(CODA_RDWR_STATS);
325
326 CODADEBUG(CODA_RDWR, myprintf(("coda_rdwr(%d, %p, %d, %lld, %d)\n", rw,
327 (void *)uiop->uio_iov->iov_base, uiop->uio_resid,
328 (long long)uiop->uio_offset, uiop->uio_segflg)); )
329
330 /* Check for rdwr of control object. */
331 if (IS_CTL_VP(vp)) {
332 MARK_INT_FAIL(CODA_RDWR_STATS);
333 return(EINVAL);
334 }
335
336 /*
337 * If file is not already open this must be a page {read,write} request
338 * and we should open it internally.
339 */
340 if (cfvp == NULL) {
341 opened_internally = 1;
342 MARK_INT_GEN(CODA_OPEN_STATS);
343 error = VOP_OPEN(vp, (rw == UIO_READ ? FREAD : FWRITE), cred, td, NULL);
344 #ifdef CODA_VERBOSE
345 printf("coda_rdwr: Internally Opening %p\n", vp);
346 #endif
347 if (error) {
348 printf("coda_rdwr: VOP_OPEN on container failed %d\n", error);
349 return (error);
350 }
351 cfvp = cp->c_ovp;
352 }
353
354 /* Have UFS handle the call. */
355 CODADEBUG(CODA_RDWR, myprintf(("indirect rdwr: fid = %s, refcnt = %d\n",
356 coda_f2s(&cp->c_fid), CTOV(cp)->v_usecount)); )
357 if (rw == UIO_READ) {
358 error = VOP_READ(cfvp, uiop, ioflag, cred);
359 } else {
360 error = VOP_WRITE(cfvp, uiop, ioflag, cred);
361 /* ufs_write updates the vnode_pager_setsize for the vnode/object */
362
363 { struct vattr attr;
364
365 if (VOP_GETATTR(cfvp, &attr, cred, td) == 0) {
366 vnode_pager_setsize(vp, attr.va_size);
367 }
368 }
369 }
370
371 if (error)
372 MARK_INT_FAIL(CODA_RDWR_STATS);
373 else
374 MARK_INT_SAT(CODA_RDWR_STATS);
375
376 /* Do an internal close if necessary. */
377 if (opened_internally) {
378 MARK_INT_GEN(CODA_CLOSE_STATS);
379 (void)VOP_CLOSE(vp, (rw == UIO_READ ? FREAD : FWRITE), cred, td);
380 }
381
382 /* Invalidate cached attributes if writing. */
383 if (rw == UIO_WRITE)
384 cp->c_flags &= ~C_VATTR;
385 return(error);
386 }
387
388
389
390 int
391 coda_ioctl(struct vop_ioctl_args *ap)
392 {
393 /* true args */
394 struct vnode *vp = ap->a_vp;
395 int com = ap->a_command;
396 caddr_t data = ap->a_data;
397 int flag = ap->a_fflag;
398 struct ucred *cred = ap->a_cred;
399 struct thread *td = ap->a_td;
400 /* locals */
401 int error;
402 struct vnode *tvp;
403 struct nameidata ndp;
404 struct PioctlData *iap = (struct PioctlData *)data;
405
406 MARK_ENTRY(CODA_IOCTL_STATS);
407
408 CODADEBUG(CODA_IOCTL, myprintf(("in coda_ioctl on %s\n", iap->path));)
409
410 /* Don't check for operation on a dying object, for ctlvp it
411 shouldn't matter */
412
413 /* Must be control object to succeed. */
414 if (!IS_CTL_VP(vp)) {
415 MARK_INT_FAIL(CODA_IOCTL_STATS);
416 CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: vp != ctlvp"));)
417 return (EOPNOTSUPP);
418 }
419 /* Look up the pathname. */
420
421 /* Should we use the name cache here? It would get it from
422 lookupname sooner or later anyway, right? */
423
424 NDINIT(&ndp, LOOKUP, (iap->follow ? FOLLOW : NOFOLLOW), UIO_USERSPACE, iap->path, td);
425 error = namei(&ndp);
426 tvp = ndp.ni_vp;
427
428 if (error) {
429 MARK_INT_FAIL(CODA_IOCTL_STATS);
430 CODADEBUG(CODA_IOCTL, myprintf(("coda_ioctl error: lookup returns %d\n",
431 error));)
432 return(error);
433 }
434
435 /*
436 * Make sure this is a coda style cnode, but it may be a
437 * different vfsp
438 */
439 if (tvp->v_op != &coda_vnodeops) {
440 vrele(tvp);
441 NDFREE(&ndp, NDF_ONLY_PNBUF);
442 MARK_INT_FAIL(CODA_IOCTL_STATS);
443 CODADEBUG(CODA_IOCTL,
444 myprintf(("coda_ioctl error: %s not a coda object\n",
445 iap->path));)
446 return(EINVAL);
447 }
448
449 if (iap->vi.in_size > VC_MAXDATASIZE) {
450 NDFREE(&ndp, 0);
451 return(EINVAL);
452 }
453 error = venus_ioctl(vtomi(tvp), &((VTOC(tvp))->c_fid), com, flag, data, cred, td->td_proc);
454
455 if (error)
456 MARK_INT_FAIL(CODA_IOCTL_STATS);
457 else
458 CODADEBUG(CODA_IOCTL, myprintf(("Ioctl returns %d \n", error)); )
459
460 vrele(tvp);
461 NDFREE(&ndp, NDF_ONLY_PNBUF);
462 return(error);
463 }
464
465 /*
466 * To reduce the cost of a user-level venus;we cache attributes in
467 * the kernel. Each cnode has storage allocated for an attribute. If
468 * c_vattr is valid, return a reference to it. Otherwise, get the
469 * attributes from venus and store them in the cnode. There is some
470 * question if this method is a security leak. But I think that in
471 * order to make this call, the user must have done a lookup and
472 * opened the file, and therefore should already have access.
473 */
474 int
475 coda_getattr(struct vop_getattr_args *ap)
476 {
477 /* true args */
478 struct vnode *vp = ap->a_vp;
479 struct cnode *cp = VTOC(vp);
480 struct vattr *vap = ap->a_vap;
481 struct ucred *cred = ap->a_cred;
482 struct thread *td = ap->a_td;
483 /* locals */
484 int error;
485
486 MARK_ENTRY(CODA_GETATTR_STATS);
487
488 if (IS_UNMOUNTING(cp))
489 return ENODEV;
490
491 /* Check for getattr of control object. */
492 if (IS_CTL_VP(vp)) {
493 MARK_INT_FAIL(CODA_GETATTR_STATS);
494 return(ENOENT);
495 }
496
497 /* Check to see if the attributes have already been cached */
498 if (VALID_VATTR(cp)) {
499 CODADEBUG(CODA_GETATTR, { myprintf(("attr cache hit: %s\n",
500 coda_f2s(&cp->c_fid)));});
501 CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
502 print_vattr(&cp->c_vattr); );
503
504 *vap = cp->c_vattr;
505 MARK_INT_SAT(CODA_GETATTR_STATS);
506 return(0);
507 }
508
509 error = venus_getattr(vtomi(vp), &cp->c_fid, cred, td->td_proc, vap);
510
511 if (!error) {
512 CODADEBUG(CODA_GETATTR, myprintf(("getattr miss %s: result %d\n",
513 coda_f2s(&cp->c_fid), error)); )
514
515 CODADEBUG(CODA_GETATTR, if (!(codadebug & ~CODA_GETATTR))
516 print_vattr(vap); );
517
518 { int size = vap->va_size;
519 struct vnode *convp = cp->c_ovp;
520 if (convp != (struct vnode *)0) {
521 vnode_pager_setsize(convp, size);
522 }
523 }
524 /* If not open for write, store attributes in cnode */
525 if ((cp->c_owrite == 0) && (coda_attr_cache)) {
526 cp->c_vattr = *vap;
527 cp->c_flags |= C_VATTR;
528 }
529
530 }
531 return(error);
532 }
533
534 int
535 coda_setattr(struct vop_setattr_args *ap)
536 {
537 /* true args */
538 register struct vnode *vp = ap->a_vp;
539 struct cnode *cp = VTOC(vp);
540 register struct vattr *vap = ap->a_vap;
541 struct ucred *cred = ap->a_cred;
542 struct thread *td = ap->a_td;
543 /* locals */
544 int error;
545
546 MARK_ENTRY(CODA_SETATTR_STATS);
547
548 /* Check for setattr of control object. */
549 if (IS_CTL_VP(vp)) {
550 MARK_INT_FAIL(CODA_SETATTR_STATS);
551 return(ENOENT);
552 }
553
554 if (codadebug & CODADBGMSK(CODA_SETATTR)) {
555 print_vattr(vap);
556 }
557 error = venus_setattr(vtomi(vp), &cp->c_fid, vap, cred, td->td_proc);
558
559 if (!error)
560 cp->c_flags &= ~C_VATTR;
561
562 { int size = vap->va_size;
563 struct vnode *convp = cp->c_ovp;
564 if (size != VNOVAL && convp != (struct vnode *)0) {
565 vnode_pager_setsize(convp, size);
566 }
567 }
568 CODADEBUG(CODA_SETATTR, myprintf(("setattr %d\n", error)); )
569 return(error);
570 }
571
572 int
573 coda_access(struct vop_access_args *ap)
574 {
575 /* true args */
576 struct vnode *vp = ap->a_vp;
577 struct cnode *cp = VTOC(vp);
578 int mode = ap->a_mode;
579 struct ucred *cred = ap->a_cred;
580 struct thread *td = ap->a_td;
581 /* locals */
582 int error;
583
584 MARK_ENTRY(CODA_ACCESS_STATS);
585
586 /* Check for access of control object. Only read access is
587 allowed on it. */
588 if (IS_CTL_VP(vp)) {
589 /* bogus hack - all will be marked as successes */
590 MARK_INT_SAT(CODA_ACCESS_STATS);
591 return(((mode & VREAD) && !(mode & (VWRITE | VEXEC)))
592 ? 0 : EACCES);
593 }
594
595 /*
596 * if the file is a directory, and we are checking exec (eg lookup)
597 * access, and the file is in the namecache, then the user must have
598 * lookup access to it.
599 */
600 if (coda_access_cache) {
601 if ((vp->v_type == VDIR) && (mode & VEXEC)) {
602 if (coda_nc_lookup(cp, ".", 1, cred)) {
603 MARK_INT_SAT(CODA_ACCESS_STATS);
604 return(0); /* it was in the cache */
605 }
606 }
607 }
608
609 error = venus_access(vtomi(vp), &cp->c_fid, mode, cred, td->td_proc);
610
611 return(error);
612 }
613
614 int
615 coda_readlink(struct vop_readlink_args *ap)
616 {
617 /* true args */
618 struct vnode *vp = ap->a_vp;
619 struct cnode *cp = VTOC(vp);
620 struct uio *uiop = ap->a_uio;
621 struct ucred *cred = ap->a_cred;
622 struct thread *td = ap->a_uio->uio_td;
623 /* locals */
624 int error;
625 char *str;
626 int len;
627
628 MARK_ENTRY(CODA_READLINK_STATS);
629
630 /* Check for readlink of control object. */
631 if (IS_CTL_VP(vp)) {
632 MARK_INT_FAIL(CODA_READLINK_STATS);
633 return(ENOENT);
634 }
635
636 if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) { /* symlink was cached */
637 uiop->uio_rw = UIO_READ;
638 error = uiomove(cp->c_symlink, (int)cp->c_symlen, uiop);
639 if (error)
640 MARK_INT_FAIL(CODA_READLINK_STATS);
641 else
642 MARK_INT_SAT(CODA_READLINK_STATS);
643 return(error);
644 }
645
646 error = venus_readlink(vtomi(vp), &cp->c_fid, cred,
647 td != NULL ? td->td_proc : NULL, &str, &len);
648
649 if (!error) {
650 uiop->uio_rw = UIO_READ;
651 error = uiomove(str, len, uiop);
652
653 if (coda_symlink_cache) {
654 cp->c_symlink = str;
655 cp->c_symlen = len;
656 cp->c_flags |= C_SYMLINK;
657 } else
658 CODA_FREE(str, len);
659 }
660
661 CODADEBUG(CODA_READLINK, myprintf(("in readlink result %d\n",error));)
662 return(error);
663 }
664
665 int
666 coda_fsync(struct vop_fsync_args *ap)
667 {
668 /* true args */
669 struct vnode *vp = ap->a_vp;
670 struct cnode *cp = VTOC(vp);
671 struct thread *td = ap->a_td;
672 /* locals */
673 struct vnode *convp = cp->c_ovp;
674 int error;
675
676 MARK_ENTRY(CODA_FSYNC_STATS);
677
678 /* Check for fsync on an unmounting object */
679 /* The NetBSD kernel, in it's infinite wisdom, can try to fsync
680 * after an unmount has been initiated. This is a Bad Thing,
681 * which we have to avoid. Not a legitimate failure for stats.
682 */
683 if (IS_UNMOUNTING(cp)) {
684 return(ENODEV);
685 }
686
687 /* Check for fsync of control object. */
688 if (IS_CTL_VP(vp)) {
689 MARK_INT_SAT(CODA_FSYNC_STATS);
690 return(0);
691 }
692
693 if (convp)
694 VOP_FSYNC(convp, MNT_WAIT, td);
695
696 /*
697 * We see fsyncs with usecount == 1 then usecount == 0.
698 * For now we ignore them.
699 */
700 /*
701 VI_LOCK(vp);
702 if (!vp->v_usecount) {
703 printf("coda_fsync on vnode %p with %d usecount. c_flags = %x (%x)\n",
704 vp, vp->v_usecount, cp->c_flags, cp->c_flags&C_PURGING);
705 }
706 VI_UNLOCK(vp);
707 */
708
709 /*
710 * We can expect fsync on any vnode at all if venus is pruging it.
711 * Venus can't very well answer the fsync request, now can it?
712 * Hopefully, it won't have to, because hopefully, venus preserves
713 * the (possibly untrue) invariant that it never purges an open
714 * vnode. Hopefully.
715 */
716 if (cp->c_flags & C_PURGING) {
717 return(0);
718 }
719
720 /* needs research */
721 return 0;
722 error = venus_fsync(vtomi(vp), &cp->c_fid, td->td_proc);
723
724 CODADEBUG(CODA_FSYNC, myprintf(("in fsync result %d\n",error)); );
725 return(error);
726 }
727
728 int
729 coda_inactive(struct vop_inactive_args *ap)
730 {
731 /* XXX - at the moment, inactive doesn't look at cred, and doesn't
732 have a proc pointer. Oops. */
733 /* true args */
734 struct vnode *vp = ap->a_vp;
735 struct cnode *cp = VTOC(vp);
736 struct ucred *cred __attribute__((unused)) = NULL;
737 struct thread *td __attribute__((unused)) = curthread;
738 /* upcall decl */
739 /* locals */
740
741 /* We don't need to send inactive to venus - DCS */
742 MARK_ENTRY(CODA_INACTIVE_STATS);
743
744 CODADEBUG(CODA_INACTIVE, myprintf(("in inactive, %s, vfsp %p\n",
745 coda_f2s(&cp->c_fid), vp->v_mount));)
746
747 vp->v_object = NULL;
748
749 /* If an array has been allocated to hold the symlink, deallocate it */
750 if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) {
751 if (cp->c_symlink == NULL)
752 panic("coda_inactive: null symlink pointer in cnode");
753
754 CODA_FREE(cp->c_symlink, cp->c_symlen);
755 cp->c_flags &= ~C_SYMLINK;
756 cp->c_symlen = 0;
757 }
758
759 /* Remove it from the table so it can't be found. */
760 coda_unsave(cp);
761 if ((struct coda_mntinfo *)(vp->v_mount->mnt_data) == NULL) {
762 myprintf(("Help! vfsp->vfs_data was NULL, but vnode %p wasn't dying\n", vp));
763 panic("badness in coda_inactive\n");
764 }
765
766 if (IS_UNMOUNTING(cp)) {
767 #ifdef DEBUG
768 printf("coda_inactive: IS_UNMOUNTING use %d: vp %p, cp %p\n", vrefcnt(vp), vp, cp);
769 if (cp->c_ovp != NULL)
770 printf("coda_inactive: cp->ovp != NULL use %d: vp %p, cp %p\n",
771 vrefcnt(vp), vp, cp);
772 #endif
773 } else {
774 #ifdef OLD_DIAGNOSTIC
775 if (vrefcnt(CTOV(cp))) {
776 panic("coda_inactive: nonzero reference count");
777 }
778 if (cp->c_ovp != NULL) {
779 panic("coda_inactive: cp->ovp != NULL");
780 }
781 #endif
782 vgone(vp);
783 }
784
785 MARK_INT_SAT(CODA_INACTIVE_STATS);
786 return(0);
787 }
788
789 /*
790 * Remote filesystem operations having to do with directory manipulation.
791 */
792
793 /*
794 * It appears that in NetBSD, lookup is supposed to return the vnode locked
795 */
796 int
797 coda_lookup(struct vop_lookup_args *ap)
798 {
799 /* true args */
800 struct vnode *dvp = ap->a_dvp;
801 struct cnode *dcp = VTOC(dvp);
802 struct vnode **vpp = ap->a_vpp;
803 /*
804 * It looks as though ap->a_cnp->ni_cnd->cn_nameptr holds the rest
805 * of the string to xlate, and that we must try to get at least
806 * ap->a_cnp->ni_cnd->cn_namelen of those characters to macth. I
807 * could be wrong.
808 */
809 struct componentname *cnp = ap->a_cnp;
810 struct ucred *cred = cnp->cn_cred;
811 struct thread *td = cnp->cn_thread;
812 /* locals */
813 struct cnode *cp;
814 const char *nm = cnp->cn_nameptr;
815 int len = cnp->cn_namelen;
816 CodaFid VFid;
817 int vtype;
818 int error = 0;
819
820 MARK_ENTRY(CODA_LOOKUP_STATS);
821
822 CODADEBUG(CODA_LOOKUP, myprintf(("lookup: %s in %s\n",
823 nm, coda_f2s(&dcp->c_fid))););
824
825 /* Check for lookup of control object. */
826 if (IS_CTL_NAME(dvp, nm, len)) {
827 *vpp = coda_ctlvp;
828 vref(*vpp);
829 MARK_INT_SAT(CODA_LOOKUP_STATS);
830 goto exit;
831 }
832
833 if (len+1 > CODA_MAXNAMLEN) {
834 MARK_INT_FAIL(CODA_LOOKUP_STATS);
835
836 CODADEBUG(CODA_LOOKUP, myprintf(("name too long: lookup, %s (%s)\n",
837 coda_f2s(&dcp->c_fid), nm)););
838 *vpp = (struct vnode *)0;
839 error = EINVAL;
840 goto exit;
841 }
842 /* First try to look the file up in the cfs name cache */
843 /* lock the parent vnode? */
844 cp = coda_nc_lookup(dcp, nm, len, cred);
845 if (cp) {
846 *vpp = CTOV(cp);
847 vref(*vpp);
848 CODADEBUG(CODA_LOOKUP,
849 myprintf(("lookup result %d vpp %p\n",error,*vpp));)
850 } else {
851
852 /* The name wasn't cached, so we need to contact Venus */
853 error = venus_lookup(vtomi(dvp), &dcp->c_fid, nm, len, cred, td->td_proc, &VFid, &vtype);
854
855 if (error) {
856 MARK_INT_FAIL(CODA_LOOKUP_STATS);
857
858 CODADEBUG(CODA_LOOKUP, myprintf(("lookup error on %s (%s)%d\n",
859 coda_f2s(&dcp->c_fid), nm, error));)
860 *vpp = (struct vnode *)0;
861 } else {
862 MARK_INT_SAT(CODA_LOOKUP_STATS);
863 CODADEBUG(CODA_LOOKUP,
864 myprintf(("lookup: %s type %o result %d\n",
865 coda_f2s(&VFid), vtype, error)); )
866 cp = make_coda_node(&VFid, dvp->v_mount, vtype);
867 *vpp = CTOV(cp);
868
869 /* enter the new vnode in the Name Cache only if the top bit isn't set */
870 /* And don't enter a new vnode for an invalid one! */
871 if (!(vtype & CODA_NOCACHE))
872 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
873 }
874 }
875
876 exit:
877 /*
878 * If we are creating, and this was the last name to be looked up,
879 * and the error was ENOENT, then there really shouldn't be an
880 * error and we can make the leaf NULL and return success. Since
881 * this is supposed to work under Mach as well as NetBSD, we're
882 * leaving this fn wrapped. We also must tell lookup/namei that
883 * we need to save the last component of the name. (Create will
884 * have to free the name buffer later...lucky us...)
885 */
886 if (((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME))
887 && (cnp->cn_flags & ISLASTCN)
888 && (error == ENOENT))
889 {
890 error = EJUSTRETURN;
891 cnp->cn_flags |= SAVENAME;
892 *ap->a_vpp = NULL;
893 }
894
895 /*
896 * If we are removing, and we are at the last element, and we
897 * found it, then we need to keep the name around so that the
898 * removal will go ahead as planned. Unfortunately, this will
899 * probably also lock the to-be-removed vnode, which may or may
900 * not be a good idea. I'll have to look at the bits of
901 * coda_remove to make sure. We'll only save the name if we did in
902 * fact find the name, otherwise coda_remove won't have a chance
903 * to free the pathname.
904 */
905 if ((cnp->cn_nameiop == DELETE)
906 && (cnp->cn_flags & ISLASTCN)
907 && !error)
908 {
909 cnp->cn_flags |= SAVENAME;
910 }
911
912 /*
913 * If the lookup went well, we need to (potentially?) unlock the
914 * parent, and lock the child. We are only responsible for
915 * checking to see if the parent is supposed to be unlocked before
916 * we return. We must always lock the child (provided there is
917 * one, and (the parent isn't locked or it isn't the same as the
918 * parent.) Simple, huh? We can never leave the parent locked unless
919 * we are ISLASTCN
920 */
921 if (!error || (error == EJUSTRETURN)) {
922 if (cnp->cn_flags & ISDOTDOT) {
923 if ((error = VOP_UNLOCK(dvp, 0, td))) {
924 return error;
925 }
926 /*
927 * The parent is unlocked. As long as there is a child,
928 * lock it without bothering to check anything else.
929 */
930 if (*ap->a_vpp) {
931 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, td);
932 }
933 vn_lock(dvp, LK_RETRY|LK_EXCLUSIVE, td);
934 } else {
935 /* The parent is locked, and may be the same as the child */
936 if (*ap->a_vpp && (*ap->a_vpp != dvp)) {
937 /* Different, go ahead and lock it. */
938 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, td);
939 }
940 }
941 } else {
942 /* If the lookup failed, we need to ensure that the leaf is NULL */
943 /* Don't change any locking? */
944 *ap->a_vpp = NULL;
945 }
946 return(error);
947 }
948
949 /*ARGSUSED*/
950 int
951 coda_create(struct vop_create_args *ap)
952 {
953 /* true args */
954 struct vnode *dvp = ap->a_dvp;
955 struct cnode *dcp = VTOC(dvp);
956 struct vattr *va = ap->a_vap;
957 int exclusive = 1;
958 int mode = ap->a_vap->va_mode;
959 struct vnode **vpp = ap->a_vpp;
960 struct componentname *cnp = ap->a_cnp;
961 struct ucred *cred = cnp->cn_cred;
962 struct thread *td = cnp->cn_thread;
963 /* locals */
964 int error;
965 struct cnode *cp;
966 const char *nm = cnp->cn_nameptr;
967 int len = cnp->cn_namelen;
968 CodaFid VFid;
969 struct vattr attr;
970
971 MARK_ENTRY(CODA_CREATE_STATS);
972
973 /* All creates are exclusive XXX */
974 /* I'm assuming the 'mode' argument is the file mode bits XXX */
975
976 /* Check for create of control object. */
977 if (IS_CTL_NAME(dvp, nm, len)) {
978 *vpp = (struct vnode *)0;
979 MARK_INT_FAIL(CODA_CREATE_STATS);
980 return(EACCES);
981 }
982
983 error = venus_create(vtomi(dvp), &dcp->c_fid, nm, len, exclusive, mode, va, cred, td->td_proc, &VFid, &attr);
984
985 if (!error) {
986
987 /* If this is an exclusive create, panic if the file already exists. */
988 /* Venus should have detected the file and reported EEXIST. */
989
990 if ((exclusive == 1) &&
991 (coda_find(&VFid) != NULL))
992 panic("cnode existed for newly created file!");
993
994 cp = make_coda_node(&VFid, dvp->v_mount, attr.va_type);
995 *vpp = CTOV(cp);
996
997 /* Update va to reflect the new attributes. */
998 (*va) = attr;
999
1000 /* Update the attribute cache and mark it as valid */
1001 if (coda_attr_cache) {
1002 VTOC(*vpp)->c_vattr = attr;
1003 VTOC(*vpp)->c_flags |= C_VATTR;
1004 }
1005
1006 /* Invalidate the parent's attr cache, the modification time has changed */
1007 VTOC(dvp)->c_flags &= ~C_VATTR;
1008
1009 /* enter the new vnode in the Name Cache */
1010 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
1011
1012 CODADEBUG(CODA_CREATE,
1013 myprintf(("create: %s, result %d\n",
1014 coda_f2s(&VFid), error)); )
1015 } else {
1016 *vpp = (struct vnode *)0;
1017 CODADEBUG(CODA_CREATE, myprintf(("create error %d\n", error));)
1018 }
1019
1020 if (!error) {
1021 if (cnp->cn_flags & LOCKLEAF) {
1022 vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, td);
1023 }
1024 #ifdef OLD_DIAGNOSTIC
1025 else {
1026 printf("coda_create: LOCKLEAF not set!\n");
1027 }
1028 #endif
1029 }
1030 return(error);
1031 }
1032
1033 int
1034 coda_remove(struct vop_remove_args *ap)
1035 {
1036 /* true args */
1037 struct vnode *dvp = ap->a_dvp;
1038 struct cnode *cp = VTOC(dvp);
1039 struct componentname *cnp = ap->a_cnp;
1040 struct ucred *cred = cnp->cn_cred;
1041 struct thread *td = cnp->cn_thread;
1042 /* locals */
1043 int error;
1044 const char *nm = cnp->cn_nameptr;
1045 int len = cnp->cn_namelen;
1046 struct cnode *tp;
1047
1048 MARK_ENTRY(CODA_REMOVE_STATS);
1049
1050 CODADEBUG(CODA_REMOVE, myprintf(("remove: %s in %s\n",
1051 nm, coda_f2s(&cp->c_fid))););
1052 /* Remove the file's entry from the CODA Name Cache */
1053 /* We're being conservative here, it might be that this person
1054 * doesn't really have sufficient access to delete the file
1055 * but we feel zapping the entry won't really hurt anyone -- dcs
1056 */
1057 /* I'm gonna go out on a limb here. If a file and a hardlink to it
1058 * exist, and one is removed, the link count on the other will be
1059 * off by 1. We could either invalidate the attrs if cached, or
1060 * fix them. I'll try to fix them. DCS 11/8/94
1061 */
1062 tp = coda_nc_lookup(VTOC(dvp), nm, len, cred);
1063 if (tp) {
1064 if (VALID_VATTR(tp)) { /* If attrs are cached */
1065 if (tp->c_vattr.va_nlink > 1) { /* If it's a hard link */
1066 tp->c_vattr.va_nlink--;
1067 }
1068 }
1069
1070 coda_nc_zapfile(VTOC(dvp), nm, len);
1071 /* No need to flush it if it doesn't exist! */
1072 }
1073 /* Invalidate the parent's attr cache, the modification time has changed */
1074 VTOC(dvp)->c_flags &= ~C_VATTR;
1075
1076 /* Check for remove of control object. */
1077 if (IS_CTL_NAME(dvp, nm, len)) {
1078 MARK_INT_FAIL(CODA_REMOVE_STATS);
1079 return(ENOENT);
1080 }
1081
1082 error = venus_remove(vtomi(dvp), &cp->c_fid, nm, len, cred, td->td_proc);
1083
1084 CODADEBUG(CODA_REMOVE, myprintf(("in remove result %d\n",error)); )
1085
1086 return(error);
1087 }
1088
1089 int
1090 coda_link(struct vop_link_args *ap)
1091 {
1092 /* true args */
1093 struct vnode *vp = ap->a_vp;
1094 struct cnode *cp = VTOC(vp);
1095 struct vnode *tdvp = ap->a_tdvp;
1096 struct cnode *tdcp = VTOC(tdvp);
1097 struct componentname *cnp = ap->a_cnp;
1098 struct ucred *cred = cnp->cn_cred;
1099 struct thread *td = cnp->cn_thread;
1100 /* locals */
1101 int error;
1102 const char *nm = cnp->cn_nameptr;
1103 int len = cnp->cn_namelen;
1104
1105 MARK_ENTRY(CODA_LINK_STATS);
1106
1107 if (codadebug & CODADBGMSK(CODA_LINK)) {
1108 myprintf(("nb_link: vp fid: %s\n",
1109 coda_f2s(&cp->c_fid)));
1110 myprintf(("nb_link: tdvp fid: %s)\n",
1111 coda_f2s(&tdcp->c_fid)));
1112 }
1113 if (codadebug & CODADBGMSK(CODA_LINK)) {
1114 myprintf(("link: vp fid: %s\n",
1115 coda_f2s(&cp->c_fid)));
1116 myprintf(("link: tdvp fid: %s\n",
1117 coda_f2s(&tdcp->c_fid)));
1118 }
1119
1120 /* Check for link to/from control object. */
1121 if (IS_CTL_NAME(tdvp, nm, len) || IS_CTL_VP(vp)) {
1122 MARK_INT_FAIL(CODA_LINK_STATS);
1123 return(EACCES);
1124 }
1125
1126 error = venus_link(vtomi(vp), &cp->c_fid, &tdcp->c_fid, nm, len, cred, td->td_proc);
1127
1128 /* Invalidate the parent's attr cache, the modification time has changed */
1129 VTOC(tdvp)->c_flags &= ~C_VATTR;
1130 VTOC(vp)->c_flags &= ~C_VATTR;
1131
1132 CODADEBUG(CODA_LINK, myprintf(("in link result %d\n",error)); )
1133
1134 return(error);
1135 }
1136
1137 int
1138 coda_rename(struct vop_rename_args *ap)
1139 {
1140 /* true args */
1141 struct vnode *odvp = ap->a_fdvp;
1142 struct cnode *odcp = VTOC(odvp);
1143 struct componentname *fcnp = ap->a_fcnp;
1144 struct vnode *ndvp = ap->a_tdvp;
1145 struct cnode *ndcp = VTOC(ndvp);
1146 struct componentname *tcnp = ap->a_tcnp;
1147 struct ucred *cred = fcnp->cn_cred;
1148 struct thread *td = fcnp->cn_thread;
1149 /* true args */
1150 int error;
1151 const char *fnm = fcnp->cn_nameptr;
1152 int flen = fcnp->cn_namelen;
1153 const char *tnm = tcnp->cn_nameptr;
1154 int tlen = tcnp->cn_namelen;
1155
1156 MARK_ENTRY(CODA_RENAME_STATS);
1157
1158 /* Hmmm. The vnodes are already looked up. Perhaps they are locked?
1159 This could be Bad. XXX */
1160 #ifdef OLD_DIAGNOSTIC
1161 if ((fcnp->cn_cred != tcnp->cn_cred)
1162 || (fcnp->cn_thread != tcnp->cn_thread))
1163 {
1164 panic("coda_rename: component names don't agree");
1165 }
1166 #endif
1167
1168 /* Check for rename involving control object. */
1169 if (IS_CTL_NAME(odvp, fnm, flen) || IS_CTL_NAME(ndvp, tnm, tlen)) {
1170 MARK_INT_FAIL(CODA_RENAME_STATS);
1171 return(EACCES);
1172 }
1173
1174 /* Problem with moving directories -- need to flush entry for .. */
1175 if (odvp != ndvp) {
1176 struct cnode *ovcp = coda_nc_lookup(VTOC(odvp), fnm, flen, cred);
1177 if (ovcp) {
1178 struct vnode *ovp = CTOV(ovcp);
1179 if ((ovp) &&
1180 (ovp->v_type == VDIR)) /* If it's a directory */
1181 coda_nc_zapfile(VTOC(ovp),"..", 2);
1182 }
1183 }
1184
1185 /* Remove the entries for both source and target files */
1186 coda_nc_zapfile(VTOC(odvp), fnm, flen);
1187 coda_nc_zapfile(VTOC(ndvp), tnm, tlen);
1188
1189 /* Invalidate the parent's attr cache, the modification time has changed */
1190 VTOC(odvp)->c_flags &= ~C_VATTR;
1191 VTOC(ndvp)->c_flags &= ~C_VATTR;
1192
1193 if (flen+1 > CODA_MAXNAMLEN) {
1194 MARK_INT_FAIL(CODA_RENAME_STATS);
1195 error = EINVAL;
1196 goto exit;
1197 }
1198
1199 if (tlen+1 > CODA_MAXNAMLEN) {
1200 MARK_INT_FAIL(CODA_RENAME_STATS);
1201 error = EINVAL;
1202 goto exit;
1203 }
1204
1205 error = venus_rename(vtomi(odvp), &odcp->c_fid, &ndcp->c_fid, fnm, flen, tnm, tlen, cred, td->td_proc);
1206
1207 exit:
1208 CODADEBUG(CODA_RENAME, myprintf(("in rename result %d\n",error));)
1209 /* XXX - do we need to call cache pureg on the moved vnode? */
1210 cache_purge(ap->a_fvp);
1211
1212 /* Release parents first, then children. */
1213 vrele(odvp);
1214 if (ap->a_tvp) {
1215 if (ap->a_tvp == ndvp)
1216 vrele(ndvp);
1217 else
1218 vput(ndvp);
1219 vput(ap->a_tvp);
1220 } else
1221 vput(ndvp);
1222 vrele(ap->a_fvp);
1223
1224 return(error);
1225 }
1226
1227 int
1228 coda_mkdir(struct vop_mkdir_args *ap)
1229 {
1230 /* true args */
1231 struct vnode *dvp = ap->a_dvp;
1232 struct cnode *dcp = VTOC(dvp);
1233 struct componentname *cnp = ap->a_cnp;
1234 register struct vattr *va = ap->a_vap;
1235 struct vnode **vpp = ap->a_vpp;
1236 struct ucred *cred = cnp->cn_cred;
1237 struct thread *td = cnp->cn_thread;
1238 /* locals */
1239 int error;
1240 const char *nm = cnp->cn_nameptr;
1241 int len = cnp->cn_namelen;
1242 struct cnode *cp;
1243 CodaFid VFid;
1244 struct vattr ova;
1245
1246 MARK_ENTRY(CODA_MKDIR_STATS);
1247
1248 /* Check for mkdir of target object. */
1249 if (IS_CTL_NAME(dvp, nm, len)) {
1250 *vpp = (struct vnode *)0;
1251 MARK_INT_FAIL(CODA_MKDIR_STATS);
1252 return(EACCES);
1253 }
1254
1255 if (len+1 > CODA_MAXNAMLEN) {
1256 *vpp = (struct vnode *)0;
1257 MARK_INT_FAIL(CODA_MKDIR_STATS);
1258 return(EACCES);
1259 }
1260
1261 error = venus_mkdir(vtomi(dvp), &dcp->c_fid, nm, len, va, cred, td->td_proc, &VFid, &ova);
1262
1263 if (!error) {
1264 if (coda_find(&VFid) != NULL)
1265 panic("cnode existed for newly created directory!");
1266
1267
1268 cp = make_coda_node(&VFid, dvp->v_mount, va->va_type);
1269 *vpp = CTOV(cp);
1270
1271 /* enter the new vnode in the Name Cache */
1272 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp));
1273
1274 /* as a side effect, enter "." and ".." for the directory */
1275 coda_nc_enter(VTOC(*vpp), ".", 1, cred, VTOC(*vpp));
1276 coda_nc_enter(VTOC(*vpp), "..", 2, cred, VTOC(dvp));
1277
1278 if (coda_attr_cache) {
1279 VTOC(*vpp)->c_vattr = ova; /* update the attr cache */
1280 VTOC(*vpp)->c_flags |= C_VATTR; /* Valid attributes in cnode */
1281 }
1282
1283 /* Invalidate the parent's attr cache, the modification time has changed */
1284 VTOC(dvp)->c_flags &= ~C_VATTR;
1285
1286 vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, td);
1287
1288 CODADEBUG( CODA_MKDIR, myprintf(("mkdir: %s result %d\n",
1289 coda_f2s(&VFid), error)); )
1290 } else {
1291 *vpp = (struct vnode *)0;
1292 CODADEBUG(CODA_MKDIR, myprintf(("mkdir error %d\n",error));)
1293 }
1294
1295 return(error);
1296 }
1297
1298 int
1299 coda_rmdir(struct vop_rmdir_args *ap)
1300 {
1301 /* true args */
1302 struct vnode *dvp = ap->a_dvp;
1303 struct cnode *dcp = VTOC(dvp);
1304 struct componentname *cnp = ap->a_cnp;
1305 struct ucred *cred = cnp->cn_cred;
1306 struct thread *td = cnp->cn_thread;
1307 /* true args */
1308 int error;
1309 const char *nm = cnp->cn_nameptr;
1310 int len = cnp->cn_namelen;
1311 struct cnode *cp;
1312
1313 MARK_ENTRY(CODA_RMDIR_STATS);
1314
1315 /* Check for rmdir of control object. */
1316 if (IS_CTL_NAME(dvp, nm, len)) {
1317 MARK_INT_FAIL(CODA_RMDIR_STATS);
1318 return(ENOENT);
1319 }
1320
1321 /* We're being conservative here, it might be that this person
1322 * doesn't really have sufficient access to delete the file
1323 * but we feel zapping the entry won't really hurt anyone -- dcs
1324 */
1325 /*
1326 * As a side effect of the rmdir, remove any entries for children of
1327 * the directory, especially "." and "..".
1328 */
1329 cp = coda_nc_lookup(dcp, nm, len, cred);
1330 if (cp) coda_nc_zapParentfid(&(cp->c_fid), NOT_DOWNCALL);
1331
1332 /* Remove the file's entry from the CODA Name Cache */
1333 coda_nc_zapfile(dcp, nm, len);
1334
1335 /* Invalidate the parent's attr cache, the modification time has changed */
1336 dcp->c_flags &= ~C_VATTR;
1337
1338 error = venus_rmdir(vtomi(dvp), &dcp->c_fid, nm, len, cred, td->td_proc);
1339
1340 CODADEBUG(CODA_RMDIR, myprintf(("in rmdir result %d\n", error)); )
1341
1342 return(error);
1343 }
1344
1345 int
1346 coda_symlink(struct vop_symlink_args *ap)
1347 {
1348 /* true args */
1349 struct vnode *tdvp = ap->a_dvp;
1350 struct cnode *tdcp = VTOC(tdvp);
1351 struct componentname *cnp = ap->a_cnp;
1352 struct vattr *tva = ap->a_vap;
1353 char *path = ap->a_target;
1354 struct ucred *cred = cnp->cn_cred;
1355 struct thread *td = cnp->cn_thread;
1356 struct vnode **vpp = ap->a_vpp;
1357 /* locals */
1358 int error;
1359 /*
1360 * XXX I'm assuming the following things about coda_symlink's
1361 * arguments:
1362 * t(foo) is the new name/parent/etc being created.
1363 * lname is the contents of the new symlink.
1364 */
1365 char *nm = cnp->cn_nameptr;
1366 int len = cnp->cn_namelen;
1367 int plen = strlen(path);
1368
1369 /*
1370 * Here's the strategy for the moment: perform the symlink, then
1371 * do a lookup to grab the resulting vnode. I know this requires
1372 * two communications with Venus for a new sybolic link, but
1373 * that's the way the ball bounces. I don't yet want to change
1374 * the way the Mach symlink works. When Mach support is
1375 * deprecated, we should change symlink so that the common case
1376 * returns the resultant vnode in a vpp argument.
1377 */
1378
1379 MARK_ENTRY(CODA_SYMLINK_STATS);
1380
1381 /* Check for symlink of control object. */
1382 if (IS_CTL_NAME(tdvp, nm, len)) {
1383 MARK_INT_FAIL(CODA_SYMLINK_STATS);
1384 return(EACCES);
1385 }
1386
1387 if (plen+1 > CODA_MAXPATHLEN) {
1388 MARK_INT_FAIL(CODA_SYMLINK_STATS);
1389 return(EINVAL);
1390 }
1391
1392 if (len+1 > CODA_MAXNAMLEN) {
1393 MARK_INT_FAIL(CODA_SYMLINK_STATS);
1394 error = EINVAL;
1395 goto exit;
1396 }
1397
1398 error = venus_symlink(vtomi(tdvp), &tdcp->c_fid, path, plen, nm, len, tva, cred, td->td_proc);
1399
1400 /* Invalidate the parent's attr cache, the modification time has changed */
1401 tdcp->c_flags &= ~C_VATTR;
1402
1403 if (error == 0)
1404 error = VOP_LOOKUP(tdvp, vpp, cnp);
1405
1406 exit:
1407 CODADEBUG(CODA_SYMLINK, myprintf(("in symlink result %d\n",error)); )
1408 return(error);
1409 }
1410
1411 /*
1412 * Read directory entries.
1413 */
1414 int
1415 coda_readdir(struct vop_readdir_args *ap)
1416 {
1417 /* true args */
1418 struct vnode *vp = ap->a_vp;
1419 struct cnode *cp = VTOC(vp);
1420 register struct uio *uiop = ap->a_uio;
1421 struct ucred *cred = ap->a_cred;
1422 int *eofflag = ap->a_eofflag;
1423 u_long **cookies = ap->a_cookies;
1424 int *ncookies = ap->a_ncookies;
1425 struct thread *td = ap->a_uio->uio_td;
1426 /* upcall decl */
1427 /* locals */
1428 int error = 0;
1429
1430 MARK_ENTRY(CODA_READDIR_STATS);
1431
1432 CODADEBUG(CODA_READDIR, myprintf(("coda_readdir(%p, %d, %lld, %d)\n",
1433 (void *)uiop->uio_iov->iov_base,
1434 uiop->uio_resid,
1435 (long long)uiop->uio_offset,
1436 uiop->uio_segflg)); )
1437
1438 /* Check for readdir of control object. */
1439 if (IS_CTL_VP(vp)) {
1440 MARK_INT_FAIL(CODA_READDIR_STATS);
1441 return(ENOENT);
1442 }
1443
1444 {
1445 /* If directory is not already open do an "internal open" on it. */
1446 int opened_internally = 0;
1447 if (cp->c_ovp == NULL) {
1448 opened_internally = 1;
1449 MARK_INT_GEN(CODA_OPEN_STATS);
1450 error = VOP_OPEN(vp, FREAD, cred, td, NULL);
1451 printf("coda_readdir: Internally Opening %p\n", vp);
1452 if (error) {
1453 printf("coda_readdir: VOP_OPEN on container failed %d\n", error);
1454 return (error);
1455 }
1456 }
1457
1458 /* Have UFS handle the call. */
1459 CODADEBUG(CODA_READDIR, myprintf(("indirect readdir: fid = %s, refcnt = %d\n", coda_f2s(&cp->c_fid), vp->v_usecount)); )
1460 error = VOP_READDIR(cp->c_ovp, uiop, cred, eofflag, ncookies,
1461 cookies);
1462
1463 if (error)
1464 MARK_INT_FAIL(CODA_READDIR_STATS);
1465 else
1466 MARK_INT_SAT(CODA_READDIR_STATS);
1467
1468 /* Do an "internal close" if necessary. */
1469 if (opened_internally) {
1470 MARK_INT_GEN(CODA_CLOSE_STATS);
1471 (void)VOP_CLOSE(vp, FREAD, cred, td);
1472 }
1473 }
1474
1475 return(error);
1476 }
1477
1478 /*
1479 * Convert from filesystem blocks to device blocks
1480 */
1481 int
1482 coda_bmap(struct vop_bmap_args *ap)
1483 {
1484 /* XXX on the global proc */
1485 /* true args */
1486 struct vnode *vp __attribute__((unused)) = ap->a_vp; /* file's vnode */
1487 daddr_t bn __attribute__((unused)) = ap->a_bn; /* fs block number */
1488 struct bufobj **bop = ap->a_bop; /* RETURN bufobj of device */
1489 daddr_t *bnp __attribute__((unused)) = ap->a_bnp; /* RETURN device block number */
1490 struct thread *td __attribute__((unused)) = curthread;
1491 /* upcall decl */
1492 /* locals */
1493
1494 int ret = 0;
1495 struct cnode *cp;
1496
1497 cp = VTOC(vp);
1498 if (cp->c_ovp) {
1499 return EINVAL;
1500 ret = VOP_BMAP(cp->c_ovp, bn, bop, bnp, ap->a_runp, ap->a_runb);
1501 #if 0
1502 printf("VOP_BMAP(cp->c_ovp %p, bn %p, bop %p, bnp %lld, ap->a_runp %p, ap->a_runb %p) = %d\n",
1503 cp->c_ovp, bn, bop, bnp, ap->a_runp, ap->a_runb, ret);
1504 #endif
1505 return ret;
1506 } else {
1507 #if 0
1508 printf("coda_bmap: no container\n");
1509 #endif
1510 return(EOPNOTSUPP);
1511 }
1512 }
1513
1514 int
1515 coda_reclaim(struct vop_reclaim_args *ap)
1516 {
1517 /* true args */
1518 struct vnode *vp = ap->a_vp;
1519 struct cnode *cp = VTOC(vp);
1520 /* upcall decl */
1521 /* locals */
1522
1523 /*
1524 * Forced unmount/flush will let vnodes with non zero use be destroyed!
1525 */
1526 ENTRY;
1527
1528 if (IS_UNMOUNTING(cp)) {
1529 #ifdef DEBUG
1530 if (VTOC(vp)->c_ovp) {
1531 if (IS_UNMOUNTING(cp))
1532 printf("coda_reclaim: c_ovp not void: vp %p, cp %p\n", vp, cp);
1533 }
1534 #endif
1535 } else {
1536 #ifdef OLD_DIAGNOSTIC
1537 if (vrefcnt(vp) != 0)
1538 print("coda_reclaim: pushing active %p\n", vp);
1539 if (VTOC(vp)->c_ovp) {
1540 panic("coda_reclaim: c_ovp not void");
1541 }
1542 #endif
1543 }
1544 cache_purge(vp);
1545 coda_free(VTOC(vp));
1546 vp->v_data = NULL;
1547 vp->v_object = NULL;
1548 return (0);
1549 }
1550
1551 int
1552 coda_lock(struct vop_lock1_args *ap)
1553 {
1554 /* true args */
1555 struct vnode *vp = ap->a_vp;
1556 struct cnode *cp = VTOC(vp);
1557 /* upcall decl */
1558 /* locals */
1559
1560 ENTRY;
1561
1562 if ((ap->a_flags & LK_INTERLOCK) == 0) {
1563 VI_LOCK(vp);
1564 ap->a_flags |= LK_INTERLOCK;
1565 }
1566
1567 if (coda_lockdebug) {
1568 myprintf(("Attempting lock on %s\n",
1569 coda_f2s(&cp->c_fid)));
1570 }
1571
1572 return (vop_stdlock(ap));
1573 }
1574
1575 int
1576 coda_unlock(struct vop_unlock_args *ap)
1577 {
1578 /* true args */
1579 struct vnode *vp = ap->a_vp;
1580 struct cnode *cp = VTOC(vp);
1581 /* upcall decl */
1582 /* locals */
1583
1584 ENTRY;
1585 if (coda_lockdebug) {
1586 myprintf(("Attempting unlock on %s\n",
1587 coda_f2s(&cp->c_fid)));
1588 }
1589
1590 return (vop_stdunlock(ap));
1591 }
1592
1593 int
1594 coda_islocked(struct vop_islocked_args *ap)
1595 {
1596 /* true args */
1597 ENTRY;
1598
1599 return (vop_stdislocked(ap));
1600 }
1601
1602 void
1603 print_vattr(struct vattr *attr)
1604 {
1605 char *typestr;
1606
1607 switch (attr->va_type) {
1608 case VNON:
1609 typestr = "VNON";
1610 break;
1611 case VREG:
1612 typestr = "VREG";
1613 break;
1614 case VDIR:
1615 typestr = "VDIR";
1616 break;
1617 case VBLK:
1618 typestr = "VBLK";
1619 break;
1620 case VCHR:
1621 typestr = "VCHR";
1622 break;
1623 case VLNK:
1624 typestr = "VLNK";
1625 break;
1626 case VSOCK:
1627 typestr = "VSCK";
1628 break;
1629 case VFIFO:
1630 typestr = "VFFO";
1631 break;
1632 case VBAD:
1633 typestr = "VBAD";
1634 break;
1635 default:
1636 typestr = "????";
1637 break;
1638 }
1639
1640
1641 myprintf(("attr: type %s mode %d uid %d gid %d fsid %d rdev %d\n",
1642 typestr, (int)attr->va_mode, (int)attr->va_uid,
1643 (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev));
1644
1645 myprintf((" fileid %d nlink %d size %d blocksize %d bytes %d\n",
1646 (int)attr->va_fileid, (int)attr->va_nlink,
1647 (int)attr->va_size,
1648 (int)attr->va_blocksize,(int)attr->va_bytes));
1649 myprintf((" gen %ld flags %ld vaflags %d\n",
1650 attr->va_gen, attr->va_flags, attr->va_vaflags));
1651 myprintf((" atime sec %d nsec %d\n",
1652 (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec));
1653 myprintf((" mtime sec %d nsec %d\n",
1654 (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec));
1655 myprintf((" ctime sec %d nsec %d\n",
1656 (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec));
1657 }
1658
1659 /* How to print a ucred */
1660 void
1661 print_cred(struct ucred *cred)
1662 {
1663
1664 int i;
1665
1666 myprintf(("ref %d\tuid %d\n",cred->cr_ref,cred->cr_uid));
1667
1668 for (i=0; i < cred->cr_ngroups; i++)
1669 myprintf(("\tgroup %d: (%d)\n",i,cred->cr_groups[i]));
1670 myprintf(("\n"));
1671
1672 }
1673
1674 /*
1675 * Return a vnode for the given fid.
1676 * If no cnode exists for this fid create one and put it
1677 * in a table hashed by coda_f2i(). If the cnode for
1678 * this fid is already in the table return it (ref count is
1679 * incremented by coda_find. The cnode will be flushed from the
1680 * table when coda_inactive calls coda_unsave.
1681 */
1682 struct cnode *
1683 make_coda_node(CodaFid *fid, struct mount *vfsp, short type)
1684 {
1685 struct cnode *cp;
1686 int err;
1687
1688 if ((cp = coda_find(fid)) == NULL) {
1689 struct vnode *vp;
1690
1691 cp = coda_alloc();
1692 cp->c_fid = *fid;
1693
1694 err = getnewvnode("coda", vfsp, &coda_vnodeops, &vp);
1695 if (err) {
1696 panic("coda: getnewvnode returned error %d\n", err);
1697 }
1698 err = insmntque1(vp, vfsp, NULL, NULL); /* XXX: Too early for mpsafe fs */
1699 if (err != 0)
1700 panic("coda: insmntque failed: error %d", err);
1701 vp->v_data = cp;
1702 vp->v_type = type;
1703 cp->c_vnode = vp;
1704 coda_save(cp);
1705
1706 } else {
1707 vref(CTOV(cp));
1708 }
1709
1710 return cp;
1711 }
1712
1713 int
1714 coda_pathconf(struct vop_pathconf_args *ap)
1715 {
1716 int error;
1717 register_t *retval;
1718
1719 retval = ap->a_retval;
1720 error = 0;
1721
1722 switch (ap->a_name) {
1723 case _PC_NAME_MAX:
1724 *retval = CODA_MAXNAMLEN;
1725 break;
1726 case _PC_PATH_MAX:
1727 *retval = CODA_MAXPATHLEN;
1728 break;
1729 default:
1730 error = vop_stdpathconf(ap);
1731 break;
1732 }
1733
1734 return (error);
1735 }
Cache object: e9571b2113d929fbf090418b4bb2360c
|