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