coda_vnops.c revision 175202
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 175202 2008-01-10 01:10:58Z attilio $"); 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 CODADEBUG(CODA_INACTIVE, myprintf(("in inactive, %s, vfsp %p\n", 749 coda_f2s(&cp->c_fid), vp->v_mount));) 750 751 /* If an array has been allocated to hold the symlink, deallocate it */ 752 if ((coda_symlink_cache) && (VALID_SYMLINK(cp))) { 753 if (cp->c_symlink == NULL) 754 panic("coda_inactive: null symlink pointer in cnode"); 755 756 CODA_FREE(cp->c_symlink, cp->c_symlen); 757 cp->c_flags &= ~C_SYMLINK; 758 cp->c_symlen = 0; 759 } 760 761 /* Remove it from the table so it can't be found. */ 762 coda_unsave(cp); 763 if ((struct coda_mntinfo *)(vp->v_mount->mnt_data) == NULL) { 764 myprintf(("Help! vfsp->vfs_data was NULL, but vnode %p wasn't dying\n", vp)); 765 panic("badness in coda_inactive\n"); 766 } 767 768 if (IS_UNMOUNTING(cp)) { 769#ifdef DEBUG 770 printf("coda_inactive: IS_UNMOUNTING use %d: vp %p, cp %p\n", vrefcnt(vp), vp, cp); 771 if (cp->c_ovp != NULL) 772 printf("coda_inactive: cp->ovp != NULL use %d: vp %p, cp %p\n", 773 vrefcnt(vp), vp, cp); 774#endif 775 } else { 776#ifdef OLD_DIAGNOSTIC 777 if (vrefcnt(CTOV(cp))) { 778 panic("coda_inactive: nonzero reference count"); 779 } 780 if (cp->c_ovp != NULL) { 781 panic("coda_inactive: cp->ovp != NULL"); 782 } 783#endif 784 vgone(vp); 785 } 786 787 MARK_INT_SAT(CODA_INACTIVE_STATS); 788 return(0); 789} 790 791/* 792 * Remote filesystem operations having to do with directory manipulation. 793 */ 794 795/* 796 * It appears that in NetBSD, lookup is supposed to return the vnode locked 797 */ 798int 799coda_lookup(struct vop_lookup_args *ap) 800{ 801/* true args */ 802 struct vnode *dvp = ap->a_dvp; 803 struct cnode *dcp = VTOC(dvp); 804 struct vnode **vpp = ap->a_vpp; 805 /* 806 * It looks as though ap->a_cnp->ni_cnd->cn_nameptr holds the rest 807 * of the string to xlate, and that we must try to get at least 808 * ap->a_cnp->ni_cnd->cn_namelen of those characters to macth. I 809 * could be wrong. 810 */ 811 struct componentname *cnp = ap->a_cnp; 812 struct ucred *cred = cnp->cn_cred; 813 struct thread *td = cnp->cn_thread; 814/* locals */ 815 struct cnode *cp; 816 const char *nm = cnp->cn_nameptr; 817 int len = cnp->cn_namelen; 818 CodaFid VFid; 819 int vtype; 820 int error = 0; 821 822 MARK_ENTRY(CODA_LOOKUP_STATS); 823 824 CODADEBUG(CODA_LOOKUP, myprintf(("lookup: %s in %s\n", 825 nm, coda_f2s(&dcp->c_fid)));); 826 827 /* Check for lookup of control object. */ 828 if (IS_CTL_NAME(dvp, nm, len)) { 829 *vpp = coda_ctlvp; 830 vref(*vpp); 831 MARK_INT_SAT(CODA_LOOKUP_STATS); 832 goto exit; 833 } 834 835 if (len+1 > CODA_MAXNAMLEN) { 836 MARK_INT_FAIL(CODA_LOOKUP_STATS); 837 838 CODADEBUG(CODA_LOOKUP, myprintf(("name too long: lookup, %s (%s)\n", 839 coda_f2s(&dcp->c_fid), nm));); 840 *vpp = (struct vnode *)0; 841 error = EINVAL; 842 goto exit; 843 } 844 /* First try to look the file up in the cfs name cache */ 845 /* lock the parent vnode? */ 846 cp = coda_nc_lookup(dcp, nm, len, cred); 847 if (cp) { 848 *vpp = CTOV(cp); 849 vref(*vpp); 850 CODADEBUG(CODA_LOOKUP, 851 myprintf(("lookup result %d vpp %p\n",error,*vpp));) 852 } else { 853 854 /* The name wasn't cached, so we need to contact Venus */ 855 error = venus_lookup(vtomi(dvp), &dcp->c_fid, nm, len, cred, td->td_proc, &VFid, &vtype); 856 857 if (error) { 858 MARK_INT_FAIL(CODA_LOOKUP_STATS); 859 860 CODADEBUG(CODA_LOOKUP, myprintf(("lookup error on %s (%s)%d\n", 861 coda_f2s(&dcp->c_fid), nm, error));) 862 *vpp = (struct vnode *)0; 863 } else { 864 MARK_INT_SAT(CODA_LOOKUP_STATS); 865 CODADEBUG(CODA_LOOKUP, 866 myprintf(("lookup: %s type %o result %d\n", 867 coda_f2s(&VFid), vtype, error)); ) 868 cp = make_coda_node(&VFid, dvp->v_mount, vtype); 869 *vpp = CTOV(cp); 870 871 /* enter the new vnode in the Name Cache only if the top bit isn't set */ 872 /* And don't enter a new vnode for an invalid one! */ 873 if (!(vtype & CODA_NOCACHE)) 874 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp)); 875 } 876 } 877 878 exit: 879 /* 880 * If we are creating, and this was the last name to be looked up, 881 * and the error was ENOENT, then there really shouldn't be an 882 * error and we can make the leaf NULL and return success. Since 883 * this is supposed to work under Mach as well as NetBSD, we're 884 * leaving this fn wrapped. We also must tell lookup/namei that 885 * we need to save the last component of the name. (Create will 886 * have to free the name buffer later...lucky us...) 887 */ 888 if (((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME)) 889 && (cnp->cn_flags & ISLASTCN) 890 && (error == ENOENT)) 891 { 892 error = EJUSTRETURN; 893 cnp->cn_flags |= SAVENAME; 894 *ap->a_vpp = NULL; 895 } 896 897 /* 898 * If we are removing, and we are at the last element, and we 899 * found it, then we need to keep the name around so that the 900 * removal will go ahead as planned. Unfortunately, this will 901 * probably also lock the to-be-removed vnode, which may or may 902 * not be a good idea. I'll have to look at the bits of 903 * coda_remove to make sure. We'll only save the name if we did in 904 * fact find the name, otherwise coda_remove won't have a chance 905 * to free the pathname. 906 */ 907 if ((cnp->cn_nameiop == DELETE) 908 && (cnp->cn_flags & ISLASTCN) 909 && !error) 910 { 911 cnp->cn_flags |= SAVENAME; 912 } 913 914 /* 915 * If the lookup went well, we need to (potentially?) unlock the 916 * parent, and lock the child. We are only responsible for 917 * checking to see if the parent is supposed to be unlocked before 918 * we return. We must always lock the child (provided there is 919 * one, and (the parent isn't locked or it isn't the same as the 920 * parent.) Simple, huh? We can never leave the parent locked unless 921 * we are ISLASTCN 922 */ 923 if (!error || (error == EJUSTRETURN)) { 924 if (cnp->cn_flags & ISDOTDOT) { 925 if ((error = VOP_UNLOCK(dvp, 0, td))) { 926 return error; 927 } 928 /* 929 * The parent is unlocked. As long as there is a child, 930 * lock it without bothering to check anything else. 931 */ 932 if (*ap->a_vpp) { 933 if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) { 934 vn_lock(dvp, LK_RETRY|LK_EXCLUSIVE); 935 return (error); 936 } 937 } 938 vn_lock(dvp, LK_RETRY|LK_EXCLUSIVE); 939 } else { 940 /* The parent is locked, and may be the same as the child */ 941 if (*ap->a_vpp && (*ap->a_vpp != dvp)) { 942 /* Different, go ahead and lock it. */ 943 if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) { 944 return (error); 945 } 946 } 947 } 948 } else { 949 /* If the lookup failed, we need to ensure that the leaf is NULL */ 950 /* Don't change any locking? */ 951 *ap->a_vpp = NULL; 952 } 953 return(error); 954} 955 956/*ARGSUSED*/ 957int 958coda_create(struct vop_create_args *ap) 959{ 960/* true args */ 961 struct vnode *dvp = ap->a_dvp; 962 struct cnode *dcp = VTOC(dvp); 963 struct vattr *va = ap->a_vap; 964 int exclusive = 1; 965 int mode = ap->a_vap->va_mode; 966 struct vnode **vpp = ap->a_vpp; 967 struct componentname *cnp = ap->a_cnp; 968 struct ucred *cred = cnp->cn_cred; 969 struct thread *td = cnp->cn_thread; 970/* locals */ 971 int error; 972 struct cnode *cp; 973 const char *nm = cnp->cn_nameptr; 974 int len = cnp->cn_namelen; 975 CodaFid VFid; 976 struct vattr attr; 977 978 MARK_ENTRY(CODA_CREATE_STATS); 979 980 /* All creates are exclusive XXX */ 981 /* I'm assuming the 'mode' argument is the file mode bits XXX */ 982 983 /* Check for create of control object. */ 984 if (IS_CTL_NAME(dvp, nm, len)) { 985 *vpp = (struct vnode *)0; 986 MARK_INT_FAIL(CODA_CREATE_STATS); 987 return(EACCES); 988 } 989 990 error = venus_create(vtomi(dvp), &dcp->c_fid, nm, len, exclusive, mode, va, cred, td->td_proc, &VFid, &attr); 991 992 if (!error) { 993 994 /* If this is an exclusive create, panic if the file already exists. */ 995 /* Venus should have detected the file and reported EEXIST. */ 996 997 if ((exclusive == 1) && 998 (coda_find(&VFid) != NULL)) 999 panic("cnode existed for newly created file!"); 1000 1001 cp = make_coda_node(&VFid, dvp->v_mount, attr.va_type); 1002 *vpp = CTOV(cp); 1003 1004 /* Update va to reflect the new attributes. */ 1005 (*va) = attr; 1006 1007 /* Update the attribute cache and mark it as valid */ 1008 if (coda_attr_cache) { 1009 VTOC(*vpp)->c_vattr = attr; 1010 VTOC(*vpp)->c_flags |= C_VATTR; 1011 } 1012 1013 /* Invalidate the parent's attr cache, the modification time has changed */ 1014 VTOC(dvp)->c_flags &= ~C_VATTR; 1015 1016 /* enter the new vnode in the Name Cache */ 1017 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp)); 1018 1019 CODADEBUG(CODA_CREATE, 1020 myprintf(("create: %s, result %d\n", 1021 coda_f2s(&VFid), error)); ) 1022 } else { 1023 *vpp = (struct vnode *)0; 1024 CODADEBUG(CODA_CREATE, myprintf(("create error %d\n", error));) 1025 } 1026 1027 if (!error) { 1028 if (cnp->cn_flags & LOCKLEAF) { 1029 if ((error = VOP_LOCK(*ap->a_vpp, LK_EXCLUSIVE, td))) { 1030 printf("coda_create: "); 1031 panic("unlocked parent but couldn't lock child"); 1032 } 1033 } 1034#ifdef OLD_DIAGNOSTIC 1035 else { 1036 printf("coda_create: LOCKLEAF not set!\n"); 1037 } 1038#endif 1039 } 1040 return(error); 1041} 1042 1043int 1044coda_remove(struct vop_remove_args *ap) 1045{ 1046/* true args */ 1047 struct vnode *dvp = ap->a_dvp; 1048 struct cnode *cp = VTOC(dvp); 1049 struct componentname *cnp = ap->a_cnp; 1050 struct ucred *cred = cnp->cn_cred; 1051 struct thread *td = cnp->cn_thread; 1052/* locals */ 1053 int error; 1054 const char *nm = cnp->cn_nameptr; 1055 int len = cnp->cn_namelen; 1056 struct cnode *tp; 1057 1058 MARK_ENTRY(CODA_REMOVE_STATS); 1059 1060 CODADEBUG(CODA_REMOVE, myprintf(("remove: %s in %s\n", 1061 nm, coda_f2s(&cp->c_fid)));); 1062 /* Remove the file's entry from the CODA Name Cache */ 1063 /* We're being conservative here, it might be that this person 1064 * doesn't really have sufficient access to delete the file 1065 * but we feel zapping the entry won't really hurt anyone -- dcs 1066 */ 1067 /* I'm gonna go out on a limb here. If a file and a hardlink to it 1068 * exist, and one is removed, the link count on the other will be 1069 * off by 1. We could either invalidate the attrs if cached, or 1070 * fix them. I'll try to fix them. DCS 11/8/94 1071 */ 1072 tp = coda_nc_lookup(VTOC(dvp), nm, len, cred); 1073 if (tp) { 1074 if (VALID_VATTR(tp)) { /* If attrs are cached */ 1075 if (tp->c_vattr.va_nlink > 1) { /* If it's a hard link */ 1076 tp->c_vattr.va_nlink--; 1077 } 1078 } 1079 1080 coda_nc_zapfile(VTOC(dvp), nm, len); 1081 /* No need to flush it if it doesn't exist! */ 1082 } 1083 /* Invalidate the parent's attr cache, the modification time has changed */ 1084 VTOC(dvp)->c_flags &= ~C_VATTR; 1085 1086 /* Check for remove of control object. */ 1087 if (IS_CTL_NAME(dvp, nm, len)) { 1088 MARK_INT_FAIL(CODA_REMOVE_STATS); 1089 return(ENOENT); 1090 } 1091 1092 error = venus_remove(vtomi(dvp), &cp->c_fid, nm, len, cred, td->td_proc); 1093 1094 CODADEBUG(CODA_REMOVE, myprintf(("in remove result %d\n",error)); ) 1095 1096 return(error); 1097} 1098 1099int 1100coda_link(struct vop_link_args *ap) 1101{ 1102/* true args */ 1103 struct vnode *vp = ap->a_vp; 1104 struct cnode *cp = VTOC(vp); 1105 struct vnode *tdvp = ap->a_tdvp; 1106 struct cnode *tdcp = VTOC(tdvp); 1107 struct componentname *cnp = ap->a_cnp; 1108 struct ucred *cred = cnp->cn_cred; 1109 struct thread *td = cnp->cn_thread; 1110/* locals */ 1111 int error; 1112 const char *nm = cnp->cn_nameptr; 1113 int len = cnp->cn_namelen; 1114 1115 MARK_ENTRY(CODA_LINK_STATS); 1116 1117 if (codadebug & CODADBGMSK(CODA_LINK)) { 1118 myprintf(("nb_link: vp fid: %s\n", 1119 coda_f2s(&cp->c_fid))); 1120 myprintf(("nb_link: tdvp fid: %s)\n", 1121 coda_f2s(&tdcp->c_fid))); 1122 } 1123 if (codadebug & CODADBGMSK(CODA_LINK)) { 1124 myprintf(("link: vp fid: %s\n", 1125 coda_f2s(&cp->c_fid))); 1126 myprintf(("link: tdvp fid: %s\n", 1127 coda_f2s(&tdcp->c_fid))); 1128 } 1129 1130 /* Check for link to/from control object. */ 1131 if (IS_CTL_NAME(tdvp, nm, len) || IS_CTL_VP(vp)) { 1132 MARK_INT_FAIL(CODA_LINK_STATS); 1133 return(EACCES); 1134 } 1135 1136 error = venus_link(vtomi(vp), &cp->c_fid, &tdcp->c_fid, nm, len, cred, td->td_proc); 1137 1138 /* Invalidate the parent's attr cache, the modification time has changed */ 1139 VTOC(tdvp)->c_flags &= ~C_VATTR; 1140 VTOC(vp)->c_flags &= ~C_VATTR; 1141 1142 CODADEBUG(CODA_LINK, myprintf(("in link result %d\n",error)); ) 1143 1144 return(error); 1145} 1146 1147int 1148coda_rename(struct vop_rename_args *ap) 1149{ 1150/* true args */ 1151 struct vnode *odvp = ap->a_fdvp; 1152 struct cnode *odcp = VTOC(odvp); 1153 struct componentname *fcnp = ap->a_fcnp; 1154 struct vnode *ndvp = ap->a_tdvp; 1155 struct cnode *ndcp = VTOC(ndvp); 1156 struct componentname *tcnp = ap->a_tcnp; 1157 struct ucred *cred = fcnp->cn_cred; 1158 struct thread *td = fcnp->cn_thread; 1159/* true args */ 1160 int error; 1161 const char *fnm = fcnp->cn_nameptr; 1162 int flen = fcnp->cn_namelen; 1163 const char *tnm = tcnp->cn_nameptr; 1164 int tlen = tcnp->cn_namelen; 1165 1166 MARK_ENTRY(CODA_RENAME_STATS); 1167 1168 /* Hmmm. The vnodes are already looked up. Perhaps they are locked? 1169 This could be Bad. XXX */ 1170#ifdef OLD_DIAGNOSTIC 1171 if ((fcnp->cn_cred != tcnp->cn_cred) 1172 || (fcnp->cn_thread != tcnp->cn_thread)) 1173 { 1174 panic("coda_rename: component names don't agree"); 1175 } 1176#endif 1177 1178 /* Check for rename involving control object. */ 1179 if (IS_CTL_NAME(odvp, fnm, flen) || IS_CTL_NAME(ndvp, tnm, tlen)) { 1180 MARK_INT_FAIL(CODA_RENAME_STATS); 1181 return(EACCES); 1182 } 1183 1184 /* Problem with moving directories -- need to flush entry for .. */ 1185 if (odvp != ndvp) { 1186 struct cnode *ovcp = coda_nc_lookup(VTOC(odvp), fnm, flen, cred); 1187 if (ovcp) { 1188 struct vnode *ovp = CTOV(ovcp); 1189 if ((ovp) && 1190 (ovp->v_type == VDIR)) /* If it's a directory */ 1191 coda_nc_zapfile(VTOC(ovp),"..", 2); 1192 } 1193 } 1194 1195 /* Remove the entries for both source and target files */ 1196 coda_nc_zapfile(VTOC(odvp), fnm, flen); 1197 coda_nc_zapfile(VTOC(ndvp), tnm, tlen); 1198 1199 /* Invalidate the parent's attr cache, the modification time has changed */ 1200 VTOC(odvp)->c_flags &= ~C_VATTR; 1201 VTOC(ndvp)->c_flags &= ~C_VATTR; 1202 1203 if (flen+1 > CODA_MAXNAMLEN) { 1204 MARK_INT_FAIL(CODA_RENAME_STATS); 1205 error = EINVAL; 1206 goto exit; 1207 } 1208 1209 if (tlen+1 > CODA_MAXNAMLEN) { 1210 MARK_INT_FAIL(CODA_RENAME_STATS); 1211 error = EINVAL; 1212 goto exit; 1213 } 1214 1215 error = venus_rename(vtomi(odvp), &odcp->c_fid, &ndcp->c_fid, fnm, flen, tnm, tlen, cred, td->td_proc); 1216 1217 exit: 1218 CODADEBUG(CODA_RENAME, myprintf(("in rename result %d\n",error));) 1219 /* XXX - do we need to call cache pureg on the moved vnode? */ 1220 cache_purge(ap->a_fvp); 1221 1222 /* Release parents first, then children. */ 1223 vrele(odvp); 1224 if (ap->a_tvp) { 1225 if (ap->a_tvp == ndvp) 1226 vrele(ndvp); 1227 else 1228 vput(ndvp); 1229 vput(ap->a_tvp); 1230 } else 1231 vput(ndvp); 1232 vrele(ap->a_fvp); 1233 1234 return(error); 1235} 1236 1237int 1238coda_mkdir(struct vop_mkdir_args *ap) 1239{ 1240/* true args */ 1241 struct vnode *dvp = ap->a_dvp; 1242 struct cnode *dcp = VTOC(dvp); 1243 struct componentname *cnp = ap->a_cnp; 1244 register struct vattr *va = ap->a_vap; 1245 struct vnode **vpp = ap->a_vpp; 1246 struct ucred *cred = cnp->cn_cred; 1247 struct thread *td = cnp->cn_thread; 1248/* locals */ 1249 int error; 1250 const char *nm = cnp->cn_nameptr; 1251 int len = cnp->cn_namelen; 1252 struct cnode *cp; 1253 CodaFid VFid; 1254 struct vattr ova; 1255 1256 MARK_ENTRY(CODA_MKDIR_STATS); 1257 1258 /* Check for mkdir of target object. */ 1259 if (IS_CTL_NAME(dvp, nm, len)) { 1260 *vpp = (struct vnode *)0; 1261 MARK_INT_FAIL(CODA_MKDIR_STATS); 1262 return(EACCES); 1263 } 1264 1265 if (len+1 > CODA_MAXNAMLEN) { 1266 *vpp = (struct vnode *)0; 1267 MARK_INT_FAIL(CODA_MKDIR_STATS); 1268 return(EACCES); 1269 } 1270 1271 error = venus_mkdir(vtomi(dvp), &dcp->c_fid, nm, len, va, cred, td->td_proc, &VFid, &ova); 1272 1273 if (!error) { 1274 if (coda_find(&VFid) != NULL) 1275 panic("cnode existed for newly created directory!"); 1276 1277 1278 cp = make_coda_node(&VFid, dvp->v_mount, va->va_type); 1279 *vpp = CTOV(cp); 1280 1281 /* enter the new vnode in the Name Cache */ 1282 coda_nc_enter(VTOC(dvp), nm, len, cred, VTOC(*vpp)); 1283 1284 /* as a side effect, enter "." and ".." for the directory */ 1285 coda_nc_enter(VTOC(*vpp), ".", 1, cred, VTOC(*vpp)); 1286 coda_nc_enter(VTOC(*vpp), "..", 2, cred, VTOC(dvp)); 1287 1288 if (coda_attr_cache) { 1289 VTOC(*vpp)->c_vattr = ova; /* update the attr cache */ 1290 VTOC(*vpp)->c_flags |= C_VATTR; /* Valid attributes in cnode */ 1291 } 1292 1293 /* Invalidate the parent's attr cache, the modification time has changed */ 1294 VTOC(dvp)->c_flags &= ~C_VATTR; 1295 1296 CODADEBUG( CODA_MKDIR, myprintf(("mkdir: %s result %d\n", 1297 coda_f2s(&VFid), error)); ) 1298 } else { 1299 *vpp = (struct vnode *)0; 1300 CODADEBUG(CODA_MKDIR, myprintf(("mkdir error %d\n",error));) 1301 } 1302 1303 return(error); 1304} 1305 1306int 1307coda_rmdir(struct vop_rmdir_args *ap) 1308{ 1309/* true args */ 1310 struct vnode *dvp = ap->a_dvp; 1311 struct cnode *dcp = VTOC(dvp); 1312 struct componentname *cnp = ap->a_cnp; 1313 struct ucred *cred = cnp->cn_cred; 1314 struct thread *td = cnp->cn_thread; 1315/* true args */ 1316 int error; 1317 const char *nm = cnp->cn_nameptr; 1318 int len = cnp->cn_namelen; 1319 struct cnode *cp; 1320 1321 MARK_ENTRY(CODA_RMDIR_STATS); 1322 1323 /* Check for rmdir of control object. */ 1324 if (IS_CTL_NAME(dvp, nm, len)) { 1325 MARK_INT_FAIL(CODA_RMDIR_STATS); 1326 return(ENOENT); 1327 } 1328 1329 /* We're being conservative here, it might be that this person 1330 * doesn't really have sufficient access to delete the file 1331 * but we feel zapping the entry won't really hurt anyone -- dcs 1332 */ 1333 /* 1334 * As a side effect of the rmdir, remove any entries for children of 1335 * the directory, especially "." and "..". 1336 */ 1337 cp = coda_nc_lookup(dcp, nm, len, cred); 1338 if (cp) coda_nc_zapParentfid(&(cp->c_fid), NOT_DOWNCALL); 1339 1340 /* Remove the file's entry from the CODA Name Cache */ 1341 coda_nc_zapfile(dcp, nm, len); 1342 1343 /* Invalidate the parent's attr cache, the modification time has changed */ 1344 dcp->c_flags &= ~C_VATTR; 1345 1346 error = venus_rmdir(vtomi(dvp), &dcp->c_fid, nm, len, cred, td->td_proc); 1347 1348 CODADEBUG(CODA_RMDIR, myprintf(("in rmdir result %d\n", error)); ) 1349 1350 return(error); 1351} 1352 1353int 1354coda_symlink(struct vop_symlink_args *ap) 1355{ 1356/* true args */ 1357 struct vnode *tdvp = ap->a_dvp; 1358 struct cnode *tdcp = VTOC(tdvp); 1359 struct componentname *cnp = ap->a_cnp; 1360 struct vattr *tva = ap->a_vap; 1361 char *path = ap->a_target; 1362 struct ucred *cred = cnp->cn_cred; 1363 struct thread *td = cnp->cn_thread; 1364 struct vnode **vpp = ap->a_vpp; 1365/* locals */ 1366 int error; 1367 /* 1368 * XXX I'm assuming the following things about coda_symlink's 1369 * arguments: 1370 * t(foo) is the new name/parent/etc being created. 1371 * lname is the contents of the new symlink. 1372 */ 1373 char *nm = cnp->cn_nameptr; 1374 int len = cnp->cn_namelen; 1375 int plen = strlen(path); 1376 1377 /* 1378 * Here's the strategy for the moment: perform the symlink, then 1379 * do a lookup to grab the resulting vnode. I know this requires 1380 * two communications with Venus for a new sybolic link, but 1381 * that's the way the ball bounces. I don't yet want to change 1382 * the way the Mach symlink works. When Mach support is 1383 * deprecated, we should change symlink so that the common case 1384 * returns the resultant vnode in a vpp argument. 1385 */ 1386 1387 MARK_ENTRY(CODA_SYMLINK_STATS); 1388 1389 /* Check for symlink of control object. */ 1390 if (IS_CTL_NAME(tdvp, nm, len)) { 1391 MARK_INT_FAIL(CODA_SYMLINK_STATS); 1392 return(EACCES); 1393 } 1394 1395 if (plen+1 > CODA_MAXPATHLEN) { 1396 MARK_INT_FAIL(CODA_SYMLINK_STATS); 1397 return(EINVAL); 1398 } 1399 1400 if (len+1 > CODA_MAXNAMLEN) { 1401 MARK_INT_FAIL(CODA_SYMLINK_STATS); 1402 error = EINVAL; 1403 goto exit; 1404 } 1405 1406 error = venus_symlink(vtomi(tdvp), &tdcp->c_fid, path, plen, nm, len, tva, cred, td->td_proc); 1407 1408 /* Invalidate the parent's attr cache, the modification time has changed */ 1409 tdcp->c_flags &= ~C_VATTR; 1410 1411 if (error == 0) 1412 error = VOP_LOOKUP(tdvp, vpp, cnp); 1413 1414 exit: 1415 CODADEBUG(CODA_SYMLINK, myprintf(("in symlink result %d\n",error)); ) 1416 return(error); 1417} 1418 1419/* 1420 * Read directory entries. 1421 */ 1422int 1423coda_readdir(struct vop_readdir_args *ap) 1424{ 1425/* true args */ 1426 struct vnode *vp = ap->a_vp; 1427 struct cnode *cp = VTOC(vp); 1428 register struct uio *uiop = ap->a_uio; 1429 struct ucred *cred = ap->a_cred; 1430 int *eofflag = ap->a_eofflag; 1431 u_long **cookies = ap->a_cookies; 1432 int *ncookies = ap->a_ncookies; 1433 struct thread *td = ap->a_uio->uio_td; 1434/* upcall decl */ 1435/* locals */ 1436 int error = 0; 1437 1438 MARK_ENTRY(CODA_READDIR_STATS); 1439 1440 CODADEBUG(CODA_READDIR, myprintf(("coda_readdir(%p, %d, %lld, %d)\n", 1441 (void *)uiop->uio_iov->iov_base, 1442 uiop->uio_resid, 1443 (long long)uiop->uio_offset, 1444 uiop->uio_segflg)); ) 1445 1446 /* Check for readdir of control object. */ 1447 if (IS_CTL_VP(vp)) { 1448 MARK_INT_FAIL(CODA_READDIR_STATS); 1449 return(ENOENT); 1450 } 1451 1452 { 1453 /* If directory is not already open do an "internal open" on it. */ 1454 int opened_internally = 0; 1455 if (cp->c_ovp == NULL) { 1456 opened_internally = 1; 1457 MARK_INT_GEN(CODA_OPEN_STATS); 1458 error = VOP_OPEN(vp, FREAD, cred, td, NULL); 1459 printf("coda_readdir: Internally Opening %p\n", vp); 1460 if (error) { 1461 printf("coda_readdir: VOP_OPEN on container failed %d\n", error); 1462 return (error); 1463 } 1464 } 1465 1466 /* Have UFS handle the call. */ 1467 CODADEBUG(CODA_READDIR, myprintf(("indirect readdir: fid = %s, refcnt = %d\n", coda_f2s(&cp->c_fid), vp->v_usecount)); ) 1468 error = VOP_READDIR(cp->c_ovp, uiop, cred, eofflag, ncookies, 1469 cookies); 1470 1471 if (error) 1472 MARK_INT_FAIL(CODA_READDIR_STATS); 1473 else 1474 MARK_INT_SAT(CODA_READDIR_STATS); 1475 1476 /* Do an "internal close" if necessary. */ 1477 if (opened_internally) { 1478 MARK_INT_GEN(CODA_CLOSE_STATS); 1479 (void)VOP_CLOSE(vp, FREAD, cred, td); 1480 } 1481 } 1482 1483 return(error); 1484} 1485 1486/* 1487 * Convert from filesystem blocks to device blocks 1488 */ 1489int 1490coda_bmap(struct vop_bmap_args *ap) 1491{ 1492 /* XXX on the global proc */ 1493/* true args */ 1494 struct vnode *vp __attribute__((unused)) = ap->a_vp; /* file's vnode */ 1495 daddr_t bn __attribute__((unused)) = ap->a_bn; /* fs block number */ 1496 struct bufobj **bop = ap->a_bop; /* RETURN bufobj of device */ 1497 daddr_t *bnp __attribute__((unused)) = ap->a_bnp; /* RETURN device block number */ 1498 struct thread *td __attribute__((unused)) = curthread; 1499/* upcall decl */ 1500/* locals */ 1501 1502 int ret = 0; 1503 struct cnode *cp; 1504 1505 cp = VTOC(vp); 1506 if (cp->c_ovp) { 1507 return EINVAL; 1508 ret = VOP_BMAP(cp->c_ovp, bn, bop, bnp, ap->a_runp, ap->a_runb); 1509#if 0 1510 printf("VOP_BMAP(cp->c_ovp %p, bn %p, bop %p, bnp %lld, ap->a_runp %p, ap->a_runb %p) = %d\n", 1511 cp->c_ovp, bn, bop, bnp, ap->a_runp, ap->a_runb, ret); 1512#endif 1513 return ret; 1514 } else { 1515#if 0 1516 printf("coda_bmap: no container\n"); 1517#endif 1518 return(EOPNOTSUPP); 1519 } 1520} 1521 1522int 1523coda_reclaim(struct vop_reclaim_args *ap) 1524{ 1525/* true args */ 1526 struct vnode *vp = ap->a_vp; 1527 struct cnode *cp = VTOC(vp); 1528/* upcall decl */ 1529/* locals */ 1530 1531/* 1532 * Forced unmount/flush will let vnodes with non zero use be destroyed! 1533 */ 1534 ENTRY; 1535 1536 if (IS_UNMOUNTING(cp)) { 1537#ifdef DEBUG 1538 if (VTOC(vp)->c_ovp) { 1539 if (IS_UNMOUNTING(cp)) 1540 printf("coda_reclaim: c_ovp not void: vp %p, cp %p\n", vp, cp); 1541 } 1542#endif 1543 } else { 1544#ifdef OLD_DIAGNOSTIC 1545 if (vrefcnt(vp) != 0) 1546 print("coda_reclaim: pushing active %p\n", vp); 1547 if (VTOC(vp)->c_ovp) { 1548 panic("coda_reclaim: c_ovp not void"); 1549 } 1550#endif 1551 } 1552 cache_purge(vp); 1553 coda_free(VTOC(vp)); 1554 vp->v_data = NULL; 1555 vnode_destroy_vobject(vp); 1556 return (0); 1557} 1558 1559int 1560coda_lock(struct vop_lock1_args *ap) 1561{ 1562/* true args */ 1563 struct vnode *vp = ap->a_vp; 1564 struct cnode *cp = VTOC(vp); 1565/* upcall decl */ 1566/* locals */ 1567 1568 ENTRY; 1569 1570 if ((ap->a_flags & LK_INTERLOCK) == 0) { 1571 VI_LOCK(vp); 1572 ap->a_flags |= LK_INTERLOCK; 1573 } 1574 1575 if (coda_lockdebug) { 1576 myprintf(("Attempting lock on %s\n", 1577 coda_f2s(&cp->c_fid))); 1578 } 1579 1580 return (vop_stdlock(ap)); 1581} 1582 1583int 1584coda_unlock(struct vop_unlock_args *ap) 1585{ 1586/* true args */ 1587 struct vnode *vp = ap->a_vp; 1588 struct cnode *cp = VTOC(vp); 1589/* upcall decl */ 1590/* locals */ 1591 1592 ENTRY; 1593 if (coda_lockdebug) { 1594 myprintf(("Attempting unlock on %s\n", 1595 coda_f2s(&cp->c_fid))); 1596 } 1597 1598 return (vop_stdunlock(ap)); 1599} 1600 1601int 1602coda_islocked(struct vop_islocked_args *ap) 1603{ 1604/* true args */ 1605 ENTRY; 1606 1607 return (vop_stdislocked(ap)); 1608} 1609 1610void 1611print_vattr(struct vattr *attr) 1612{ 1613 char *typestr; 1614 1615 switch (attr->va_type) { 1616 case VNON: 1617 typestr = "VNON"; 1618 break; 1619 case VREG: 1620 typestr = "VREG"; 1621 break; 1622 case VDIR: 1623 typestr = "VDIR"; 1624 break; 1625 case VBLK: 1626 typestr = "VBLK"; 1627 break; 1628 case VCHR: 1629 typestr = "VCHR"; 1630 break; 1631 case VLNK: 1632 typestr = "VLNK"; 1633 break; 1634 case VSOCK: 1635 typestr = "VSCK"; 1636 break; 1637 case VFIFO: 1638 typestr = "VFFO"; 1639 break; 1640 case VBAD: 1641 typestr = "VBAD"; 1642 break; 1643 default: 1644 typestr = "????"; 1645 break; 1646 } 1647 1648 1649 myprintf(("attr: type %s mode %d uid %d gid %d fsid %d rdev %d\n", 1650 typestr, (int)attr->va_mode, (int)attr->va_uid, 1651 (int)attr->va_gid, (int)attr->va_fsid, (int)attr->va_rdev)); 1652 1653 myprintf((" fileid %d nlink %d size %d blocksize %d bytes %d\n", 1654 (int)attr->va_fileid, (int)attr->va_nlink, 1655 (int)attr->va_size, 1656 (int)attr->va_blocksize,(int)attr->va_bytes)); 1657 myprintf((" gen %ld flags %ld vaflags %d\n", 1658 attr->va_gen, attr->va_flags, attr->va_vaflags)); 1659 myprintf((" atime sec %d nsec %d\n", 1660 (int)attr->va_atime.tv_sec, (int)attr->va_atime.tv_nsec)); 1661 myprintf((" mtime sec %d nsec %d\n", 1662 (int)attr->va_mtime.tv_sec, (int)attr->va_mtime.tv_nsec)); 1663 myprintf((" ctime sec %d nsec %d\n", 1664 (int)attr->va_ctime.tv_sec, (int)attr->va_ctime.tv_nsec)); 1665} 1666 1667/* How to print a ucred */ 1668void 1669print_cred(struct ucred *cred) 1670{ 1671 1672 int i; 1673 1674 myprintf(("ref %d\tuid %d\n",cred->cr_ref,cred->cr_uid)); 1675 1676 for (i=0; i < cred->cr_ngroups; i++) 1677 myprintf(("\tgroup %d: (%d)\n",i,cred->cr_groups[i])); 1678 myprintf(("\n")); 1679 1680} 1681 1682/* 1683 * Return a vnode for the given fid. 1684 * If no cnode exists for this fid create one and put it 1685 * in a table hashed by coda_f2i(). If the cnode for 1686 * this fid is already in the table return it (ref count is 1687 * incremented by coda_find. The cnode will be flushed from the 1688 * table when coda_inactive calls coda_unsave. 1689 */ 1690struct cnode * 1691make_coda_node(CodaFid *fid, struct mount *vfsp, short type) 1692{ 1693 struct cnode *cp; 1694 int err; 1695 1696 if ((cp = coda_find(fid)) == NULL) { 1697 struct vnode *vp; 1698 1699 cp = coda_alloc(); 1700 cp->c_fid = *fid; 1701 1702 err = getnewvnode("coda", vfsp, &coda_vnodeops, &vp); 1703 if (err) { 1704 panic("coda: getnewvnode returned error %d\n", err); 1705 } 1706 err = insmntque1(vp, vfsp, NULL, NULL); /* XXX: Too early for mpsafe fs */ 1707 if (err != 0) 1708 panic("coda: insmntque failed: error %d", err); 1709 vp->v_data = cp; 1710 vp->v_type = type; 1711 cp->c_vnode = vp; 1712 coda_save(cp); 1713 1714 } else { 1715 vref(CTOV(cp)); 1716 } 1717 1718 return cp; 1719} 1720 1721int 1722coda_pathconf(struct vop_pathconf_args *ap) 1723{ 1724 int error; 1725 register_t *retval; 1726 1727 retval = ap->a_retval; 1728 error = 0; 1729 1730 switch (ap->a_name) { 1731 case _PC_NAME_MAX: 1732 *retval = CODA_MAXNAMLEN; 1733 break; 1734 case _PC_PATH_MAX: 1735 *retval = CODA_MAXPATHLEN; 1736 break; 1737 default: 1738 error = vop_stdpathconf(ap); 1739 break; 1740 } 1741 1742 return (error); 1743} 1744