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