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