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