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