coda_vfsops.c revision 171379
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/cfs/coda_vfsops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ 29 */ 30/*- 31 * Mach Operating System 32 * Copyright (c) 1989 Carnegie-Mellon University 33 * All rights reserved. The CMU software License Agreement specifies 34 * the terms and conditions for use and redistribution. 35 */ 36 37/* 38 * This code was written for the Coda filesystem at Carnegie Mellon 39 * University. Contributers include David Steere, James Kistler, and 40 * M. Satyanarayanan. 41 */ 42 43#include <sys/cdefs.h> 44__FBSDID("$FreeBSD: head/sys/fs/coda/coda_vfsops.c 171379 2007-07-11 21:34:41Z rwatson $"); 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/conf.h> 49#include <sys/kernel.h> 50#include <sys/lock.h> 51#include <sys/malloc.h> 52#include <sys/mount.h> 53#include <sys/namei.h> 54#include <sys/proc.h> 55 56#include <coda/coda.h> 57#include <coda/cnode.h> 58#include <coda/coda_vfsops.h> 59#include <coda/coda_venus.h> 60#include <coda/coda_subr.h> 61#include <coda/coda_opstats.h> 62 63MALLOC_DEFINE(M_CODA, "coda", "Various Coda Structures"); 64 65int codadebug = 0; 66int coda_vfsop_print_entry = 0; 67#define ENTRY if(coda_vfsop_print_entry) myprintf(("Entered %s\n",__func__)) 68 69struct vnode *coda_ctlvp; 70 71/* structure to keep statistics of internally generated/satisfied calls */ 72 73struct coda_op_stats coda_vfsopstats[CODA_VFSOPS_SIZE]; 74 75#define MARK_ENTRY(op) (coda_vfsopstats[op].entries++) 76#define MARK_INT_SAT(op) (coda_vfsopstats[op].sat_intrn++) 77#define MARK_INT_FAIL(op) (coda_vfsopstats[op].unsat_intrn++) 78#define MARK_INT_GEN(op) (coda_vfsopstats[op].gen_intrn++) 79 80extern int coda_nc_initialized; /* Set if cache has been initialized */ 81extern int vc_nb_open(struct cdev *, int, int, struct thread *); 82 83int 84coda_vfsopstats_init(void) 85{ 86 register int i; 87 88 for (i=0;i<CODA_VFSOPS_SIZE;i++) { 89 coda_vfsopstats[i].opcode = i; 90 coda_vfsopstats[i].entries = 0; 91 coda_vfsopstats[i].sat_intrn = 0; 92 coda_vfsopstats[i].unsat_intrn = 0; 93 coda_vfsopstats[i].gen_intrn = 0; 94 } 95 96 return 0; 97} 98 99static const char *coda_opts[] = { "from", NULL }; 100/* 101 * cfs mount vfsop 102 * Set up mount info record and attach it to vfs struct. 103 */ 104/*ARGSUSED*/ 105int 106coda_mount(struct mount *vfsp, struct thread *td) 107{ 108 struct vnode *dvp; 109 struct cnode *cp; 110 struct cdev *dev; 111 struct coda_mntinfo *mi; 112 struct vnode *rootvp; 113 CodaFid rootfid = INVAL_FID; 114 CodaFid ctlfid = CTL_FID; 115 int error; 116 struct nameidata ndp; 117 ENTRY; 118 char *from; 119 120 if (vfs_filteropt(vfsp->mnt_optnew, coda_opts)) 121 return (EINVAL); 122 123 from = vfs_getopts(vfsp->mnt_optnew, "from", &error); 124 if (error) 125 return (error); 126 127 coda_vfsopstats_init(); 128 coda_vnodeopstats_init(); 129 130 MARK_ENTRY(CODA_MOUNT_STATS); 131 if (CODA_MOUNTED(vfsp)) { 132 MARK_INT_FAIL(CODA_MOUNT_STATS); 133 return(EBUSY); 134 } 135 136 /* Validate mount device. Similar to getmdev(). */ 137 NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, td); 138 error = namei(&ndp); 139 dvp = ndp.ni_vp; 140 141 if (error) { 142 MARK_INT_FAIL(CODA_MOUNT_STATS); 143 return (error); 144 } 145 if (dvp->v_type != VCHR) { 146 MARK_INT_FAIL(CODA_MOUNT_STATS); 147 vrele(dvp); 148 NDFREE(&ndp, NDF_ONLY_PNBUF); 149 return(ENXIO); 150 } 151 dev = dvp->v_rdev; 152 vrele(dvp); 153 NDFREE(&ndp, NDF_ONLY_PNBUF); 154 155 /* 156 * Initialize the mount record and link it to the vfs struct 157 */ 158 mi = dev2coda_mntinfo(dev); 159 if (!mi) { 160 MARK_INT_FAIL(CODA_MOUNT_STATS); 161 printf("Coda mount: %s is not a cfs device\n", from); 162 return(ENXIO); 163 } 164 165 if (!VC_OPEN(&mi->mi_vcomm)) { 166 MARK_INT_FAIL(CODA_MOUNT_STATS); 167 return(ENODEV); 168 } 169 170 /* No initialization (here) of mi_vcomm! */ 171 vfsp->mnt_data = (qaddr_t)mi; 172 vfs_getnewfsid (vfsp); 173 174 mi->mi_vfsp = vfsp; 175 mi->mi_started = 0; /* XXX See coda_root() */ 176 177 /* 178 * Make a root vnode to placate the Vnode interface, but don't 179 * actually make the CODA_ROOT call to venus until the first call 180 * to coda_root in case a server is down while venus is starting. 181 */ 182 cp = make_coda_node(&rootfid, vfsp, VDIR); 183 rootvp = CTOV(cp); 184 rootvp->v_vflag |= VV_ROOT; 185 186 cp = make_coda_node(&ctlfid, vfsp, VREG); 187 coda_ctlvp = CTOV(cp); 188 189 /* Add vfs and rootvp to chain of vfs hanging off mntinfo */ 190 mi->mi_vfsp = vfsp; 191 mi->mi_rootvp = rootvp; 192 193 vfs_mountedfrom(vfsp, from); 194 /* error is currently guaranteed to be zero, but in case some 195 code changes... */ 196 CODADEBUG(1, 197 myprintf(("coda_omount returned %d\n",error));); 198 if (error) 199 MARK_INT_FAIL(CODA_MOUNT_STATS); 200 else 201 MARK_INT_SAT(CODA_MOUNT_STATS); 202 203 return(error); 204} 205 206int 207coda_unmount(vfsp, mntflags, td) 208 struct mount *vfsp; 209 int mntflags; 210 struct thread *td; 211{ 212 struct coda_mntinfo *mi = vftomi(vfsp); 213 int active, error = 0; 214 215 ENTRY; 216 MARK_ENTRY(CODA_UMOUNT_STATS); 217 if (!CODA_MOUNTED(vfsp)) { 218 MARK_INT_FAIL(CODA_UMOUNT_STATS); 219 return(EINVAL); 220 } 221 222 if (mi->mi_vfsp == vfsp) { /* We found the victim */ 223 if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp))) 224 return (EBUSY); /* Venus is still running */ 225 226#ifdef DEBUG 227 printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp, VTOC(mi->mi_rootvp)); 228#endif 229 vrele(mi->mi_rootvp); 230 active = coda_kill(vfsp, NOT_DOWNCALL); 231 ASSERT_VOP_LOCKED(mi->mi_rootvp, "coda_unmount"); 232 mi->mi_rootvp->v_vflag &= ~VV_ROOT; 233 error = vflush(mi->mi_vfsp, 0, FORCECLOSE, td); 234#ifdef CODA_VERBOSE 235 printf("coda_unmount: active = %d, vflush active %d\n", active, error); 236#endif 237 error = 0; 238 /* I'm going to take this out to allow lookups to go through. I'm 239 * not sure it's important anyway. -- DCS 2/2/94 240 */ 241 /* vfsp->VFS_DATA = NULL; */ 242 243 /* No more vfsp's to hold onto */ 244 mi->mi_vfsp = NULL; 245 mi->mi_rootvp = NULL; 246 247 if (error) 248 MARK_INT_FAIL(CODA_UMOUNT_STATS); 249 else 250 MARK_INT_SAT(CODA_UMOUNT_STATS); 251 252 return(error); 253 } 254 return (EINVAL); 255} 256 257/* 258 * find root of cfs 259 */ 260int 261coda_root(vfsp, flags, vpp, td) 262 struct mount *vfsp; 263 int flags; 264 struct vnode **vpp; 265 struct thread *td; 266{ 267 struct coda_mntinfo *mi = vftomi(vfsp); 268 struct vnode **result; 269 int error; 270 struct proc *p = td->td_proc; 271 CodaFid VFid; 272 static const CodaFid invalfid = INVAL_FID; 273 274 ENTRY; 275 MARK_ENTRY(CODA_ROOT_STATS); 276 result = NULL; 277 278 if (vfsp == mi->mi_vfsp) { 279 /* 280 * Cache the root across calls. We only need to pass the request 281 * on to Venus if the root vnode is the dummy we installed in 282 * coda_omount() with all c_fid members zeroed. 283 * 284 * XXX In addition, we assume that the first call to coda_root() 285 * is from vfs_omount() 286 * (before the call to checkdirs()) and return the dummy root 287 * node to avoid a deadlock. This bug is fixed in the Coda CVS 288 * repository but not in any released versions as of 6 Mar 2003. 289 */ 290 if (memcmp(&VTOC(mi->mi_rootvp)->c_fid, &invalfid, 291 sizeof(CodaFid)) != 0 || mi->mi_started == 0) 292 { /* Found valid root. */ 293 *vpp = mi->mi_rootvp; 294 mi->mi_started = 1; 295 296 /* On Mach, this is vref. On NetBSD, VOP_LOCK */ 297#if 1 298 vref(*vpp); 299 vn_lock(*vpp, LK_EXCLUSIVE, td); 300#else 301 vget(*vpp, LK_EXCLUSIVE, td); 302#endif 303 MARK_INT_SAT(CODA_ROOT_STATS); 304 return(0); 305 } 306 } 307 308 error = venus_root(vftomi(vfsp), td->td_ucred, p, &VFid); 309 310 if (!error) { 311 /* 312 * Save the new rootfid in the cnode, and rehash the cnode into the 313 * cnode hash with the new fid key. 314 */ 315 coda_unsave(VTOC(mi->mi_rootvp)); 316 VTOC(mi->mi_rootvp)->c_fid = VFid; 317 coda_save(VTOC(mi->mi_rootvp)); 318 319 *vpp = mi->mi_rootvp; 320#if 1 321 vref(*vpp); 322 vn_lock(*vpp, LK_EXCLUSIVE, td); 323#else 324 vget(*vpp, LK_EXCLUSIVE, td); 325#endif 326 327 MARK_INT_SAT(CODA_ROOT_STATS); 328 goto exit; 329 } else if (error == ENODEV || error == EINTR) { 330 /* Gross hack here! */ 331 /* 332 * If Venus fails to respond to the CODA_ROOT call, coda_call returns 333 * ENODEV. Return the uninitialized root vnode to allow vfs 334 * operations such as unmount to continue. Without this hack, 335 * there is no way to do an unmount if Venus dies before a 336 * successful CODA_ROOT call is done. All vnode operations 337 * will fail. 338 */ 339 *vpp = mi->mi_rootvp; 340#if 1 341 vref(*vpp); 342 vn_lock(*vpp, LK_EXCLUSIVE, td); 343#else 344 vget(*vpp, LK_EXCLUSIVE, td); 345#endif 346 347 MARK_INT_FAIL(CODA_ROOT_STATS); 348 error = 0; 349 goto exit; 350 } else { 351 CODADEBUG( CODA_ROOT, myprintf(("error %d in CODA_ROOT\n", error)); ); 352 MARK_INT_FAIL(CODA_ROOT_STATS); 353 354 goto exit; 355 } 356 357 exit: 358 return(error); 359} 360 361/* 362 * Get filesystem statistics. 363 */ 364int 365coda_nb_statfs(vfsp, sbp, td) 366 register struct mount *vfsp; 367 struct statfs *sbp; 368 struct thread *td; 369{ 370 ENTRY; 371/* MARK_ENTRY(CODA_STATFS_STATS); */ 372 if (!CODA_MOUNTED(vfsp)) { 373/* MARK_INT_FAIL(CODA_STATFS_STATS);*/ 374 return(EINVAL); 375 } 376 377 bzero(sbp, sizeof(struct statfs)); 378 /* XXX - what to do about f_flags, others? --bnoble */ 379 /* Below This is what AFS does 380 #define NB_SFS_SIZ 0x895440 381 */ 382 /* Note: Normal fs's have a bsize of 0x400 == 1024 */ 383 sbp->f_type = vfsp->mnt_vfc->vfc_typenum; 384 sbp->f_bsize = 8192; /* XXX */ 385 sbp->f_iosize = 8192; /* XXX */ 386#define NB_SFS_SIZ 0x8AB75D 387 sbp->f_blocks = NB_SFS_SIZ; 388 sbp->f_bfree = NB_SFS_SIZ; 389 sbp->f_bavail = NB_SFS_SIZ; 390 sbp->f_files = NB_SFS_SIZ; 391 sbp->f_ffree = NB_SFS_SIZ; 392 bcopy((caddr_t)&(vfsp->mnt_stat.f_fsid), (caddr_t)&(sbp->f_fsid), sizeof (fsid_t)); 393 snprintf(sbp->f_mntonname, sizeof(sbp->f_mntonname), "/coda"); 394 snprintf(sbp->f_fstypename, sizeof(sbp->f_fstypename), "coda"); 395/* MARK_INT_SAT(CODA_STATFS_STATS); */ 396 return(0); 397} 398 399/* 400 * Flush any pending I/O. 401 */ 402int 403coda_sync(vfsp, waitfor, td) 404 struct mount *vfsp; 405 int waitfor; 406 struct thread *td; 407{ 408 ENTRY; 409 MARK_ENTRY(CODA_SYNC_STATS); 410 MARK_INT_SAT(CODA_SYNC_STATS); 411 return(0); 412} 413 414/* 415 * fhtovp is now what vget used to be in 4.3-derived systems. For 416 * some silly reason, vget is now keyed by a 32 bit ino_t, rather than 417 * a type-specific fid. 418 */ 419int 420coda_fhtovp(vfsp, fhp, nam, vpp, exflagsp, creadanonp) 421 register struct mount *vfsp; 422 struct fid *fhp; 423 struct mbuf *nam; 424 struct vnode **vpp; 425 int *exflagsp; 426 struct ucred **creadanonp; 427{ 428 struct cfid *cfid = (struct cfid *)fhp; 429 struct cnode *cp = 0; 430 int error; 431 struct thread *td = curthread; /* XXX -mach */ 432 struct proc *p = td->td_proc; 433 CodaFid VFid; 434 int vtype; 435 436 ENTRY; 437 438 MARK_ENTRY(CODA_VGET_STATS); 439 /* Check for vget of control object. */ 440 if (IS_CTL_FID(&cfid->cfid_fid)) { 441 *vpp = coda_ctlvp; 442 vref(coda_ctlvp); 443 MARK_INT_SAT(CODA_VGET_STATS); 444 return(0); 445 } 446 447 error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, td->td_ucred, p, &VFid, &vtype); 448 449 if (error) { 450 CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error));) 451 *vpp = (struct vnode *)0; 452 } else { 453 CODADEBUG(CODA_VGET, 454 myprintf(("vget: %s type %d result %d\n", 455 coda_f2s(&VFid), vtype, error)); ) 456 cp = make_coda_node(&VFid, vfsp, vtype); 457 *vpp = CTOV(cp); 458 } 459 return(error); 460} 461 462/* 463 * To allow for greater ease of use, some vnodes may be orphaned when 464 * Venus dies. Certain operations should still be allowed to go 465 * through, but without propagating ophan-ness. So this function will 466 * get a new vnode for the file from the current run of Venus. */ 467 468int 469getNewVnode(vpp) 470 struct vnode **vpp; 471{ 472 struct cfid cfid; 473 struct coda_mntinfo *mi = vftomi((*vpp)->v_mount); 474 475 ENTRY; 476 477 cfid.cfid_len = (short)sizeof(CodaFid); 478 cfid.cfid_fid = VTOC(*vpp)->c_fid; /* Structure assignment. */ 479 /* XXX ? */ 480 481 /* We're guessing that if set, the 1st element on the list is a 482 * valid vnode to use. If not, return ENODEV as venus is dead. 483 */ 484 if (mi->mi_vfsp == NULL) 485 return ENODEV; 486 487 return coda_fhtovp(mi->mi_vfsp, (struct fid*)&cfid, NULL, vpp, 488 NULL, NULL); 489} 490 491#include <ufs/ufs/extattr.h> 492#include <ufs/ufs/quota.h> 493#include <ufs/ufs/ufsmount.h> 494/* get the mount structure corresponding to a given device. Assume 495 * device corresponds to a UFS. Return NULL if no device is found. 496 */ 497struct mount *devtomp(dev) 498 struct cdev *dev; 499{ 500 struct mount *mp; 501 502 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 503 if (((VFSTOUFS(mp))->um_dev == dev)) { 504 /* mount corresponds to UFS and the device matches one we want */ 505 return(mp); 506 } 507 } 508 /* mount structure wasn't found */ 509 return(NULL); 510} 511 512struct vfsops coda_vfsops = { 513 .vfs_mount = coda_mount, 514 .vfs_root = coda_root, 515 .vfs_statfs = coda_nb_statfs, 516 .vfs_sync = coda_sync, 517 .vfs_unmount = coda_unmount, 518}; 519 520VFS_SET(coda_vfsops, coda, VFCF_NETWORK); 521