coda_vfsops.c revision 176139
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/*- 32 * Mach Operating System 33 * Copyright (c) 1989 Carnegie-Mellon University 34 * All rights reserved. The CMU software License Agreement specifies 35 * the terms and conditions for use and redistribution. 36 */ 37 38/* 39 * This code was written for the Coda filesystem at Carnegie Mellon 40 * University. Contributers include David Steere, James Kistler, and 41 * M. Satyanarayanan. 42 */ 43 44#include <sys/cdefs.h> 45__FBSDID("$FreeBSD: head/sys/fs/coda/coda_vfsops.c 176139 2008-02-10 11:18:12Z rwatson $"); 46 47#include <sys/param.h> 48#include <sys/systm.h> 49#include <sys/conf.h> 50#include <sys/kernel.h> 51#include <sys/lock.h> 52#include <sys/malloc.h> 53#include <sys/mount.h> 54#include <sys/namei.h> 55#include <sys/proc.h> 56 57#include <fs/coda/coda.h> 58#include <fs/coda/cnode.h> 59#include <fs/coda/coda_vfsops.h> 60#include <fs/coda/coda_venus.h> 61#include <fs/coda/coda_subr.h> 62#include <fs/coda/coda_opstats.h> 63 64MALLOC_DEFINE(M_CODA, "coda", "Various Coda Structures"); 65 66int codadebug = 0; 67int coda_vfsop_print_entry = 0; 68#define ENTRY do { \ 69 if (coda_vfsop_print_entry) \ 70 myprintf(("Entered %s\n", __func__)); \ 71} while (0) 72 73struct vnode *coda_ctlvp; 74 75/* 76 * Structure to keep statistics of internally generated/satisfied calls. 77 */ 78static struct 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 MARK_INT_GEN(op) (coda_vfsopstats[op].gen_intrn++) 84 85int 86coda_vfsopstats_init(void) 87{ 88 int i; 89 90 for (i=0; i<CODA_VFSOPS_SIZE;i++) { 91 coda_vfsopstats[i].opcode = i; 92 coda_vfsopstats[i].entries = 0; 93 coda_vfsopstats[i].sat_intrn = 0; 94 coda_vfsopstats[i].unsat_intrn = 0; 95 coda_vfsopstats[i].gen_intrn = 0; 96 } 97 return (0); 98} 99 100static const char *coda_opts[] = { "from", NULL }; 101/* 102 * cfs mount vfsop 103 * 104 * Set up mount info record and attach it to vfs struct. 105 */ 106/*ARGSUSED*/ 107int 108coda_mount(struct mount *vfsp, struct thread *td) 109{ 110 struct vnode *dvp; 111 struct cnode *cp; 112 struct cdev *dev; 113 struct coda_mntinfo *mi; 114 struct vnode *rootvp; 115 CodaFid rootfid = INVAL_FID; 116 CodaFid ctlfid = CTL_FID; 117 int error; 118 struct nameidata ndp; 119 ENTRY; 120 char *from; 121 122 if (vfs_filteropt(vfsp->mnt_optnew, coda_opts)) 123 return (EINVAL); 124 from = vfs_getopts(vfsp->mnt_optnew, "from", &error); 125 if (error) 126 return (error); 127 coda_vfsopstats_init(); 128 coda_vnodeopstats_init(); 129 MARK_ENTRY(CODA_MOUNT_STATS); 130 if (CODA_MOUNTED(vfsp)) { 131 MARK_INT_FAIL(CODA_MOUNT_STATS); 132 return (EBUSY); 133 } 134 135 /* 136 * Validate mount device. Similar to getmdev(). 137 */ 138 NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, td); 139 error = namei(&ndp); 140 dvp = ndp.ni_vp; 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 if (!VC_OPEN(&mi->mi_vcomm)) { 165 MARK_INT_FAIL(CODA_MOUNT_STATS); 166 return (ENODEV); 167 } 168 169 /* 170 * No initialization (here) of mi_vcomm! 171 */ 172 vfsp->mnt_data = mi; 173 vfs_getnewfsid (vfsp); 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 to 180 * 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 cp = make_coda_node(&ctlfid, vfsp, VREG); 186 coda_ctlvp = CTOV(cp); 187 188 /* 189 * Add vfs and rootvp to chain of vfs hanging off mntinfo. 190 */ 191 mi->mi_vfsp = vfsp; 192 mi->mi_rootvp = rootvp; 193 vfs_mountedfrom(vfsp, from); 194 195 /* 196 * Error is currently guaranteed to be zero, but in case some code 197 * changes... 198 */ 199 CODADEBUG(1, myprintf(("coda_mount returned %d\n", error));); 200 if (error) 201 MARK_INT_FAIL(CODA_MOUNT_STATS); 202 else 203 MARK_INT_SAT(CODA_MOUNT_STATS); 204 return (error); 205} 206 207int 208coda_unmount(struct mount *vfsp, int mntflags, struct thread *td) 209{ 210 struct coda_mntinfo *mi = vftomi(vfsp); 211 int active, error = 0; 212 213 ENTRY; 214 MARK_ENTRY(CODA_UMOUNT_STATS); 215 if (!CODA_MOUNTED(vfsp)) { 216 MARK_INT_FAIL(CODA_UMOUNT_STATS); 217 return (EINVAL); 218 } 219 if (mi->mi_vfsp == vfsp) { 220 /* 221 * We found the victim. 222 */ 223 if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp))) 224 return (EBUSY); /* Venus is still running */ 225#ifdef DEBUG 226 printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp, 227 VTOC(mi->mi_rootvp)); 228#endif 229 vrele(mi->mi_rootvp); 230 mi->mi_rootvp = NULL; 231 vrele(coda_ctlvp); 232 coda_ctlvp = NULL; 233 active = coda_kill(vfsp, NOT_DOWNCALL); 234 error = vflush(mi->mi_vfsp, 0, FORCECLOSE, td); 235#ifdef CODA_VERBOSE 236 printf("coda_unmount: active = %d, vflush active %d\n", 237 active, error); 238#endif 239 error = 0; 240 /* 241 * I'm going to take this out to allow lookups to go through. 242 * I'm not sure it's important anyway. -- DCS 2/2/94 243 */ 244 /* vfsp->VFS_DATA = NULL; */ 245 246 /* 247 * No more vfsp's to hold onto. 248 */ 249 mi->mi_vfsp = NULL; 250 251 if (error) 252 MARK_INT_FAIL(CODA_UMOUNT_STATS); 253 else 254 MARK_INT_SAT(CODA_UMOUNT_STATS); 255 return (error); 256 } 257 return (EINVAL); 258} 259 260/* 261 * Find root of cfs. 262 */ 263int 264coda_root(struct mount *vfsp, int flags, 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 if (vfsp == mi->mi_vfsp) { 278 /* 279 * Cache the root across calls. We only need to pass the 280 * request on to Venus if the root vnode is the dummy we 281 * installed in coda_mount() with all c_fid members zeroed. 282 * 283 * XXX In addition, we assume that the first call to 284 * coda_root() is from vfs_mount() (before the call to 285 * checkdirs()) and return the dummy root node to avoid a 286 * deadlock. This bug is fixed in the Coda CVS repository 287 * but not in any released versions as of 6 Mar 2003. 288 */ 289 if (memcmp(&VTOC(mi->mi_rootvp)->c_fid, &invalfid, 290 sizeof(CodaFid)) != 0 || mi->mi_started == 0) { 291 /* 292 * Found valid root. 293 */ 294 *vpp = mi->mi_rootvp; 295 mi->mi_started = 1; 296 297 /* 298 * On Mach, this is vref. On FreeBSD, vref + 299 * vn_lock. 300 */ 301 vref(*vpp); 302 vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 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 if (!error) { 310 /* 311 * Save the new rootfid in the cnode, and rehash the cnode 312 * into the cnode hash with the new fid key. 313 */ 314 coda_unsave(VTOC(mi->mi_rootvp)); 315 VTOC(mi->mi_rootvp)->c_fid = VFid; 316 coda_save(VTOC(mi->mi_rootvp)); 317 *vpp = mi->mi_rootvp; 318 vref(*vpp); 319 vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 320 MARK_INT_SAT(CODA_ROOT_STATS); 321 } else if (error == ENODEV || error == EINTR) { 322 /* 323 * Gross hack here! 324 * 325 * If Venus fails to respond to the CODA_ROOT call, coda_call 326 * returns ENODEV. Return the uninitialized root vnode to 327 * allow vfs operations such as unmount to continue. Without 328 * this hack, there is no way to do an unmount if Venus dies 329 * before a successful CODA_ROOT call is done. All vnode 330 * operations will fail. 331 */ 332 *vpp = mi->mi_rootvp; 333 vref(*vpp); 334 vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY); 335 MARK_INT_FAIL(CODA_ROOT_STATS); 336 error = 0; 337 } else { 338 CODADEBUG(CODA_ROOT, myprintf(("error %d in CODA_ROOT\n", 339 error));); 340 MARK_INT_FAIL(CODA_ROOT_STATS); 341 } 342 return (error); 343} 344 345/* 346 * Get filesystem statistics. 347 */ 348int 349coda_statfs(struct mount *vfsp, struct statfs *sbp, struct thread *td) 350{ 351 352 ENTRY; 353 MARK_ENTRY(CODA_STATFS_STATS); 354 if (!CODA_MOUNTED(vfsp)) { 355 MARK_INT_FAIL(CODA_STATFS_STATS); 356 return (EINVAL); 357 } 358 359 /* 360 * XXX - what to do about f_flags, others? --bnoble 361 * 362 * We just make up free space counts that are sufficiently large. 363 */ 364 sbp->f_flags = 0; 365 sbp->f_bsize = 8192; /* XXX */ 366 sbp->f_iosize = 8192; /* XXX */ 367#define CODA_SFS_SIZ 0x8AB75D 368 sbp->f_blocks = CODA_SFS_SIZ; 369 sbp->f_bfree = CODA_SFS_SIZ; 370 sbp->f_bavail = CODA_SFS_SIZ; 371 sbp->f_files = CODA_SFS_SIZ; 372 sbp->f_ffree = CODA_SFS_SIZ; 373 MARK_INT_SAT(CODA_STATFS_STATS); 374 return (0); 375} 376 377/* 378 * Flush any pending I/O. 379 */ 380int 381coda_sync(struct mount *vfsp, int waitfor, struct thread *td) 382{ 383 384 ENTRY; 385 MARK_ENTRY(CODA_SYNC_STATS); 386 MARK_INT_SAT(CODA_SYNC_STATS); 387 return (0); 388} 389 390/* 391 * fhtovp is now what vget used to be in 4.3-derived systems. For some silly 392 * reason, vget is now keyed by a 32 bit ino_t, rather than a type-specific 393 * fid. 394 * 395 * XXX: coda_fhtovp is currently not hooked up, so no NFS export for Coda. 396 * We leave it here in the hopes that someone will find it someday and hook 397 * it up. Among other things, it will need some reworking to match the 398 * vfs_fhtovp_t prototype. 399 */ 400int 401coda_fhtovp(struct mount *vfsp, struct fid *fhp, struct mbuf *nam, 402 struct vnode **vpp, int *exflagsp, struct ucred **creadanonp) 403{ 404 struct cfid *cfid = (struct cfid *)fhp; 405 struct cnode *cp = NULL; 406 int error; 407 struct thread *td = curthread; /* XXX -mach */ 408 struct proc *p = td->td_proc; 409 CodaFid VFid; 410 int vtype; 411 412 ENTRY; 413 MARK_ENTRY(CODA_VGET_STATS); 414 415 /* 416 * Check for vget of control object. 417 */ 418 if (IS_CTL_FID(&cfid->cfid_fid)) { 419 *vpp = coda_ctlvp; 420 vref(coda_ctlvp); 421 MARK_INT_SAT(CODA_VGET_STATS); 422 return (0); 423 } 424 error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, td->td_ucred, p, 425 &VFid, &vtype); 426 if (error) { 427 CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error));); 428 *vpp = NULL; 429 } else { 430 CODADEBUG(CODA_VGET, myprintf(("vget: %s type %d result " 431 "%d\n", coda_f2s(&VFid), vtype, error));); 432 cp = make_coda_node(&VFid, vfsp, vtype); 433 *vpp = CTOV(cp); 434 } 435 return (error); 436} 437 438struct vfsops coda_vfsops = { 439 .vfs_mount = coda_mount, 440 .vfs_root = coda_root, 441 .vfs_statfs = coda_statfs, 442 .vfs_sync = coda_sync, 443 .vfs_unmount = coda_unmount, 444}; 445VFS_SET(coda_vfsops, coda, VFCF_NETWORK); 446