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 * Mach Operating System
32 * Copyright (c) 1989 Carnegie-Mellon University
33 * All rights reserved. The CMU software License Agreement specifies
34 * the terms and conditions for use and redistribution.
35 */
36
37 /*
38 * This code was written for the Coda filesystem at Carnegie Mellon
39 * University. Contributers include David Steere, James Kistler, and
40 * M. Satyanarayanan.
41 */
42
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/conf.h>
49 #include <sys/kernel.h>
50 #include <sys/lock.h>
51 #include <sys/malloc.h>
52 #include <sys/mount.h>
53 #include <sys/namei.h>
54 #include <sys/proc.h>
55
56 #include <fs/coda/coda.h>
57 #include <fs/coda/cnode.h>
58 #include <fs/coda/coda_vfsops.h>
59 #include <fs/coda/coda_venus.h>
60 #include <fs/coda/coda_subr.h>
61 #include <fs/coda/coda_opstats.h>
62
63 MALLOC_DEFINE(M_CODA, "coda", "Various Coda Structures");
64
65 int codadebug = 0;
66 int coda_vfsop_print_entry = 0;
67 #define ENTRY if(coda_vfsop_print_entry) myprintf(("Entered %s\n",__func__))
68
69 struct vnode *coda_ctlvp;
70
71 /* structure to keep statistics of internally generated/satisfied calls */
72
73 struct coda_op_stats coda_vfsopstats[CODA_VFSOPS_SIZE];
74
75 #define MARK_ENTRY(op) (coda_vfsopstats[op].entries++)
76 #define MARK_INT_SAT(op) (coda_vfsopstats[op].sat_intrn++)
77 #define MARK_INT_FAIL(op) (coda_vfsopstats[op].unsat_intrn++)
78 #define MARK_INT_GEN(op) (coda_vfsopstats[op].gen_intrn++)
79
80 int
81 coda_vfsopstats_init(void)
82 {
83 register int i;
84
85 for (i=0;i<CODA_VFSOPS_SIZE;i++) {
86 coda_vfsopstats[i].opcode = i;
87 coda_vfsopstats[i].entries = 0;
88 coda_vfsopstats[i].sat_intrn = 0;
89 coda_vfsopstats[i].unsat_intrn = 0;
90 coda_vfsopstats[i].gen_intrn = 0;
91 }
92
93 return 0;
94 }
95
96 static const char *coda_opts[] = { "from", NULL };
97 /*
98 * cfs mount vfsop
99 * Set up mount info record and attach it to vfs struct.
100 */
101 /*ARGSUSED*/
102 int
103 coda_mount(struct mount *vfsp, struct thread *td)
104 {
105 struct vnode *dvp;
106 struct cnode *cp;
107 struct cdev *dev;
108 struct coda_mntinfo *mi;
109 struct vnode *rootvp;
110 CodaFid rootfid = INVAL_FID;
111 CodaFid ctlfid = CTL_FID;
112 int error;
113 struct nameidata ndp;
114 ENTRY;
115 char *from;
116
117 if (vfs_filteropt(vfsp->mnt_optnew, coda_opts))
118 return (EINVAL);
119
120 from = vfs_getopts(vfsp->mnt_optnew, "from", &error);
121 if (error)
122 return (error);
123
124 coda_vfsopstats_init();
125 coda_vnodeopstats_init();
126
127 MARK_ENTRY(CODA_MOUNT_STATS);
128 if (CODA_MOUNTED(vfsp)) {
129 MARK_INT_FAIL(CODA_MOUNT_STATS);
130 return(EBUSY);
131 }
132
133 /* Validate mount device. Similar to getmdev(). */
134 NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, td);
135 error = namei(&ndp);
136 dvp = ndp.ni_vp;
137
138 if (error) {
139 MARK_INT_FAIL(CODA_MOUNT_STATS);
140 return (error);
141 }
142 if (dvp->v_type != VCHR) {
143 MARK_INT_FAIL(CODA_MOUNT_STATS);
144 vrele(dvp);
145 NDFREE(&ndp, NDF_ONLY_PNBUF);
146 return(ENXIO);
147 }
148 dev = dvp->v_rdev;
149 vrele(dvp);
150 NDFREE(&ndp, NDF_ONLY_PNBUF);
151
152 /*
153 * Initialize the mount record and link it to the vfs struct
154 */
155 mi = dev2coda_mntinfo(dev);
156 if (!mi) {
157 MARK_INT_FAIL(CODA_MOUNT_STATS);
158 printf("Coda mount: %s is not a cfs device\n", from);
159 return(ENXIO);
160 }
161
162 if (!VC_OPEN(&mi->mi_vcomm)) {
163 MARK_INT_FAIL(CODA_MOUNT_STATS);
164 return(ENODEV);
165 }
166
167 /* No initialization (here) of mi_vcomm! */
168 vfsp->mnt_data = mi;
169 vfs_getnewfsid (vfsp);
170
171 mi->mi_vfsp = vfsp;
172 mi->mi_started = 0; /* XXX See coda_root() */
173
174 /*
175 * Make a root vnode to placate the Vnode interface, but don't
176 * actually make the CODA_ROOT call to venus until the first call
177 * to coda_root in case a server is down while venus is starting.
178 */
179 cp = make_coda_node(&rootfid, vfsp, VDIR);
180 rootvp = CTOV(cp);
181 rootvp->v_vflag |= VV_ROOT;
182
183 cp = make_coda_node(&ctlfid, vfsp, VREG);
184 coda_ctlvp = CTOV(cp);
185
186 /* Add vfs and rootvp to chain of vfs hanging off mntinfo */
187 mi->mi_vfsp = vfsp;
188 mi->mi_rootvp = rootvp;
189
190 vfs_mountedfrom(vfsp, from);
191 /* error is currently guaranteed to be zero, but in case some
192 code changes... */
193 CODADEBUG(1,
194 myprintf(("coda_omount returned %d\n",error)););
195 if (error)
196 MARK_INT_FAIL(CODA_MOUNT_STATS);
197 else
198 MARK_INT_SAT(CODA_MOUNT_STATS);
199
200 return(error);
201 }
202
203 int
204 coda_unmount(vfsp, mntflags, td)
205 struct mount *vfsp;
206 int mntflags;
207 struct thread *td;
208 {
209 struct coda_mntinfo *mi = vftomi(vfsp);
210 int active, error = 0;
211
212 ENTRY;
213 MARK_ENTRY(CODA_UMOUNT_STATS);
214 if (!CODA_MOUNTED(vfsp)) {
215 MARK_INT_FAIL(CODA_UMOUNT_STATS);
216 return(EINVAL);
217 }
218
219 if (mi->mi_vfsp == vfsp) { /* We found the victim */
220 if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp)))
221 return (EBUSY); /* Venus is still running */
222
223 #ifdef DEBUG
224 printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp, VTOC(mi->mi_rootvp));
225 #endif
226 vrele(mi->mi_rootvp);
227 mi->mi_rootvp = NULL;
228 vrele(coda_ctlvp);
229 coda_ctlvp = NULL;
230 active = coda_kill(vfsp, NOT_DOWNCALL);
231 error = vflush(mi->mi_vfsp, 0, FORCECLOSE, td);
232 #ifdef CODA_VERBOSE
233 printf("coda_unmount: active = %d, vflush active %d\n", active, error);
234 #endif
235 error = 0;
236 /* I'm going to take this out to allow lookups to go through. I'm
237 * not sure it's important anyway. -- DCS 2/2/94
238 */
239 /* vfsp->VFS_DATA = NULL; */
240
241 /* No more vfsp's to hold onto */
242 mi->mi_vfsp = NULL;
243
244 if (error)
245 MARK_INT_FAIL(CODA_UMOUNT_STATS);
246 else
247 MARK_INT_SAT(CODA_UMOUNT_STATS);
248
249 return(error);
250 }
251 return (EINVAL);
252 }
253
254 /*
255 * find root of cfs
256 */
257 int
258 coda_root(vfsp, flags, vpp, td)
259 struct mount *vfsp;
260 int flags;
261 struct vnode **vpp;
262 struct thread *td;
263 {
264 struct coda_mntinfo *mi = vftomi(vfsp);
265 struct vnode **result;
266 int error;
267 struct proc *p = td->td_proc;
268 CodaFid VFid;
269 static const CodaFid invalfid = INVAL_FID;
270
271 ENTRY;
272 MARK_ENTRY(CODA_ROOT_STATS);
273 result = NULL;
274
275 if (vfsp == mi->mi_vfsp) {
276 /*
277 * Cache the root across calls. We only need to pass the request
278 * on to Venus if the root vnode is the dummy we installed in
279 * coda_omount() with all c_fid members zeroed.
280 *
281 * XXX In addition, we assume that the first call to coda_root()
282 * is from vfs_omount()
283 * (before the call to checkdirs()) and return the dummy root
284 * node to avoid a deadlock. This bug is fixed in the Coda CVS
285 * repository but not in any released versions as of 6 Mar 2003.
286 */
287 if (memcmp(&VTOC(mi->mi_rootvp)->c_fid, &invalfid,
288 sizeof(CodaFid)) != 0 || mi->mi_started == 0)
289 { /* Found valid root. */
290 *vpp = mi->mi_rootvp;
291 mi->mi_started = 1;
292
293 /* On Mach, this is vref. On NetBSD, VOP_LOCK */
294 #if 1
295 vref(*vpp);
296 vn_lock(*vpp, LK_EXCLUSIVE, td);
297 #else
298 vget(*vpp, LK_EXCLUSIVE, td);
299 #endif
300 MARK_INT_SAT(CODA_ROOT_STATS);
301 return(0);
302 }
303 }
304
305 error = venus_root(vftomi(vfsp), td->td_ucred, p, &VFid);
306
307 if (!error) {
308 /*
309 * Save the new rootfid in the cnode, and rehash the cnode into the
310 * cnode hash with the new fid key.
311 */
312 coda_unsave(VTOC(mi->mi_rootvp));
313 VTOC(mi->mi_rootvp)->c_fid = VFid;
314 coda_save(VTOC(mi->mi_rootvp));
315
316 *vpp = mi->mi_rootvp;
317 #if 1
318 vref(*vpp);
319 vn_lock(*vpp, LK_EXCLUSIVE, td);
320 #else
321 vget(*vpp, LK_EXCLUSIVE, td);
322 #endif
323
324 MARK_INT_SAT(CODA_ROOT_STATS);
325 goto exit;
326 } else if (error == ENODEV || error == EINTR) {
327 /* Gross hack here! */
328 /*
329 * If Venus fails to respond to the CODA_ROOT call, coda_call returns
330 * ENODEV. Return the uninitialized root vnode to allow vfs
331 * operations such as unmount to continue. Without this hack,
332 * there is no way to do an unmount if Venus dies before a
333 * successful CODA_ROOT call is done. All vnode operations
334 * will fail.
335 */
336 *vpp = mi->mi_rootvp;
337 #if 1
338 vref(*vpp);
339 vn_lock(*vpp, LK_EXCLUSIVE, td);
340 #else
341 vget(*vpp, LK_EXCLUSIVE, td);
342 #endif
343
344 MARK_INT_FAIL(CODA_ROOT_STATS);
345 error = 0;
346 goto exit;
347 } else {
348 CODADEBUG( CODA_ROOT, myprintf(("error %d in CODA_ROOT\n", error)); );
349 MARK_INT_FAIL(CODA_ROOT_STATS);
350
351 goto exit;
352 }
353
354 exit:
355 return(error);
356 }
357
358 /*
359 * Get filesystem statistics.
360 */
361 int
362 coda_nb_statfs(vfsp, sbp, td)
363 register struct mount *vfsp;
364 struct statfs *sbp;
365 struct thread *td;
366 {
367 ENTRY;
368 /* MARK_ENTRY(CODA_STATFS_STATS); */
369 if (!CODA_MOUNTED(vfsp)) {
370 /* MARK_INT_FAIL(CODA_STATFS_STATS);*/
371 return(EINVAL);
372 }
373
374 /* XXX - what to do about f_flags, others? --bnoble */
375 /* Below This is what AFS does
376 #define NB_SFS_SIZ 0x895440
377 */
378 sbp->f_flags = 0;
379 sbp->f_bsize = 8192; /* XXX */
380 sbp->f_iosize = 8192; /* XXX */
381 #define NB_SFS_SIZ 0x8AB75D
382 sbp->f_blocks = NB_SFS_SIZ;
383 sbp->f_bfree = NB_SFS_SIZ;
384 sbp->f_bavail = NB_SFS_SIZ;
385 sbp->f_files = NB_SFS_SIZ;
386 sbp->f_ffree = NB_SFS_SIZ;
387 /* MARK_INT_SAT(CODA_STATFS_STATS); */
388 return(0);
389 }
390
391 /*
392 * Flush any pending I/O.
393 */
394 int
395 coda_sync(vfsp, waitfor, td)
396 struct mount *vfsp;
397 int waitfor;
398 struct thread *td;
399 {
400 ENTRY;
401 MARK_ENTRY(CODA_SYNC_STATS);
402 MARK_INT_SAT(CODA_SYNC_STATS);
403 return(0);
404 }
405
406 /*
407 * fhtovp is now what vget used to be in 4.3-derived systems. For
408 * some silly reason, vget is now keyed by a 32 bit ino_t, rather than
409 * a type-specific fid.
410 */
411 int
412 coda_fhtovp(vfsp, fhp, nam, vpp, exflagsp, creadanonp)
413 register struct mount *vfsp;
414 struct fid *fhp;
415 struct mbuf *nam;
416 struct vnode **vpp;
417 int *exflagsp;
418 struct ucred **creadanonp;
419 {
420 struct cfid *cfid = (struct cfid *)fhp;
421 struct cnode *cp = 0;
422 int error;
423 struct thread *td = curthread; /* XXX -mach */
424 struct proc *p = td->td_proc;
425 CodaFid VFid;
426 int vtype;
427
428 ENTRY;
429
430 MARK_ENTRY(CODA_VGET_STATS);
431 /* Check for vget of control object. */
432 if (IS_CTL_FID(&cfid->cfid_fid)) {
433 *vpp = coda_ctlvp;
434 vref(coda_ctlvp);
435 MARK_INT_SAT(CODA_VGET_STATS);
436 return(0);
437 }
438
439 error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, td->td_ucred, p, &VFid, &vtype);
440
441 if (error) {
442 CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error));)
443 *vpp = (struct vnode *)0;
444 } else {
445 CODADEBUG(CODA_VGET,
446 myprintf(("vget: %s type %d result %d\n",
447 coda_f2s(&VFid), vtype, error)); )
448 cp = make_coda_node(&VFid, vfsp, vtype);
449 *vpp = CTOV(cp);
450 }
451 return(error);
452 }
453
454 /*
455 * To allow for greater ease of use, some vnodes may be orphaned when
456 * Venus dies. Certain operations should still be allowed to go
457 * through, but without propagating ophan-ness. So this function will
458 * get a new vnode for the file from the current run of Venus. */
459
460 int
461 getNewVnode(vpp)
462 struct vnode **vpp;
463 {
464 struct cfid cfid;
465 struct coda_mntinfo *mi = vftomi((*vpp)->v_mount);
466
467 ENTRY;
468
469 cfid.cfid_len = (short)sizeof(CodaFid);
470 cfid.cfid_fid = VTOC(*vpp)->c_fid; /* Structure assignment. */
471 /* XXX ? */
472
473 /* We're guessing that if set, the 1st element on the list is a
474 * valid vnode to use. If not, return ENODEV as venus is dead.
475 */
476 if (mi->mi_vfsp == NULL)
477 return ENODEV;
478
479 return coda_fhtovp(mi->mi_vfsp, (struct fid*)&cfid, NULL, vpp,
480 NULL, NULL);
481 }
482
483 #include <ufs/ufs/extattr.h>
484 #include <ufs/ufs/quota.h>
485 #include <ufs/ufs/ufsmount.h>
486 /* get the mount structure corresponding to a given device. Assume
487 * device corresponds to a UFS. Return NULL if no device is found.
488 */
489 struct mount *devtomp(dev)
490 struct cdev *dev;
491 {
492 struct mount *mp;
493
494 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
495 if (((VFSTOUFS(mp))->um_dev == dev)) {
496 /* mount corresponds to UFS and the device matches one we want */
497 return(mp);
498 }
499 }
500 /* mount structure wasn't found */
501 return(NULL);
502 }
503
504 struct vfsops coda_vfsops = {
505 .vfs_mount = coda_mount,
506 .vfs_root = coda_root,
507 .vfs_statfs = coda_nb_statfs,
508 .vfs_sync = coda_sync,
509 .vfs_unmount = coda_unmount,
510 };
511
512 VFS_SET(coda_vfsops, coda, VFCF_NETWORK);
Cache object: d039a395eb32f07fd22448b05b0cfc2a
|