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