1 /* $NetBSD: coda_vfsops.c,v 1.65 2008/04/29 18:18:08 ad 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.65 2008/04/29 18:18:08 ad 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/sysctl.h> 59 #include <sys/malloc.h> 60 #include <sys/conf.h> 61 #include <sys/namei.h> 62 #include <sys/dirent.h> 63 #include <sys/mount.h> 64 #include <sys/proc.h> 65 #include <sys/select.h> 66 #include <sys/kauth.h> 67 68 #include <coda/coda.h> 69 #include <coda/cnode.h> 70 #include <coda/coda_vfsops.h> 71 #include <coda/coda_venus.h> 72 #include <coda/coda_subr.h> 73 #include <coda/coda_opstats.h> 74 /* for VN_RDEV */ 75 #include <miscfs/specfs/specdev.h> 76 #include <miscfs/genfs/genfs.h> 77 78 MALLOC_DEFINE(M_CODA, "coda", "Coda file system structures and tables"); 79 80 int codadebug = 0; 81 82 int coda_vfsop_print_entry = 0; 83 #define ENTRY if(coda_vfsop_print_entry) myprintf(("Entered %s\n",__func__)) 84 85 struct vnode *coda_ctlvp; 86 struct coda_mntinfo coda_mnttbl[NVCODA]; /* indexed by minor device number */ 87 88 /* structure to keep statistics of internally generated/satisfied calls */ 89 90 struct coda_op_stats coda_vfsopstats[CODA_VFSOPS_SIZE]; 91 92 #define MARK_ENTRY(op) (coda_vfsopstats[op].entries++) 93 #define MARK_INT_SAT(op) (coda_vfsopstats[op].sat_intrn++) 94 #define MARK_INT_FAIL(op) (coda_vfsopstats[op].unsat_intrn++) 95 #define MRAK_INT_GEN(op) (coda_vfsopstats[op].gen_intrn++) 96 97 extern const struct cdevsw vcoda_cdevsw; 98 extern const struct vnodeopv_desc coda_vnodeop_opv_desc; 99 100 const struct vnodeopv_desc * const coda_vnodeopv_descs[] = { 101 &coda_vnodeop_opv_desc, 102 NULL, 103 }; 104 105 struct vfsops coda_vfsops = { 106 MOUNT_CODA, 107 256, /* This is the pathname, unlike every other fs */ 108 coda_mount, 109 coda_start, 110 coda_unmount, 111 coda_root, 112 (void *)eopnotsupp, /* vfs_quotactl */ 113 coda_nb_statvfs, 114 coda_sync, 115 coda_vget, 116 (void *)eopnotsupp, /* vfs_fhtovp */ 117 (void *)eopnotsupp, /* vfs_vptofh */ 118 coda_init, 119 NULL, /* vfs_reinit */ 120 coda_done, 121 (int (*)(void)) eopnotsupp, 122 (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp, 123 vfs_stdextattrctl, 124 (void *)eopnotsupp, /* vfs_suspendctl */ 125 genfs_renamelock_enter, 126 genfs_renamelock_exit, 127 (void *)eopnotsupp, 128 coda_vnodeopv_descs, 129 0, /* vfs_refcount */ 130 { NULL, NULL }, /* vfs_list */ 131 }; 132 133 VFS_ATTACH(coda_vfsops); 134 135 int 136 coda_vfsopstats_init(void) 137 { 138 int i; 139 140 for (i=0;i<CODA_VFSOPS_SIZE;i++) { 141 coda_vfsopstats[i].opcode = i; 142 coda_vfsopstats[i].entries = 0; 143 coda_vfsopstats[i].sat_intrn = 0; 144 coda_vfsopstats[i].unsat_intrn = 0; 145 coda_vfsopstats[i].gen_intrn = 0; 146 } 147 148 return 0; 149 } 150 151 /* 152 * cfs mount vfsop 153 * Set up mount info record and attach it to vfs struct. 154 */ 155 /*ARGSUSED*/ 156 int 157 coda_mount(struct mount *vfsp, /* Allocated and initialized by mount(2) */ 158 const char *path, /* path covered: ignored by the fs-layer */ 159 void *data, /* Need to define a data type for this in netbsd? */ 160 size_t *data_len) 161 { 162 struct lwp *l = curlwp; 163 struct nameidata nd; 164 struct vnode *dvp; 165 struct cnode *cp; 166 dev_t dev; 167 struct coda_mntinfo *mi; 168 struct vnode *rtvp; 169 const struct cdevsw *cdev; 170 CodaFid rootfid = INVAL_FID; 171 CodaFid ctlfid = CTL_FID; 172 int error; 173 174 if (vfsp->mnt_flag & MNT_GETARGS) 175 return EINVAL; 176 ENTRY; 177 178 coda_vfsopstats_init(); 179 coda_vnodeopstats_init(); 180 181 MARK_ENTRY(CODA_MOUNT_STATS); 182 if (CODA_MOUNTED(vfsp)) { 183 MARK_INT_FAIL(CODA_MOUNT_STATS); 184 return(EBUSY); 185 } 186 187 /* Validate mount device. Similar to getmdev(). */ 188 189 /* 190 * XXX: coda passes the mount device as the entire mount args, 191 * All other fs pass a structure contining a pointer. 192 * In order to get sys_mount() to do the copyin() we've set a 193 * fixed default size for the filename buffer. 194 */ 195 /* Ensure that namei() doesn't run off the filename buffer */ 196 ((char *)data)[*data_len - 1] = 0; 197 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, data); 198 error = namei(&nd); 199 dvp = nd.ni_vp; 200 201 if (error) { 202 MARK_INT_FAIL(CODA_MOUNT_STATS); 203 return (error); 204 } 205 if (dvp->v_type != VCHR) { 206 MARK_INT_FAIL(CODA_MOUNT_STATS); 207 vrele(dvp); 208 return(ENXIO); 209 } 210 dev = dvp->v_rdev; 211 vrele(dvp); 212 cdev = cdevsw_lookup(dev); 213 if (cdev == NULL) { 214 MARK_INT_FAIL(CODA_MOUNT_STATS); 215 return(ENXIO); 216 } 217 218 /* 219 * See if the device table matches our expectations. 220 */ 221 if (cdev != &vcoda_cdevsw) 222 { 223 MARK_INT_FAIL(CODA_MOUNT_STATS); 224 return(ENXIO); 225 } 226 227 if (minor(dev) >= NVCODA || minor(dev) < 0) { 228 MARK_INT_FAIL(CODA_MOUNT_STATS); 229 return(ENXIO); 230 } 231 232 /* 233 * Initialize the mount record and link it to the vfs struct 234 */ 235 mi = &coda_mnttbl[minor(dev)]; 236 237 if (!VC_OPEN(&mi->mi_vcomm)) { 238 MARK_INT_FAIL(CODA_MOUNT_STATS); 239 return(ENODEV); 240 } 241 242 /* No initialization (here) of mi_vcomm! */ 243 vfsp->mnt_data = mi; 244 vfsp->mnt_stat.f_fsidx.__fsid_val[0] = 0; 245 vfsp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_CODA); 246 vfsp->mnt_stat.f_fsid = vfsp->mnt_stat.f_fsidx.__fsid_val[0]; 247 vfsp->mnt_stat.f_namemax = MAXNAMLEN; 248 mi->mi_vfsp = vfsp; 249 250 /* 251 * Make a root vnode to placate the Vnode interface, but don't 252 * actually make the CODA_ROOT call to venus until the first call 253 * to coda_root in case a server is down while venus is starting. 254 */ 255 cp = make_coda_node(&rootfid, vfsp, VDIR); 256 rtvp = CTOV(cp); 257 rtvp->v_vflag |= VV_ROOT; 258 259 /* cp = make_coda_node(&ctlfid, vfsp, VCHR); 260 The above code seems to cause a loop in the cnode links. 261 I don't totally understand when it happens, it is caught 262 when closing down the system. 263 */ 264 cp = make_coda_node(&ctlfid, 0, VCHR); 265 266 coda_ctlvp = CTOV(cp); 267 268 /* Add vfs and rootvp to chain of vfs hanging off mntinfo */ 269 mi->mi_vfsp = vfsp; 270 mi->mi_rootvp = rtvp; 271 272 /* set filesystem block size */ 273 vfsp->mnt_stat.f_bsize = 8192; /* XXX -JJK */ 274 vfsp->mnt_stat.f_frsize = 8192; /* XXX -JJK */ 275 276 /* error is currently guaranteed to be zero, but in case some 277 code changes... */ 278 CODADEBUG(1, 279 myprintf(("coda_mount returned %d\n",error));); 280 if (error) 281 MARK_INT_FAIL(CODA_MOUNT_STATS); 282 else 283 MARK_INT_SAT(CODA_MOUNT_STATS); 284 285 return set_statvfs_info("/coda", UIO_SYSSPACE, "CODA", UIO_SYSSPACE, 286 vfsp->mnt_op->vfs_name, vfsp, l); 287 } 288 289 int 290 coda_start(struct mount *vfsp, int flags) 291 { 292 ENTRY; 293 vftomi(vfsp)->mi_started = 1; 294 return (0); 295 } 296 297 int 298 coda_unmount(struct mount *vfsp, int mntflags) 299 { 300 struct coda_mntinfo *mi = vftomi(vfsp); 301 int active, error = 0; 302 303 ENTRY; 304 MARK_ENTRY(CODA_UMOUNT_STATS); 305 if (!CODA_MOUNTED(vfsp)) { 306 MARK_INT_FAIL(CODA_UMOUNT_STATS); 307 return(EINVAL); 308 } 309 310 if (mi->mi_vfsp == vfsp) { /* We found the victim */ 311 if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp))) 312 return (EBUSY); /* Venus is still running */ 313 314 #ifdef DEBUG 315 printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp, VTOC(mi->mi_rootvp)); 316 #endif 317 mi->mi_started = 0; 318 319 vrele(mi->mi_rootvp); 320 321 active = coda_kill(vfsp, NOT_DOWNCALL); 322 mi->mi_rootvp->v_vflag &= ~VV_ROOT; 323 error = vflush(mi->mi_vfsp, NULLVP, FORCECLOSE); 324 printf("coda_unmount: active = %d, vflush active %d\n", active, error); 325 error = 0; 326 327 /* I'm going to take this out to allow lookups to go through. I'm 328 * not sure it's important anyway. -- DCS 2/2/94 329 */ 330 /* vfsp->VFS_DATA = NULL; */ 331 332 /* No more vfsp's to hold onto */ 333 mi->mi_vfsp = NULL; 334 mi->mi_rootvp = NULL; 335 336 if (error) 337 MARK_INT_FAIL(CODA_UMOUNT_STATS); 338 else 339 MARK_INT_SAT(CODA_UMOUNT_STATS); 340 341 return(error); 342 } 343 return (EINVAL); 344 } 345 346 /* 347 * find root of cfs 348 */ 349 int 350 coda_root(struct mount *vfsp, struct vnode **vpp) 351 { 352 struct coda_mntinfo *mi = vftomi(vfsp); 353 int error; 354 struct lwp *l = curlwp; /* XXX - bnoble */ 355 CodaFid VFid; 356 static const CodaFid invalfid = INVAL_FID; 357 358 ENTRY; 359 MARK_ENTRY(CODA_ROOT_STATS); 360 361 if (vfsp == mi->mi_vfsp) { 362 if (memcmp(&VTOC(mi->mi_rootvp)->c_fid, &invalfid, sizeof(CodaFid))) 363 { /* Found valid root. */ 364 *vpp = mi->mi_rootvp; 365 /* On Mach, this is vref. On NetBSD, VOP_LOCK */ 366 vref(*vpp); 367 vn_lock(*vpp, LK_EXCLUSIVE); 368 MARK_INT_SAT(CODA_ROOT_STATS); 369 return(0); 370 } 371 } 372 373 error = venus_root(vftomi(vfsp), l->l_cred, l->l_proc, &VFid); 374 375 if (!error) { 376 /* 377 * Save the new rootfid in the cnode, and rehash the cnode into the 378 * cnode hash with the new fid key. 379 */ 380 coda_unsave(VTOC(mi->mi_rootvp)); 381 VTOC(mi->mi_rootvp)->c_fid = VFid; 382 coda_save(VTOC(mi->mi_rootvp)); 383 384 *vpp = mi->mi_rootvp; 385 vref(*vpp); 386 vn_lock(*vpp, LK_EXCLUSIVE); 387 MARK_INT_SAT(CODA_ROOT_STATS); 388 goto exit; 389 } else if (error == ENODEV || error == EINTR) { 390 /* Gross hack here! */ 391 /* 392 * If Venus fails to respond to the CODA_ROOT call, coda_call returns 393 * ENODEV. Return the uninitialized root vnode to allow vfs 394 * operations such as unmount to continue. Without this hack, 395 * there is no way to do an unmount if Venus dies before a 396 * successful CODA_ROOT call is done. All vnode operations 397 * will fail. 398 */ 399 *vpp = mi->mi_rootvp; 400 vref(*vpp); 401 vn_lock(*vpp, LK_EXCLUSIVE); 402 MARK_INT_FAIL(CODA_ROOT_STATS); 403 error = 0; 404 goto exit; 405 } else { 406 CODADEBUG( CODA_ROOT, myprintf(("error %d in CODA_ROOT\n", error)); ); 407 MARK_INT_FAIL(CODA_ROOT_STATS); 408 409 goto exit; 410 } 411 exit: 412 return(error); 413 } 414 415 /* 416 * Get file system statistics. 417 */ 418 int 419 coda_nb_statvfs(struct mount *vfsp, struct statvfs *sbp) 420 { 421 struct lwp *l = curlwp; 422 struct coda_statfs fsstat; 423 int error; 424 425 ENTRY; 426 MARK_ENTRY(CODA_STATFS_STATS); 427 if (!CODA_MOUNTED(vfsp)) { 428 /* MARK_INT_FAIL(CODA_STATFS_STATS); */ 429 return(EINVAL); 430 } 431 432 /* XXX - what to do about f_flags, others? --bnoble */ 433 /* Below This is what AFS does 434 #define NB_SFS_SIZ 0x895440 435 */ 436 /* Note: Normal fs's have a bsize of 0x400 == 1024 */ 437 438 error = venus_statfs(vftomi(vfsp), l->l_cred, l, &fsstat); 439 440 if (!error) { 441 sbp->f_bsize = 8192; /* XXX */ 442 sbp->f_frsize = 8192; /* XXX */ 443 sbp->f_iosize = 8192; /* XXX */ 444 sbp->f_blocks = fsstat.f_blocks; 445 sbp->f_bfree = fsstat.f_bfree; 446 sbp->f_bavail = fsstat.f_bavail; 447 sbp->f_bresvd = 0; 448 sbp->f_files = fsstat.f_files; 449 sbp->f_ffree = fsstat.f_ffree; 450 sbp->f_favail = fsstat.f_ffree; 451 sbp->f_fresvd = 0; 452 copy_statvfs_info(sbp, vfsp); 453 } 454 455 MARK_INT_SAT(CODA_STATFS_STATS); 456 return(error); 457 } 458 459 /* 460 * Flush any pending I/O. 461 */ 462 int 463 coda_sync(struct mount *vfsp, int waitfor, 464 kauth_cred_t cred) 465 { 466 ENTRY; 467 MARK_ENTRY(CODA_SYNC_STATS); 468 MARK_INT_SAT(CODA_SYNC_STATS); 469 return(0); 470 } 471 472 int 473 coda_vget(struct mount *vfsp, ino_t ino, 474 struct vnode **vpp) 475 { 476 ENTRY; 477 return (EOPNOTSUPP); 478 } 479 480 /* 481 * fhtovp is now what vget used to be in 4.3-derived systems. For 482 * some silly reason, vget is now keyed by a 32 bit ino_t, rather than 483 * a type-specific fid. 484 */ 485 int 486 coda_fhtovp(struct mount *vfsp, struct fid *fhp, struct mbuf *nam, 487 struct vnode **vpp, int *exflagsp, 488 kauth_cred_t *creadanonp) 489 { 490 struct cfid *cfid = (struct cfid *)fhp; 491 struct cnode *cp = 0; 492 int error; 493 struct lwp *l = curlwp; /* XXX -mach */ 494 CodaFid VFid; 495 int vtype; 496 497 ENTRY; 498 499 MARK_ENTRY(CODA_VGET_STATS); 500 /* Check for vget of control object. */ 501 if (IS_CTL_FID(&cfid->cfid_fid)) { 502 *vpp = coda_ctlvp; 503 vref(coda_ctlvp); 504 MARK_INT_SAT(CODA_VGET_STATS); 505 return(0); 506 } 507 508 error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, l->l_cred, l->l_proc, &VFid, &vtype); 509 510 if (error) { 511 CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error));) 512 *vpp = (struct vnode *)0; 513 } else { 514 CODADEBUG(CODA_VGET, 515 myprintf(("vget: %s type %d result %d\n", 516 coda_f2s(&VFid), vtype, error)); ) 517 518 cp = make_coda_node(&VFid, vfsp, vtype); 519 *vpp = CTOV(cp); 520 } 521 return(error); 522 } 523 524 int 525 coda_vptofh(struct vnode *vnp, struct fid *fidp) 526 { 527 ENTRY; 528 return (EOPNOTSUPP); 529 } 530 531 void 532 coda_init(void) 533 { 534 ENTRY; 535 } 536 537 void 538 coda_done(void) 539 { 540 ENTRY; 541 } 542 543 SYSCTL_SETUP(sysctl_vfs_coda_setup, "sysctl vfs.coda subtree setup") 544 { 545 sysctl_createv(clog, 0, NULL, NULL, 546 CTLFLAG_PERMANENT, 547 CTLTYPE_NODE, "vfs", NULL, 548 NULL, 0, NULL, 0, 549 CTL_VFS, CTL_EOL); 550 sysctl_createv(clog, 0, NULL, NULL, 551 CTLFLAG_PERMANENT, 552 CTLTYPE_NODE, "coda", 553 SYSCTL_DESCR("code vfs options"), 554 NULL, 0, NULL, 0, 555 CTL_VFS, 18, CTL_EOL); 556 /* 557 * XXX the "18" above could be dynamic, thereby eliminating 558 * one more instance of the "number to vfs" mapping problem, 559 * but "18" is the order as taken from sys/mount.h 560 */ 561 562 /* 563 sysctl_createv(clog, 0, NULL, NULL, 564 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 565 CTLTYPE_INT, "clusterread", 566 SYSCTL_DESCR( anyone? ), 567 NULL, 0, &doclusterread, 0, 568 CTL_VFS, 18, FFS_CLUSTERREAD, CTL_EOL); 569 */ 570 } 571 572 /* 573 * To allow for greater ease of use, some vnodes may be orphaned when 574 * Venus dies. Certain operations should still be allowed to go 575 * through, but without propagating orphan-ness. So this function will 576 * get a new vnode for the file from the current run of Venus. 577 */ 578 579 int 580 getNewVnode(struct vnode **vpp) 581 { 582 struct cfid cfid; 583 struct coda_mntinfo *mi = vftomi((*vpp)->v_mount); 584 585 ENTRY; 586 587 cfid.cfid_len = (short)sizeof(CodaFid); 588 cfid.cfid_fid = VTOC(*vpp)->c_fid; /* Structure assignment. */ 589 /* XXX ? */ 590 591 /* We're guessing that if set, the 1st element on the list is a 592 * valid vnode to use. If not, return ENODEV as venus is dead. 593 */ 594 if (mi->mi_vfsp == NULL) 595 return ENODEV; 596 597 return coda_fhtovp(mi->mi_vfsp, (struct fid*)&cfid, NULL, vpp, 598 NULL, NULL); 599 } 600 601 #include <ufs/ufs/quota.h> 602 #include <ufs/ufs/ufsmount.h> 603 /* get the mount structure corresponding to a given device. Assume 604 * device corresponds to a UFS. Return NULL if no device is found. 605 */ 606 struct mount *devtomp(dev_t dev) 607 { 608 struct mount *mp, *nmp; 609 610 for (mp = mountlist.cqh_first; mp != (void*)&mountlist; mp = nmp) { 611 nmp = mp->mnt_list.cqe_next; 612 if ((!strcmp(mp->mnt_op->vfs_name, MOUNT_UFS)) && 613 ((VFSTOUFS(mp))->um_dev == (dev_t) dev)) { 614 /* mount corresponds to UFS and the device matches one we want */ 615 return(mp); 616 } 617 } 618 /* mount structure wasn't found */ 619 return(NULL); 620 } 621