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