1 /* $NetBSD: coda_vfsops.c,v 1.22 2003/04/16 21:44:18 christos Exp $ */ 2 3 /* 4 * 5 * Coda: an Experimental Distributed File System 6 * Release 3.1 7 * 8 * Copyright (c) 1987-1998 Carnegie Mellon University 9 * All Rights Reserved 10 * 11 * Permission to use, copy, modify and distribute this software and its 12 * documentation is hereby granted, provided that both the copyright 13 * notice and this permission notice appear in all copies of the 14 * software, derivative works or modified versions, and any portions 15 * thereof, and that both notices appear in supporting documentation, and 16 * that credit is given to Carnegie Mellon University in all documents 17 * and publicity pertaining to direct or indirect use of this code or its 18 * derivatives. 19 * 20 * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, 21 * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS 22 * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON 23 * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 24 * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF 25 * ANY DERIVATIVE WORK. 26 * 27 * Carnegie Mellon encourages users of this software to return any 28 * improvements or extensions that they make, and to grant Carnegie 29 * Mellon the rights to redistribute these changes without encumbrance. 30 * 31 * @(#) cfs/coda_vfsops.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $ 32 */ 33 34 /* 35 * Mach Operating System 36 * Copyright (c) 1989 Carnegie-Mellon University 37 * All rights reserved. The CMU software License Agreement specifies 38 * the terms and conditions for use and redistribution. 39 */ 40 41 /* 42 * This code was written for the Coda file system at Carnegie Mellon 43 * University. Contributers include David Steere, James Kistler, and 44 * M. Satyanarayanan. 45 */ 46 47 #include <sys/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: coda_vfsops.c,v 1.22 2003/04/16 21:44:18 christos Exp $"); 49 50 #ifdef _LKM 51 #define NVCODA 4 52 #else 53 #include <vcoda.h> 54 #endif 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/malloc.h> 59 #include <sys/conf.h> 60 #include <sys/namei.h> 61 #include <sys/mount.h> 62 #include <sys/proc.h> 63 #include <sys/select.h> 64 65 #include <coda/coda.h> 66 #include <coda/cnode.h> 67 #include <coda/coda_vfsops.h> 68 #include <coda/coda_venus.h> 69 #include <coda/coda_subr.h> 70 #include <coda/coda_opstats.h> 71 /* for VN_RDEV */ 72 #include <miscfs/specfs/specdev.h> 73 74 MALLOC_DEFINE(M_CODA, "coda", "Coda file system structures and tables"); 75 76 int codadebug = 0; 77 78 int coda_vfsop_print_entry = 0; 79 #define ENTRY if(coda_vfsop_print_entry) myprintf(("Entered %s\n",__func__)) 80 81 struct vnode *coda_ctlvp; 82 struct coda_mntinfo coda_mnttbl[NVCODA]; /* indexed by minor device number */ 83 84 /* structure to keep statistics of internally generated/satisfied calls */ 85 86 struct coda_op_stats coda_vfsopstats[CODA_VFSOPS_SIZE]; 87 88 #define MARK_ENTRY(op) (coda_vfsopstats[op].entries++) 89 #define MARK_INT_SAT(op) (coda_vfsopstats[op].sat_intrn++) 90 #define MARK_INT_FAIL(op) (coda_vfsopstats[op].unsat_intrn++) 91 #define MRAK_INT_GEN(op) (coda_vfsopstats[op].gen_intrn++) 92 93 extern const struct cdevsw vcoda_cdevsw; 94 extern const struct vnodeopv_desc coda_vnodeop_opv_desc; 95 96 const struct vnodeopv_desc * const coda_vnodeopv_descs[] = { 97 &coda_vnodeop_opv_desc, 98 NULL, 99 }; 100 101 struct vfsops coda_vfsops = { 102 MOUNT_CODA, 103 coda_mount, 104 coda_start, 105 coda_unmount, 106 coda_root, 107 coda_quotactl, 108 coda_nb_statfs, 109 coda_sync, 110 coda_vget, 111 (int (*) (struct mount *, struct fid *, struct vnode ** )) 112 eopnotsupp, 113 (int (*) (struct vnode *, struct fid *)) eopnotsupp, 114 coda_init, 115 NULL, 116 coda_done, 117 coda_sysctl, 118 (int (*)(void)) eopnotsupp, 119 (int (*)(struct mount *, struct mbuf *, int *, struct ucred **)) 120 eopnotsupp, 121 coda_vnodeopv_descs, 122 0 123 }; 124 125 int 126 coda_vfsopstats_init(void) 127 { 128 int i; 129 130 for (i=0;i<CODA_VFSOPS_SIZE;i++) { 131 coda_vfsopstats[i].opcode = i; 132 coda_vfsopstats[i].entries = 0; 133 coda_vfsopstats[i].sat_intrn = 0; 134 coda_vfsopstats[i].unsat_intrn = 0; 135 coda_vfsopstats[i].gen_intrn = 0; 136 } 137 138 return 0; 139 } 140 141 /* 142 * cfs mount vfsop 143 * Set up mount info record and attach it to vfs struct. 144 */ 145 /*ARGSUSED*/ 146 int 147 coda_mount(vfsp, path, data, ndp, p) 148 struct mount *vfsp; /* Allocated and initialized by mount(2) */ 149 const char *path; /* path covered: ignored by the fs-layer */ 150 void *data; /* Need to define a data type for this in netbsd? */ 151 struct nameidata *ndp; /* Clobber this to lookup the device name */ 152 struct proc *p; /* The ever-famous proc pointer */ 153 { 154 struct vnode *dvp; 155 struct cnode *cp; 156 dev_t dev; 157 struct coda_mntinfo *mi; 158 struct vnode *rootvp; 159 const struct cdevsw *cdev; 160 ViceFid rootfid; 161 ViceFid ctlfid; 162 int error; 163 164 if (vfsp->mnt_flag & MNT_GETARGS) 165 return 0; 166 ENTRY; 167 168 coda_vfsopstats_init(); 169 coda_vnodeopstats_init(); 170 171 MARK_ENTRY(CODA_MOUNT_STATS); 172 if (CODA_MOUNTED(vfsp)) { 173 MARK_INT_FAIL(CODA_MOUNT_STATS); 174 return(EBUSY); 175 } 176 177 /* Validate mount device. Similar to getmdev(). */ 178 179 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, data, p); 180 error = namei(ndp); 181 dvp = ndp->ni_vp; 182 183 if (error) { 184 MARK_INT_FAIL(CODA_MOUNT_STATS); 185 return (error); 186 } 187 if (dvp->v_type != VCHR) { 188 MARK_INT_FAIL(CODA_MOUNT_STATS); 189 vrele(dvp); 190 return(ENXIO); 191 } 192 dev = dvp->v_specinfo->si_rdev; 193 vrele(dvp); 194 cdev = cdevsw_lookup(dev); 195 if (cdev == NULL) { 196 MARK_INT_FAIL(CODA_MOUNT_STATS); 197 return(ENXIO); 198 } 199 200 /* 201 * See if the device table matches our expectations. 202 */ 203 if (cdev != &vcoda_cdevsw) 204 { 205 MARK_INT_FAIL(CODA_MOUNT_STATS); 206 return(ENXIO); 207 } 208 209 if (minor(dev) >= NVCODA || minor(dev) < 0) { 210 MARK_INT_FAIL(CODA_MOUNT_STATS); 211 return(ENXIO); 212 } 213 214 /* 215 * Initialize the mount record and link it to the vfs struct 216 */ 217 mi = &coda_mnttbl[minor(dev)]; 218 219 if (!VC_OPEN(&mi->mi_vcomm)) { 220 MARK_INT_FAIL(CODA_MOUNT_STATS); 221 return(ENODEV); 222 } 223 224 /* No initialization (here) of mi_vcomm! */ 225 vfsp->mnt_data = mi; 226 vfsp->mnt_stat.f_fsid.val[0] = 0; 227 vfsp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_CODA); 228 mi->mi_vfsp = vfsp; 229 230 /* 231 * Make a root vnode to placate the Vnode interface, but don't 232 * actually make the CODA_ROOT call to venus until the first call 233 * to coda_root in case a server is down while venus is starting. 234 */ 235 rootfid.Volume = 0; 236 rootfid.Vnode = 0; 237 rootfid.Unique = 0; 238 cp = make_coda_node(&rootfid, vfsp, VDIR); 239 rootvp = CTOV(cp); 240 rootvp->v_flag |= VROOT; 241 242 ctlfid.Volume = CTL_VOL; 243 ctlfid.Vnode = CTL_VNO; 244 ctlfid.Unique = CTL_UNI; 245 /* cp = make_coda_node(&ctlfid, vfsp, VCHR); 246 The above code seems to cause a loop in the cnode links. 247 I don't totally understand when it happens, it is caught 248 when closing down the system. 249 */ 250 cp = make_coda_node(&ctlfid, 0, VCHR); 251 252 coda_ctlvp = CTOV(cp); 253 254 /* Add vfs and rootvp to chain of vfs hanging off mntinfo */ 255 mi->mi_vfsp = vfsp; 256 mi->mi_rootvp = rootvp; 257 258 /* set filesystem block size */ 259 vfsp->mnt_stat.f_bsize = 8192; /* XXX -JJK */ 260 261 /* error is currently guaranteed to be zero, but in case some 262 code changes... */ 263 CODADEBUG(1, 264 myprintf(("coda_mount returned %d\n",error));); 265 if (error) 266 MARK_INT_FAIL(CODA_MOUNT_STATS); 267 else 268 MARK_INT_SAT(CODA_MOUNT_STATS); 269 270 return set_statfs_info("/coda", UIO_SYSSPACE, "CODA", UIO_SYSSPACE, vfsp, 271 p); 272 } 273 274 int 275 coda_start(vfsp, flags, p) 276 struct mount *vfsp; 277 int flags; 278 struct proc *p; 279 { 280 ENTRY; 281 return (0); 282 } 283 284 int 285 coda_unmount(vfsp, mntflags, p) 286 struct mount *vfsp; 287 int mntflags; 288 struct proc *p; 289 { 290 struct coda_mntinfo *mi = vftomi(vfsp); 291 int active, error = 0; 292 293 ENTRY; 294 MARK_ENTRY(CODA_UMOUNT_STATS); 295 if (!CODA_MOUNTED(vfsp)) { 296 MARK_INT_FAIL(CODA_UMOUNT_STATS); 297 return(EINVAL); 298 } 299 300 if (mi->mi_vfsp == vfsp) { /* We found the victim */ 301 if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp))) 302 return (EBUSY); /* Venus is still running */ 303 304 #ifdef DEBUG 305 printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp, VTOC(mi->mi_rootvp)); 306 #endif 307 vrele(mi->mi_rootvp); 308 309 active = coda_kill(vfsp, NOT_DOWNCALL); 310 mi->mi_rootvp->v_flag &= ~VROOT; 311 error = vflush(mi->mi_vfsp, NULLVP, FORCECLOSE); 312 printf("coda_unmount: active = %d, vflush active %d\n", active, error); 313 error = 0; 314 315 /* I'm going to take this out to allow lookups to go through. I'm 316 * not sure it's important anyway. -- DCS 2/2/94 317 */ 318 /* vfsp->VFS_DATA = NULL; */ 319 320 /* No more vfsp's to hold onto */ 321 mi->mi_vfsp = NULL; 322 mi->mi_rootvp = NULL; 323 324 if (error) 325 MARK_INT_FAIL(CODA_UMOUNT_STATS); 326 else 327 MARK_INT_SAT(CODA_UMOUNT_STATS); 328 329 return(error); 330 } 331 return (EINVAL); 332 } 333 334 /* 335 * find root of cfs 336 */ 337 int 338 coda_root(vfsp, vpp) 339 struct mount *vfsp; 340 struct vnode **vpp; 341 { 342 struct coda_mntinfo *mi = vftomi(vfsp); 343 struct vnode **result; 344 int error; 345 struct proc *p = curproc; /* XXX - bnoble */ 346 ViceFid VFid; 347 348 ENTRY; 349 MARK_ENTRY(CODA_ROOT_STATS); 350 result = NULL; 351 352 if (vfsp == mi->mi_vfsp) { 353 if ((VTOC(mi->mi_rootvp)->c_fid.Volume != 0) || 354 (VTOC(mi->mi_rootvp)->c_fid.Vnode != 0) || 355 (VTOC(mi->mi_rootvp)->c_fid.Unique != 0)) 356 { /* Found valid root. */ 357 *vpp = mi->mi_rootvp; 358 /* On Mach, this is vref. On NetBSD, VOP_LOCK */ 359 vref(*vpp); 360 vn_lock(*vpp, LK_EXCLUSIVE); 361 MARK_INT_SAT(CODA_ROOT_STATS); 362 return(0); 363 } 364 } 365 366 error = venus_root(vftomi(vfsp), p->p_cred->pc_ucred, p, &VFid); 367 368 if (!error) { 369 /* 370 * Save the new rootfid in the cnode, and rehash the cnode into the 371 * cnode hash with the new fid key. 372 */ 373 coda_unsave(VTOC(mi->mi_rootvp)); 374 VTOC(mi->mi_rootvp)->c_fid = VFid; 375 coda_save(VTOC(mi->mi_rootvp)); 376 377 *vpp = mi->mi_rootvp; 378 vref(*vpp); 379 vn_lock(*vpp, LK_EXCLUSIVE); 380 MARK_INT_SAT(CODA_ROOT_STATS); 381 goto exit; 382 } else if (error == ENODEV || error == EINTR) { 383 /* Gross hack here! */ 384 /* 385 * If Venus fails to respond to the CODA_ROOT call, coda_call returns 386 * ENODEV. Return the uninitialized root vnode to allow vfs 387 * operations such as unmount to continue. Without this hack, 388 * there is no way to do an unmount if Venus dies before a 389 * successful CODA_ROOT call is done. All vnode operations 390 * will fail. 391 */ 392 *vpp = mi->mi_rootvp; 393 vref(*vpp); 394 vn_lock(*vpp, LK_EXCLUSIVE); 395 MARK_INT_FAIL(CODA_ROOT_STATS); 396 error = 0; 397 goto exit; 398 } else { 399 CODADEBUG( CODA_ROOT, myprintf(("error %d in CODA_ROOT\n", error)); ); 400 MARK_INT_FAIL(CODA_ROOT_STATS); 401 402 goto exit; 403 } 404 exit: 405 return(error); 406 } 407 408 int 409 coda_quotactl(vfsp, cmd, uid, arg, p) 410 struct mount *vfsp; 411 int cmd; 412 uid_t uid; 413 caddr_t arg; 414 struct proc *p; 415 { 416 ENTRY; 417 return (EOPNOTSUPP); 418 } 419 420 /* 421 * Get file system statistics. 422 */ 423 int 424 coda_nb_statfs(vfsp, sbp, p) 425 struct mount *vfsp; 426 struct statfs *sbp; 427 struct proc *p; 428 { 429 struct coda_statfs fsstat; 430 int error; 431 432 ENTRY; 433 MARK_ENTRY(CODA_STATFS_STATS); 434 if (!CODA_MOUNTED(vfsp)) { 435 /* MARK_INT_FAIL(CODA_STATFS_STATS); */ 436 return(EINVAL); 437 } 438 439 memset(sbp, 0, sizeof(struct statfs)); 440 /* XXX - what to do about f_flags, others? --bnoble */ 441 /* Below This is what AFS does 442 #define NB_SFS_SIZ 0x895440 443 */ 444 /* Note: Normal fs's have a bsize of 0x400 == 1024 */ 445 446 error = venus_statfs(vftomi(vfsp), p->p_cred->pc_ucred, p, &fsstat); 447 448 if (!error) { 449 sbp->f_type = 0; 450 sbp->f_bsize = 8192; /* XXX */ 451 sbp->f_iosize = 8192; /* XXX */ 452 sbp->f_blocks = fsstat.f_blocks; 453 sbp->f_bfree = fsstat.f_bfree; 454 sbp->f_bavail = fsstat.f_bavail; 455 sbp->f_files = fsstat.f_files; 456 sbp->f_ffree = fsstat.f_ffree; 457 copy_statfs_info(sbp, vfsp); 458 } 459 460 MARK_INT_SAT(CODA_STATFS_STATS); 461 return(error); 462 } 463 464 /* 465 * Flush any pending I/O. 466 */ 467 int 468 coda_sync(vfsp, waitfor, cred, p) 469 struct mount *vfsp; 470 int waitfor; 471 struct ucred *cred; 472 struct proc *p; 473 { 474 ENTRY; 475 MARK_ENTRY(CODA_SYNC_STATS); 476 MARK_INT_SAT(CODA_SYNC_STATS); 477 return(0); 478 } 479 480 int 481 coda_vget(vfsp, ino, vpp) 482 struct mount *vfsp; 483 ino_t ino; 484 struct vnode **vpp; 485 { 486 ENTRY; 487 return (EOPNOTSUPP); 488 } 489 490 /* 491 * fhtovp is now what vget used to be in 4.3-derived systems. For 492 * some silly reason, vget is now keyed by a 32 bit ino_t, rather than 493 * a type-specific fid. 494 */ 495 int 496 coda_fhtovp(vfsp, fhp, nam, vpp, exflagsp, creadanonp) 497 struct mount *vfsp; 498 struct fid *fhp; 499 struct mbuf *nam; 500 struct vnode **vpp; 501 int *exflagsp; 502 struct ucred **creadanonp; 503 { 504 struct cfid *cfid = (struct cfid *)fhp; 505 struct cnode *cp = 0; 506 int error; 507 struct proc *p = curproc; /* XXX -mach */ 508 ViceFid VFid; 509 int vtype; 510 511 ENTRY; 512 513 MARK_ENTRY(CODA_VGET_STATS); 514 /* Check for vget of control object. */ 515 if (IS_CTL_FID(&cfid->cfid_fid)) { 516 *vpp = coda_ctlvp; 517 vref(coda_ctlvp); 518 MARK_INT_SAT(CODA_VGET_STATS); 519 return(0); 520 } 521 522 error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, p->p_cred->pc_ucred, p, &VFid, &vtype); 523 524 if (error) { 525 CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error));) 526 *vpp = (struct vnode *)0; 527 } else { 528 CODADEBUG(CODA_VGET, 529 myprintf(("vget: vol %lx vno %lx uni %lx type %d result %d\n", 530 VFid.Volume, VFid.Vnode, VFid.Unique, vtype, error)); ) 531 532 cp = make_coda_node(&VFid, vfsp, vtype); 533 *vpp = CTOV(cp); 534 } 535 return(error); 536 } 537 538 int 539 coda_vptofh(vnp, fidp) 540 struct vnode *vnp; 541 struct fid *fidp; 542 { 543 ENTRY; 544 return (EOPNOTSUPP); 545 } 546 547 void 548 coda_init(void) 549 { 550 ENTRY; 551 } 552 553 void 554 coda_done(void) 555 { 556 ENTRY; 557 } 558 559 int 560 coda_sysctl(name, namelen, oldp, oldlp, newp, newl, p) 561 int *name; 562 u_int namelen; 563 void *oldp; 564 size_t *oldlp; 565 void *newp; 566 size_t newl; 567 struct proc *p; 568 { 569 570 /* all sysctl names at this level are terminal */ 571 if (namelen != 1) 572 return (ENOTDIR); /* overloaded */ 573 574 switch (name[0]) { 575 /* 576 case FFS_CLUSTERREAD: 577 return (sysctl_int(oldp, oldlp, newp, newl, &doclusterread)); 578 */ 579 default: 580 return (EOPNOTSUPP); 581 } 582 /* NOTREACHED */ 583 } 584 585 /* 586 * To allow for greater ease of use, some vnodes may be orphaned when 587 * Venus dies. Certain operations should still be allowed to go 588 * through, but without propagating ophan-ness. So this function will 589 * get a new vnode for the file from the current run of Venus. */ 590 591 int 592 getNewVnode(vpp) 593 struct vnode **vpp; 594 { 595 struct cfid cfid; 596 struct coda_mntinfo *mi = vftomi((*vpp)->v_mount); 597 598 ENTRY; 599 600 cfid.cfid_len = (short)sizeof(ViceFid); 601 cfid.cfid_fid = VTOC(*vpp)->c_fid; /* Structure assignment. */ 602 /* XXX ? */ 603 604 /* We're guessing that if set, the 1st element on the list is a 605 * valid vnode to use. If not, return ENODEV as venus is dead. 606 */ 607 if (mi->mi_vfsp == NULL) 608 return ENODEV; 609 610 return coda_fhtovp(mi->mi_vfsp, (struct fid*)&cfid, NULL, vpp, 611 NULL, NULL); 612 } 613 614 #include <ufs/ufs/quota.h> 615 #include <ufs/ufs/ufsmount.h> 616 /* get the mount structure corresponding to a given device. Assume 617 * device corresponds to a UFS. Return NULL if no device is found. 618 */ 619 struct mount *devtomp(dev) 620 dev_t dev; 621 { 622 struct mount *mp, *nmp; 623 624 for (mp = mountlist.cqh_first; mp != (void*)&mountlist; mp = nmp) { 625 nmp = mp->mnt_list.cqe_next; 626 if ((!strcmp(mp->mnt_op->vfs_name, MOUNT_UFS)) && 627 ((VFSTOUFS(mp))->um_dev == (dev_t) dev)) { 628 /* mount corresponds to UFS and the device matches one we want */ 629 return(mp); 630 } 631 } 632 /* mount structure wasn't found */ 633 return(NULL); 634 } 635