coda_vfsops.c revision 76688
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 76688 2001-05-16 18:04:37Z iedowse $ 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 proc *)); 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, p) 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 proc *p; /* 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, p); 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, p) 237 struct mount *vfsp; 238 int mntflags; 239 struct proc *p; 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 proc *p = curproc; /* XXX - bnoble */ 296 ViceFid VFid; 297 298 ENTRY; 299 MARK_ENTRY(CODA_ROOT_STATS); 300 result = NULL; 301 302 if (vfsp == mi->mi_vfsp) { 303 if ((VTOC(mi->mi_rootvp)->c_fid.Volume != 0) || 304 (VTOC(mi->mi_rootvp)->c_fid.Vnode != 0) || 305 (VTOC(mi->mi_rootvp)->c_fid.Unique != 0)) 306 { /* Found valid root. */ 307 *vpp = mi->mi_rootvp; 308 /* On Mach, this is vref. On NetBSD, VOP_LOCK */ 309#if 1 310 vref(*vpp); 311 vn_lock(*vpp, LK_EXCLUSIVE, p); 312#else 313 vget(*vpp, LK_EXCLUSIVE, p); 314#endif 315 MARK_INT_SAT(CODA_ROOT_STATS); 316 return(0); 317 } 318 } 319 320 error = venus_root(vftomi(vfsp), p->p_ucred, p, &VFid); 321 322 if (!error) { 323 /* 324 * Save the new rootfid in the cnode, and rehash the cnode into the 325 * cnode hash with the new fid key. 326 */ 327 coda_unsave(VTOC(mi->mi_rootvp)); 328 VTOC(mi->mi_rootvp)->c_fid = VFid; 329 coda_save(VTOC(mi->mi_rootvp)); 330 331 *vpp = mi->mi_rootvp; 332#if 1 333 vref(*vpp); 334 vn_lock(*vpp, LK_EXCLUSIVE, p); 335#else 336 vget(*vpp, LK_EXCLUSIVE, p); 337#endif 338 339 MARK_INT_SAT(CODA_ROOT_STATS); 340 goto exit; 341 } else if (error == ENODEV || error == EINTR) { 342 /* Gross hack here! */ 343 /* 344 * If Venus fails to respond to the CODA_ROOT call, coda_call returns 345 * ENODEV. Return the uninitialized root vnode to allow vfs 346 * operations such as unmount to continue. Without this hack, 347 * there is no way to do an unmount if Venus dies before a 348 * successful CODA_ROOT call is done. All vnode operations 349 * will fail. 350 */ 351 *vpp = mi->mi_rootvp; 352#if 1 353 vref(*vpp); 354 vn_lock(*vpp, LK_EXCLUSIVE, p); 355#else 356 vget(*vpp, LK_EXCLUSIVE, p); 357#endif 358 359 MARK_INT_FAIL(CODA_ROOT_STATS); 360 error = 0; 361 goto exit; 362 } else { 363 CODADEBUG( CODA_ROOT, myprintf(("error %d in CODA_ROOT\n", error)); ); 364 MARK_INT_FAIL(CODA_ROOT_STATS); 365 366 goto exit; 367 } 368 369 exit: 370 return(error); 371} 372 373/* 374 * Get file system statistics. 375 */ 376int 377coda_nb_statfs(vfsp, sbp, p) 378 register struct mount *vfsp; 379 struct statfs *sbp; 380 struct proc *p; 381{ 382 ENTRY; 383/* MARK_ENTRY(CODA_STATFS_STATS); */ 384 if (!CODA_MOUNTED(vfsp)) { 385/* MARK_INT_FAIL(CODA_STATFS_STATS);*/ 386 return(EINVAL); 387 } 388 389 bzero(sbp, sizeof(struct statfs)); 390 /* XXX - what to do about f_flags, others? --bnoble */ 391 /* Below This is what AFS does 392 #define NB_SFS_SIZ 0x895440 393 */ 394 /* Note: Normal fs's have a bsize of 0x400 == 1024 */ 395 sbp->f_type = vfsp->mnt_vfc->vfc_typenum; 396 sbp->f_bsize = 8192; /* XXX */ 397 sbp->f_iosize = 8192; /* XXX */ 398#define NB_SFS_SIZ 0x8AB75D 399 sbp->f_blocks = NB_SFS_SIZ; 400 sbp->f_bfree = NB_SFS_SIZ; 401 sbp->f_bavail = NB_SFS_SIZ; 402 sbp->f_files = NB_SFS_SIZ; 403 sbp->f_ffree = NB_SFS_SIZ; 404 bcopy((caddr_t)&(vfsp->mnt_stat.f_fsid), (caddr_t)&(sbp->f_fsid), sizeof (fsid_t)); 405 snprintf(sbp->f_mntonname, sizeof(sbp->f_mntonname), "/coda"); 406 snprintf(sbp->f_mntfromname, sizeof(sbp->f_mntfromname), "CODA"); 407/* MARK_INT_SAT(CODA_STATFS_STATS); */ 408 return(0); 409} 410 411/* 412 * Flush any pending I/O. 413 */ 414int 415coda_sync(vfsp, waitfor, cred, p) 416 struct mount *vfsp; 417 int waitfor; 418 struct ucred *cred; 419 struct proc *p; 420{ 421 ENTRY; 422 MARK_ENTRY(CODA_SYNC_STATS); 423 MARK_INT_SAT(CODA_SYNC_STATS); 424 return(0); 425} 426 427/* 428 * fhtovp is now what vget used to be in 4.3-derived systems. For 429 * some silly reason, vget is now keyed by a 32 bit ino_t, rather than 430 * a type-specific fid. 431 */ 432int 433coda_fhtovp(vfsp, fhp, nam, vpp, exflagsp, creadanonp) 434 register struct mount *vfsp; 435 struct fid *fhp; 436 struct mbuf *nam; 437 struct vnode **vpp; 438 int *exflagsp; 439 struct ucred **creadanonp; 440{ 441 struct cfid *cfid = (struct cfid *)fhp; 442 struct cnode *cp = 0; 443 int error; 444 struct proc *p = curproc; /* XXX -mach */ 445 ViceFid VFid; 446 int vtype; 447 448 ENTRY; 449 450 MARK_ENTRY(CODA_VGET_STATS); 451 /* Check for vget of control object. */ 452 if (IS_CTL_FID(&cfid->cfid_fid)) { 453 *vpp = coda_ctlvp; 454 vref(coda_ctlvp); 455 MARK_INT_SAT(CODA_VGET_STATS); 456 return(0); 457 } 458 459 error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, p->p_ucred, p, &VFid, &vtype); 460 461 if (error) { 462 CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error));) 463 *vpp = (struct vnode *)0; 464 } else { 465 CODADEBUG(CODA_VGET, 466 myprintf(("vget: vol %lx vno %lx uni %lx type %d result %d\n", 467 VFid.Volume, VFid.Vnode, VFid.Unique, vtype, error)); ) 468 469 cp = make_coda_node(&VFid, vfsp, vtype); 470 *vpp = CTOV(cp); 471 } 472 return(error); 473} 474 475/* 476 * To allow for greater ease of use, some vnodes may be orphaned when 477 * Venus dies. Certain operations should still be allowed to go 478 * through, but without propagating ophan-ness. So this function will 479 * get a new vnode for the file from the current run of Venus. */ 480 481int 482getNewVnode(vpp) 483 struct vnode **vpp; 484{ 485 struct cfid cfid; 486 struct coda_mntinfo *mi = vftomi((*vpp)->v_mount); 487 488 ENTRY; 489 490 cfid.cfid_len = (short)sizeof(ViceFid); 491 cfid.cfid_fid = VTOC(*vpp)->c_fid; /* Structure assignment. */ 492 /* XXX ? */ 493 494 /* We're guessing that if set, the 1st element on the list is a 495 * valid vnode to use. If not, return ENODEV as venus is dead. 496 */ 497 if (mi->mi_vfsp == NULL) 498 return ENODEV; 499 500 return coda_fhtovp(mi->mi_vfsp, (struct fid*)&cfid, NULL, vpp, 501 NULL, NULL); 502} 503 504#include <ufs/ufs/extattr.h> 505#include <ufs/ufs/quota.h> 506#include <ufs/ufs/ufsmount.h> 507/* get the mount structure corresponding to a given device. Assume 508 * device corresponds to a UFS. Return NULL if no device is found. 509 */ 510struct mount *devtomp(dev) 511 dev_t dev; 512{ 513 struct mount *mp; 514 515 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 516 if (((VFSTOUFS(mp))->um_dev == dev)) { 517 /* mount corresponds to UFS and the device matches one we want */ 518 return(mp); 519 } 520 } 521 /* mount structure wasn't found */ 522 return(NULL); 523} 524 525struct vfsops coda_vfsops = { 526 coda_mount, 527 vfs_stdstart, 528 coda_unmount, 529 coda_root, 530 vfs_stdquotactl, 531 coda_nb_statfs, 532 coda_sync, 533 vfs_stdvget, 534 vfs_stdfhtovp, 535 vfs_stdcheckexp, 536 vfs_stdvptofh, 537 vfs_stdinit, 538 vfs_stduninit, 539 vfs_stdextattrctl, 540}; 541 542VFS_SET(coda_vfsops, coda, VFCF_NETWORK); 543