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