1139745Simp/*- 238759Srvb * Coda: an Experimental Distributed File System 338759Srvb * Release 3.1 4176139Srwatson * 538759Srvb * Copyright (c) 1987-1998 Carnegie Mellon University 638759Srvb * All Rights Reserved 7176139Srwatson * 838759Srvb * Permission to use, copy, modify and distribute this software and its 938759Srvb * documentation is hereby granted, provided that both the copyright 1038759Srvb * notice and this permission notice appear in all copies of the 1138759Srvb * software, derivative works or modified versions, and any portions 1238759Srvb * thereof, and that both notices appear in supporting documentation, and 1338759Srvb * that credit is given to Carnegie Mellon University in all documents 1438759Srvb * and publicity pertaining to direct or indirect use of this code or its 1538759Srvb * derivatives. 16176139Srwatson * 1738759Srvb * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, 1838759Srvb * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS 1938759Srvb * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON 2038759Srvb * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 2138759Srvb * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF 2238759Srvb * ANY DERIVATIVE WORK. 23176139Srwatson * 2438759Srvb * Carnegie Mellon encourages users of this software to return any 2538759Srvb * improvements or extensions that they make, and to grant Carnegie 2638759Srvb * Mellon the rights to redistribute these changes without encumbrance. 27176139Srwatson * 2839085Srvb * @(#) src/sys/cfs/coda_vfsops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $ 2938759Srvb */ 30176139Srwatson 31139745Simp/*- 3238625Srvb * Mach Operating System 3338625Srvb * Copyright (c) 1989 Carnegie-Mellon University 3438625Srvb * All rights reserved. The CMU software License Agreement specifies 3538625Srvb * the terms and conditions for use and redistribution. 3638625Srvb */ 3738625Srvb 3838625Srvb/* 3996755Strhodes * This code was written for the Coda filesystem at Carnegie Mellon 4038625Srvb * University. Contributers include David Steere, James Kistler, and 41176139Srwatson * M. Satyanarayanan. 4238625Srvb */ 4338625Srvb 44116173Sobrien#include <sys/cdefs.h> 45116173Sobrien__FBSDID("$FreeBSD$"); 46116173Sobrien 4738625Srvb#include <sys/param.h> 4838625Srvb#include <sys/systm.h> 4976166Smarkm#include <sys/conf.h> 50177785Skib#include <sys/fcntl.h> 5138759Srvb#include <sys/kernel.h> 5276166Smarkm#include <sys/lock.h> 5338625Srvb#include <sys/malloc.h> 5476166Smarkm#include <sys/mount.h> 5538625Srvb#include <sys/namei.h> 5676166Smarkm#include <sys/proc.h> 5738625Srvb 58171416Srwatson#include <fs/coda/coda.h> 59171416Srwatson#include <fs/coda/cnode.h> 60171416Srwatson#include <fs/coda/coda_vfsops.h> 61171416Srwatson#include <fs/coda/coda_venus.h> 62171416Srwatson#include <fs/coda/coda_subr.h> 63171416Srwatson#include <fs/coda/coda_opstats.h> 6438759Srvb 65151897SrwatsonMALLOC_DEFINE(M_CODA, "coda", "Various Coda Structures"); 6638625Srvb 6739085Srvbint codadebug = 0; 6839085Srvbint coda_vfsop_print_entry = 0; 69176139Srwatson#define ENTRY do { \ 70176139Srwatson if (coda_vfsop_print_entry) \ 71176139Srwatson myprintf(("Entered %s\n", __func__)); \ 72176139Srwatson} while (0) 7338625Srvb 7439085Srvbstruct vnode *coda_ctlvp; 7538625Srvb 76176139Srwatson/* 77176139Srwatson * Structure to keep statistics of internally generated/satisfied calls. 78176139Srwatson */ 79176139Srwatsonstatic struct coda_op_stats coda_vfsopstats[CODA_VFSOPS_SIZE]; 8038625Srvb 81176139Srwatson#define MARK_ENTRY(op) (coda_vfsopstats[op].entries++) 82176139Srwatson#define MARK_INT_SAT(op) (coda_vfsopstats[op].sat_intrn++) 83176139Srwatson#define MARK_INT_FAIL(op) (coda_vfsopstats[op].unsat_intrn++) 84176139Srwatson#define MARK_INT_GEN(op) (coda_vfsopstats[op].gen_intrn++) 8538625Srvb 8638625Srvbint 8739085Srvbcoda_vfsopstats_init(void) 8838625Srvb{ 89176139Srwatson int i; 90176139Srwatson 91176139Srwatson for (i=0; i<CODA_VFSOPS_SIZE;i++) { 9239085Srvb coda_vfsopstats[i].opcode = i; 9339085Srvb coda_vfsopstats[i].entries = 0; 9439085Srvb coda_vfsopstats[i].sat_intrn = 0; 9539085Srvb coda_vfsopstats[i].unsat_intrn = 0; 9639085Srvb coda_vfsopstats[i].gen_intrn = 0; 9738625Srvb } 98176139Srwatson return (0); 9938625Srvb} 10038625Srvb 101138478Sphkstatic const char *coda_opts[] = { "from", NULL }; 10238625Srvb/* 10338625Srvb * cfs mount vfsop 104176139Srwatson * 10538625Srvb * Set up mount info record and attach it to vfs struct. 10638625Srvb */ 10738625Srvb/*ARGSUSED*/ 10838625Srvbint 109191990Sattiliocoda_mount(struct mount *vfsp) 11038625Srvb{ 111176139Srwatson struct vnode *dvp; 112176139Srwatson struct cnode *cp; 113176139Srwatson struct cdev *dev; 114176139Srwatson struct coda_mntinfo *mi; 115176139Srwatson struct vnode *rootvp; 116206210Srwatson struct CodaFid rootfid = INVAL_FID; 117206210Srwatson struct CodaFid ctlfid = CTL_FID; 118176139Srwatson int error; 119176139Srwatson struct nameidata ndp; 120176139Srwatson ENTRY; 121176139Srwatson char *from; 12238625Srvb 123176139Srwatson if (vfs_filteropt(vfsp->mnt_optnew, coda_opts)) 124176139Srwatson return (EINVAL); 125176139Srwatson from = vfs_getopts(vfsp->mnt_optnew, "from", &error); 126176139Srwatson if (error) 127176139Srwatson return (error); 128176139Srwatson coda_vfsopstats_init(); 129176139Srwatson coda_vnodeopstats_init(); 130176139Srwatson MARK_ENTRY(CODA_MOUNT_STATS); 131176139Srwatson if (CODA_MOUNTED(vfsp)) { 132176139Srwatson MARK_INT_FAIL(CODA_MOUNT_STATS); 133176139Srwatson return (EBUSY); 134176139Srwatson } 135138478Sphk 136176139Srwatson /* 137176139Srwatson * Validate mount device. Similar to getmdev(). 138176139Srwatson */ 139191990Sattilio NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, curthread); 140176139Srwatson error = namei(&ndp); 141176139Srwatson dvp = ndp.ni_vp; 142176139Srwatson if (error) { 143176139Srwatson MARK_INT_FAIL(CODA_MOUNT_STATS); 144176139Srwatson return (error); 145176139Srwatson } 146176139Srwatson if (dvp->v_type != VCHR) { 147176139Srwatson MARK_INT_FAIL(CODA_MOUNT_STATS); 148176139Srwatson vrele(dvp); 149176139Srwatson NDFREE(&ndp, NDF_ONLY_PNBUF); 150176139Srwatson return (ENXIO); 151176139Srwatson } 152176139Srwatson dev = dvp->v_rdev; 15338625Srvb vrele(dvp); 154132902Sphk NDFREE(&ndp, NDF_ONLY_PNBUF); 15538625Srvb 156176139Srwatson /* 157176139Srwatson * Initialize the mount record and link it to the vfs struct. 158176139Srwatson */ 159176139Srwatson mi = dev2coda_mntinfo(dev); 160176139Srwatson if (!mi) { 161176139Srwatson MARK_INT_FAIL(CODA_MOUNT_STATS); 162176139Srwatson printf("Coda mount: %s is not a cfs device\n", from); 163176139Srwatson return (ENXIO); 164176139Srwatson } 165176139Srwatson if (!VC_OPEN(&mi->mi_vcomm)) { 166176139Srwatson MARK_INT_FAIL(CODA_MOUNT_STATS); 167176139Srwatson return (ENODEV); 168176139Srwatson } 16938625Srvb 170176139Srwatson /* 171176139Srwatson * No initialization (here) of mi_vcomm! 172176139Srwatson */ 173176139Srwatson vfsp->mnt_data = mi; 174176139Srwatson vfs_getnewfsid (vfsp); 175176139Srwatson mi->mi_vfsp = vfsp; 176176139Srwatson mi->mi_started = 0; /* XXX See coda_root() */ 17738625Srvb 178176139Srwatson /* 179176139Srwatson * Make a root vnode to placate the Vnode interface, but don't 180176139Srwatson * actually make the CODA_ROOT call to venus until the first call to 181176139Srwatson * coda_root in case a server is down while venus is starting. 182176139Srwatson */ 183176139Srwatson cp = make_coda_node(&rootfid, vfsp, VDIR); 184176139Srwatson rootvp = CTOV(cp); 185176139Srwatson rootvp->v_vflag |= VV_ROOT; 186176139Srwatson cp = make_coda_node(&ctlfid, vfsp, VREG); 187176139Srwatson coda_ctlvp = CTOV(cp); 188176139Srwatson 189176139Srwatson /* 190176139Srwatson * Add vfs and rootvp to chain of vfs hanging off mntinfo. 191176139Srwatson */ 192176139Srwatson mi->mi_vfsp = vfsp; 193176139Srwatson mi->mi_rootvp = rootvp; 194176139Srwatson vfs_mountedfrom(vfsp, from); 195176139Srwatson 196176139Srwatson /* 197176139Srwatson * Error is currently guaranteed to be zero, but in case some code 198176139Srwatson * changes... 199176139Srwatson */ 200176139Srwatson CODADEBUG(1, myprintf(("coda_mount returned %d\n", error));); 201176139Srwatson if (error) 202176139Srwatson MARK_INT_FAIL(CODA_MOUNT_STATS); 203176139Srwatson else 204176139Srwatson MARK_INT_SAT(CODA_MOUNT_STATS); 205176139Srwatson return (error); 20638625Srvb} 20738625Srvb 20838625Srvbint 209191990Sattiliocoda_unmount(struct mount *vfsp, int mntflags) 21038625Srvb{ 211176139Srwatson struct coda_mntinfo *mi = vftomi(vfsp); 212176139Srwatson int active, error = 0; 21338625Srvb 214176139Srwatson ENTRY; 215176139Srwatson MARK_ENTRY(CODA_UMOUNT_STATS); 216176139Srwatson if (!CODA_MOUNTED(vfsp)) { 217176139Srwatson MARK_INT_FAIL(CODA_UMOUNT_STATS); 218176139Srwatson return (EINVAL); 219176139Srwatson } 220176139Srwatson if (mi->mi_vfsp == vfsp) { 221176139Srwatson /* 222176139Srwatson * We found the victim. 223176139Srwatson */ 224176139Srwatson if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp))) 225176139Srwatson return (EBUSY); /* Venus is still running */ 226176139Srwatson#ifdef DEBUG 227176139Srwatson printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp, 228176139Srwatson VTOC(mi->mi_rootvp)); 22938625Srvb#endif 230176139Srwatson vrele(mi->mi_rootvp); 231176139Srwatson mi->mi_rootvp = NULL; 232176139Srwatson vrele(coda_ctlvp); 233176139Srwatson coda_ctlvp = NULL; 234176139Srwatson active = coda_kill(vfsp, NOT_DOWNCALL); 235191990Sattilio error = vflush(mi->mi_vfsp, 0, FORCECLOSE, curthread); 236120011Stjr#ifdef CODA_VERBOSE 237176139Srwatson printf("coda_unmount: active = %d, vflush active %d\n", 238176139Srwatson active, error); 239120011Stjr#endif 240176139Srwatson error = 0; 241176139Srwatson /* 242176139Srwatson * I'm going to take this out to allow lookups to go through. 243176139Srwatson * I'm not sure it's important anyway. -- DCS 2/2/94 244176139Srwatson */ 245176139Srwatson /* vfsp->VFS_DATA = NULL; */ 24638625Srvb 247176139Srwatson /* 248176139Srwatson * No more vfsp's to hold onto. 249176139Srwatson */ 250176139Srwatson mi->mi_vfsp = NULL; 25138625Srvb 252176139Srwatson if (error) 253176139Srwatson MARK_INT_FAIL(CODA_UMOUNT_STATS); 254176139Srwatson else 255176139Srwatson MARK_INT_SAT(CODA_UMOUNT_STATS); 256176139Srwatson return (error); 257176139Srwatson } 258176139Srwatson return (EINVAL); 25938625Srvb} 26038625Srvb 26138625Srvb/* 262176139Srwatson * Find root of cfs. 26338625Srvb */ 26438625Srvbint 265191990Sattiliocoda_root(struct mount *vfsp, int flags, struct vnode **vpp) 26638625Srvb{ 267176139Srwatson struct coda_mntinfo *mi = vftomi(vfsp); 268176139Srwatson int error; 269191990Sattilio struct proc *p; 270191990Sattilio struct thread *td; 271206210Srwatson struct CodaFid VFid; 272206210Srwatson static const struct CodaFid invalfid = INVAL_FID; 273176139Srwatson 274191990Sattilio td = curthread; 275191990Sattilio p = td->td_proc; 276176139Srwatson ENTRY; 277176139Srwatson MARK_ENTRY(CODA_ROOT_STATS); 278176139Srwatson if (vfsp == mi->mi_vfsp) { 279176139Srwatson /* 280176139Srwatson * Cache the root across calls. We only need to pass the 281176139Srwatson * request on to Venus if the root vnode is the dummy we 282176139Srwatson * installed in coda_mount() with all c_fid members zeroed. 283176139Srwatson * 284176139Srwatson * XXX In addition, we assume that the first call to 285176139Srwatson * coda_root() is from vfs_mount() (before the call to 286176139Srwatson * checkdirs()) and return the dummy root node to avoid a 287176139Srwatson * deadlock. This bug is fixed in the Coda CVS repository 288176139Srwatson * but not in any released versions as of 6 Mar 2003. 289176139Srwatson */ 290176139Srwatson if (memcmp(&VTOC(mi->mi_rootvp)->c_fid, &invalfid, 291206210Srwatson sizeof(struct CodaFid)) != 0 || mi->mi_started == 0) { 292176139Srwatson /* 293176139Srwatson * Found valid root. 294176139Srwatson */ 295176139Srwatson *vpp = mi->mi_rootvp; 296176139Srwatson mi->mi_started = 1; 297176139Srwatson 298176139Srwatson /* 299176139Srwatson * On Mach, this is vref. On FreeBSD, vref + 300176139Srwatson * vn_lock. 301176139Srwatson */ 302176139Srwatson vref(*vpp); 303176139Srwatson vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 304176139Srwatson MARK_INT_SAT(CODA_ROOT_STATS); 305176139Srwatson return (0); 306176139Srwatson } 307176139Srwatson } 308176139Srwatson 309176139Srwatson error = venus_root(vftomi(vfsp), td->td_ucred, p, &VFid); 310176139Srwatson if (!error) { 311176139Srwatson /* 312176139Srwatson * Save the new rootfid in the cnode, and rehash the cnode 313176139Srwatson * into the cnode hash with the new fid key. 314176139Srwatson */ 315176139Srwatson coda_unsave(VTOC(mi->mi_rootvp)); 316176139Srwatson VTOC(mi->mi_rootvp)->c_fid = VFid; 317176139Srwatson coda_save(VTOC(mi->mi_rootvp)); 31838625Srvb *vpp = mi->mi_rootvp; 31938625Srvb vref(*vpp); 320176121Srwatson vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 32139085Srvb MARK_INT_SAT(CODA_ROOT_STATS); 322176139Srwatson } else if (error == ENODEV || error == EINTR) { 323176139Srwatson /* 324176139Srwatson * Gross hack here! 325176139Srwatson * 326176139Srwatson * If Venus fails to respond to the CODA_ROOT call, coda_call 327176139Srwatson * returns ENODEV. Return the uninitialized root vnode to 328176139Srwatson * allow vfs operations such as unmount to continue. Without 329176139Srwatson * this hack, there is no way to do an unmount if Venus dies 330176139Srwatson * before a successful CODA_ROOT call is done. All vnode 331176139Srwatson * operations will fail. 332176139Srwatson */ 333176139Srwatson *vpp = mi->mi_rootvp; 334176139Srwatson vref(*vpp); 335176139Srwatson vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 336176139Srwatson MARK_INT_FAIL(CODA_ROOT_STATS); 337176139Srwatson error = 0; 338176139Srwatson } else { 339176139Srwatson CODADEBUG(CODA_ROOT, myprintf(("error %d in CODA_ROOT\n", 340176139Srwatson error));); 341176139Srwatson MARK_INT_FAIL(CODA_ROOT_STATS); 342176139Srwatson } 343176139Srwatson return (error); 34438625Srvb} 34538625Srvb 34638625Srvb/* 34796755Strhodes * Get filesystem statistics. 34838625Srvb */ 34938625Srvbint 350191990Sattiliocoda_statfs(struct mount *vfsp, struct statfs *sbp) 35138625Srvb{ 352176139Srwatson 353176139Srwatson ENTRY; 354176139Srwatson MARK_ENTRY(CODA_STATFS_STATS); 355176139Srwatson if (!CODA_MOUNTED(vfsp)) { 356176139Srwatson MARK_INT_FAIL(CODA_STATFS_STATS); 357176139Srwatson return (EINVAL); 358176139Srwatson } 359176139Srwatson 360176139Srwatson /* 361176139Srwatson * XXX - what to do about f_flags, others? --bnoble 362176139Srwatson * 363176139Srwatson * We just make up free space counts that are sufficiently large. 364176139Srwatson */ 365176139Srwatson sbp->f_flags = 0; 366176139Srwatson sbp->f_bsize = 8192; /* XXX */ 367176139Srwatson sbp->f_iosize = 8192; /* XXX */ 368176139Srwatson#define CODA_SFS_SIZ 0x8AB75D 369176139Srwatson sbp->f_blocks = CODA_SFS_SIZ; 370176139Srwatson sbp->f_bfree = CODA_SFS_SIZ; 371176139Srwatson sbp->f_bavail = CODA_SFS_SIZ; 372176139Srwatson sbp->f_files = CODA_SFS_SIZ; 373176139Srwatson sbp->f_ffree = CODA_SFS_SIZ; 374176139Srwatson MARK_INT_SAT(CODA_STATFS_STATS); 375176139Srwatson return (0); 37638625Srvb} 37738625Srvb 37838625Srvb/* 37938625Srvb * Flush any pending I/O. 38038625Srvb */ 38138625Srvbint 382191990Sattiliocoda_sync(struct mount *vfsp, int waitfor) 38338625Srvb{ 384176139Srwatson 385176139Srwatson ENTRY; 386176139Srwatson MARK_ENTRY(CODA_SYNC_STATS); 387176139Srwatson MARK_INT_SAT(CODA_SYNC_STATS); 388176139Srwatson return (0); 38938625Srvb} 39038625Srvb 391176139Srwatson/* 392176139Srwatson * fhtovp is now what vget used to be in 4.3-derived systems. For some silly 393176139Srwatson * reason, vget is now keyed by a 32 bit ino_t, rather than a type-specific 394176139Srwatson * fid. 395176131Srwatson * 396176131Srwatson * XXX: coda_fhtovp is currently not hooked up, so no NFS export for Coda. 397176131Srwatson * We leave it here in the hopes that someone will find it someday and hook 398176131Srwatson * it up. Among other things, it will need some reworking to match the 399176131Srwatson * vfs_fhtovp_t prototype. 40038625Srvb */ 40138625Srvbint 402176139Srwatsoncoda_fhtovp(struct mount *vfsp, struct fid *fhp, struct mbuf *nam, 403176139Srwatson struct vnode **vpp, int *exflagsp, struct ucred **creadanonp) 40438625Srvb{ 405176139Srwatson struct cfid *cfid = (struct cfid *)fhp; 406176139Srwatson struct cnode *cp = NULL; 407176139Srwatson int error; 408176139Srwatson struct thread *td = curthread; /* XXX -mach */ 409176139Srwatson struct proc *p = td->td_proc; 410206210Srwatson struct CodaFid VFid; 411176139Srwatson int vtype; 41238625Srvb 413176139Srwatson ENTRY; 414176139Srwatson MARK_ENTRY(CODA_VGET_STATS); 415176139Srwatson 416176139Srwatson /* 417176139Srwatson * Check for vget of control object. 418176139Srwatson */ 419176139Srwatson if (IS_CTL_FID(&cfid->cfid_fid)) { 420176139Srwatson *vpp = coda_ctlvp; 421176139Srwatson vref(coda_ctlvp); 422176139Srwatson MARK_INT_SAT(CODA_VGET_STATS); 423176139Srwatson return (0); 424176139Srwatson } 425176139Srwatson error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, td->td_ucred, p, 426176139Srwatson &VFid, &vtype); 427176139Srwatson if (error) { 428176139Srwatson CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error));); 429176139Srwatson *vpp = NULL; 430176139Srwatson } else { 431176139Srwatson CODADEBUG(CODA_VGET, myprintf(("vget: %s type %d result " 432176139Srwatson "%d\n", coda_f2s(&VFid), vtype, error));); 433176139Srwatson cp = make_coda_node(&VFid, vfsp, vtype); 434176139Srwatson *vpp = CTOV(cp); 435176139Srwatson } 436176139Srwatson return (error); 43738625Srvb} 43838625Srvb 43939650Srvbstruct vfsops coda_vfsops = { 440176139Srwatson .vfs_mount = coda_mount, 441176139Srwatson .vfs_root = coda_root, 442176139Srwatson .vfs_statfs = coda_statfs, 443176139Srwatson .vfs_sync = coda_sync, 444176139Srwatson .vfs_unmount = coda_unmount, 44539650Srvb}; 44639650SrvbVFS_SET(coda_vfsops, coda, VFCF_NETWORK); 447