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