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