1 /* $NetBSD: coda_vfsops.c,v 1.68 2009/01/11 02:45:46 christos Exp $ */
5 * Coda: an Experimental Distributed File System
8 * Copyright (c) 1987-1998 Carnegie Mellon University
11 * Permission to use, copy, modify and distribute this software and its
12 * documentation is hereby granted, provided that both the copyright
13 * notice and this permission notice appear in all copies of the
14 * software, derivative works or modified versions, and any portions
15 * thereof, and that both notices appear in supporting documentation, and
16 * that credit is given to Carnegie Mellon University in all documents
17 * and publicity pertaining to direct or indirect use of this code or its
20 * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS,
21 * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS
22 * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON
23 * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
24 * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF
25 * ANY DERIVATIVE WORK.
27 * Carnegie Mellon encourages users of this software to return any
28 * improvements or extensions that they make, and to grant Carnegie
29 * Mellon the rights to redistribute these changes without encumbrance.
31 * @(#) cfs/coda_vfsops.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $
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.
42 * This code was written for the Coda file system at Carnegie Mellon
43 * University. Contributers include David Steere, James Kistler, and
47 #include <sys/cdefs.h>
48 __KERNEL_RCSID(0, "$NetBSD: coda_vfsops.c,v 1.68 2009/01/11 02:45:46 christos Exp $");
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/sysctl.h>
59 #include <sys/malloc.h>
61 #include <sys/namei.h>
62 #include <sys/dirent.h>
63 #include <sys/mount.h>
65 #include <sys/select.h>
66 #include <sys/kauth.h>
67 #include <sys/module.h>
69 #include <coda/coda.h>
70 #include <coda/cnode.h>
71 #include <coda/coda_vfsops.h>
72 #include <coda/coda_venus.h>
73 #include <coda/coda_subr.h>
74 #include <coda/coda_opstats.h>
76 #include <miscfs/specfs/specdev.h>
77 #include <miscfs/genfs/genfs.h>
79 MODULE(MODULE_CLASS_VFS
, coda
, NULL
);
81 MALLOC_DEFINE(M_CODA
, "coda", "Coda file system structures and tables");
85 int coda_vfsop_print_entry
= 0;
86 #define ENTRY if(coda_vfsop_print_entry) myprintf(("Entered %s\n",__func__))
88 struct vnode
*coda_ctlvp
;
89 struct coda_mntinfo coda_mnttbl
[NVCODA
]; /* indexed by minor device number */
91 /* structure to keep statistics of internally generated/satisfied calls */
93 struct coda_op_stats coda_vfsopstats
[CODA_VFSOPS_SIZE
];
95 #define MARK_ENTRY(op) (coda_vfsopstats[op].entries++)
96 #define MARK_INT_SAT(op) (coda_vfsopstats[op].sat_intrn++)
97 #define MARK_INT_FAIL(op) (coda_vfsopstats[op].unsat_intrn++)
98 #define MRAK_INT_GEN(op) (coda_vfsopstats[op].gen_intrn++)
100 extern const struct cdevsw vcoda_cdevsw
;
101 extern const struct vnodeopv_desc coda_vnodeop_opv_desc
;
103 const struct vnodeopv_desc
* const coda_vnodeopv_descs
[] = {
104 &coda_vnodeop_opv_desc
,
108 struct vfsops coda_vfsops
= {
110 256, /* This is the pathname, unlike every other fs */
115 (void *)eopnotsupp
, /* vfs_quotactl */
119 (void *)eopnotsupp
, /* vfs_fhtovp */
120 (void *)eopnotsupp
, /* vfs_vptofh */
122 NULL
, /* vfs_reinit */
124 (int (*)(void)) eopnotsupp
,
125 (int (*)(struct mount
*, struct vnode
*, struct timespec
*)) eopnotsupp
,
127 (void *)eopnotsupp
, /* vfs_suspendctl */
128 genfs_renamelock_enter
,
129 genfs_renamelock_exit
,
132 0, /* vfs_refcount */
133 { NULL
, NULL
}, /* vfs_list */
137 coda_modcmd(modcmd_t cmd
, void *arg
)
141 case MODULE_CMD_INIT
:
142 return vfs_attach(&coda_vfsops
);
143 case MODULE_CMD_FINI
:
144 return vfs_detach(&coda_vfsops
);
151 coda_vfsopstats_init(void)
155 for (i
=0;i
<CODA_VFSOPS_SIZE
;i
++) {
156 coda_vfsopstats
[i
].opcode
= i
;
157 coda_vfsopstats
[i
].entries
= 0;
158 coda_vfsopstats
[i
].sat_intrn
= 0;
159 coda_vfsopstats
[i
].unsat_intrn
= 0;
160 coda_vfsopstats
[i
].gen_intrn
= 0;
168 * Set up mount info record and attach it to vfs struct.
172 coda_mount(struct mount
*vfsp
, /* Allocated and initialized by mount(2) */
173 const char *path
, /* path covered: ignored by the fs-layer */
174 void *data
, /* Need to define a data type for this in netbsd? */
177 struct lwp
*l
= curlwp
;
181 struct coda_mntinfo
*mi
;
183 const struct cdevsw
*cdev
;
184 CodaFid rootfid
= INVAL_FID
;
185 CodaFid ctlfid
= CTL_FID
;
188 if (vfsp
->mnt_flag
& MNT_GETARGS
)
192 coda_vfsopstats_init();
193 coda_vnodeopstats_init();
195 MARK_ENTRY(CODA_MOUNT_STATS
);
196 if (CODA_MOUNTED(vfsp
)) {
197 MARK_INT_FAIL(CODA_MOUNT_STATS
);
201 /* Validate mount device. Similar to getmdev(). */
204 * XXX: coda passes the mount device as the entire mount args,
205 * All other fs pass a structure contining a pointer.
206 * In order to get sys_mount() to do the copyin() we've set a
207 * fixed default size for the filename buffer.
209 /* Ensure that namei() doesn't run off the filename buffer */
210 ((char *)data
)[*data_len
- 1] = 0;
211 error
= namei_simple_kernel((char *)data
, NSM_FOLLOW_NOEMULROOT
,
215 MARK_INT_FAIL(CODA_MOUNT_STATS
);
218 if (dvp
->v_type
!= VCHR
) {
219 MARK_INT_FAIL(CODA_MOUNT_STATS
);
225 cdev
= cdevsw_lookup(dev
);
227 MARK_INT_FAIL(CODA_MOUNT_STATS
);
232 * See if the device table matches our expectations.
234 if (cdev
!= &vcoda_cdevsw
)
236 MARK_INT_FAIL(CODA_MOUNT_STATS
);
240 if (minor(dev
) >= NVCODA
) {
241 MARK_INT_FAIL(CODA_MOUNT_STATS
);
246 * Initialize the mount record and link it to the vfs struct
248 mi
= &coda_mnttbl
[minor(dev
)];
250 if (!VC_OPEN(&mi
->mi_vcomm
)) {
251 MARK_INT_FAIL(CODA_MOUNT_STATS
);
255 /* No initialization (here) of mi_vcomm! */
257 vfsp
->mnt_stat
.f_fsidx
.__fsid_val
[0] = 0;
258 vfsp
->mnt_stat
.f_fsidx
.__fsid_val
[1] = makefstype(MOUNT_CODA
);
259 vfsp
->mnt_stat
.f_fsid
= vfsp
->mnt_stat
.f_fsidx
.__fsid_val
[0];
260 vfsp
->mnt_stat
.f_namemax
= MAXNAMLEN
;
264 * Make a root vnode to placate the Vnode interface, but don't
265 * actually make the CODA_ROOT call to venus until the first call
266 * to coda_root in case a server is down while venus is starting.
268 cp
= make_coda_node(&rootfid
, vfsp
, VDIR
);
270 rtvp
->v_vflag
|= VV_ROOT
;
272 /* cp = make_coda_node(&ctlfid, vfsp, VCHR);
273 The above code seems to cause a loop in the cnode links.
274 I don't totally understand when it happens, it is caught
275 when closing down the system.
277 cp
= make_coda_node(&ctlfid
, 0, VCHR
);
279 coda_ctlvp
= CTOV(cp
);
281 /* Add vfs and rootvp to chain of vfs hanging off mntinfo */
283 mi
->mi_rootvp
= rtvp
;
285 /* set filesystem block size */
286 vfsp
->mnt_stat
.f_bsize
= 8192; /* XXX -JJK */
287 vfsp
->mnt_stat
.f_frsize
= 8192; /* XXX -JJK */
289 /* error is currently guaranteed to be zero, but in case some
292 myprintf(("coda_mount returned %d\n",error
)););
294 MARK_INT_FAIL(CODA_MOUNT_STATS
);
296 MARK_INT_SAT(CODA_MOUNT_STATS
);
298 return set_statvfs_info("/coda", UIO_SYSSPACE
, "CODA", UIO_SYSSPACE
,
299 vfsp
->mnt_op
->vfs_name
, vfsp
, l
);
303 coda_start(struct mount
*vfsp
, int flags
)
306 vftomi(vfsp
)->mi_started
= 1;
311 coda_unmount(struct mount
*vfsp
, int mntflags
)
313 struct coda_mntinfo
*mi
= vftomi(vfsp
);
314 int active
, error
= 0;
317 MARK_ENTRY(CODA_UMOUNT_STATS
);
318 if (!CODA_MOUNTED(vfsp
)) {
319 MARK_INT_FAIL(CODA_UMOUNT_STATS
);
323 if (mi
->mi_vfsp
== vfsp
) { /* We found the victim */
324 if (!IS_UNMOUNTING(VTOC(mi
->mi_rootvp
)))
325 return (EBUSY
); /* Venus is still running */
328 printf("coda_unmount: ROOT: vp %p, cp %p\n", mi
->mi_rootvp
, VTOC(mi
->mi_rootvp
));
332 vrele(mi
->mi_rootvp
);
334 active
= coda_kill(vfsp
, NOT_DOWNCALL
);
335 mi
->mi_rootvp
->v_vflag
&= ~VV_ROOT
;
336 error
= vflush(mi
->mi_vfsp
, NULLVP
, FORCECLOSE
);
337 printf("coda_unmount: active = %d, vflush active %d\n", active
, error
);
340 /* I'm going to take this out to allow lookups to go through. I'm
341 * not sure it's important anyway. -- DCS 2/2/94
343 /* vfsp->VFS_DATA = NULL; */
345 /* No more vfsp's to hold onto */
347 mi
->mi_rootvp
= NULL
;
350 MARK_INT_FAIL(CODA_UMOUNT_STATS
);
352 MARK_INT_SAT(CODA_UMOUNT_STATS
);
363 coda_root(struct mount
*vfsp
, struct vnode
**vpp
)
365 struct coda_mntinfo
*mi
= vftomi(vfsp
);
367 struct lwp
*l
= curlwp
; /* XXX - bnoble */
369 static const CodaFid invalfid
= INVAL_FID
;
372 MARK_ENTRY(CODA_ROOT_STATS
);
374 if (vfsp
== mi
->mi_vfsp
) {
375 if (memcmp(&VTOC(mi
->mi_rootvp
)->c_fid
, &invalfid
, sizeof(CodaFid
)))
376 { /* Found valid root. */
377 *vpp
= mi
->mi_rootvp
;
378 /* On Mach, this is vref. On NetBSD, VOP_LOCK */
380 vn_lock(*vpp
, LK_EXCLUSIVE
);
381 MARK_INT_SAT(CODA_ROOT_STATS
);
386 error
= venus_root(vftomi(vfsp
), l
->l_cred
, l
->l_proc
, &VFid
);
390 * Save the new rootfid in the cnode, and rehash the cnode into the
391 * cnode hash with the new fid key.
393 coda_unsave(VTOC(mi
->mi_rootvp
));
394 VTOC(mi
->mi_rootvp
)->c_fid
= VFid
;
395 coda_save(VTOC(mi
->mi_rootvp
));
397 *vpp
= mi
->mi_rootvp
;
399 vn_lock(*vpp
, LK_EXCLUSIVE
);
400 MARK_INT_SAT(CODA_ROOT_STATS
);
402 } else if (error
== ENODEV
|| error
== EINTR
) {
403 /* Gross hack here! */
405 * If Venus fails to respond to the CODA_ROOT call, coda_call returns
406 * ENODEV. Return the uninitialized root vnode to allow vfs
407 * operations such as unmount to continue. Without this hack,
408 * there is no way to do an unmount if Venus dies before a
409 * successful CODA_ROOT call is done. All vnode operations
412 *vpp
= mi
->mi_rootvp
;
414 vn_lock(*vpp
, LK_EXCLUSIVE
);
415 MARK_INT_FAIL(CODA_ROOT_STATS
);
419 CODADEBUG( CODA_ROOT
, myprintf(("error %d in CODA_ROOT\n", error
)); );
420 MARK_INT_FAIL(CODA_ROOT_STATS
);
429 * Get file system statistics.
432 coda_nb_statvfs(struct mount
*vfsp
, struct statvfs
*sbp
)
434 struct lwp
*l
= curlwp
;
435 struct coda_statfs fsstat
;
439 MARK_ENTRY(CODA_STATFS_STATS
);
440 if (!CODA_MOUNTED(vfsp
)) {
441 /* MARK_INT_FAIL(CODA_STATFS_STATS); */
445 /* XXX - what to do about f_flags, others? --bnoble */
446 /* Below This is what AFS does
447 #define NB_SFS_SIZ 0x895440
449 /* Note: Normal fs's have a bsize of 0x400 == 1024 */
451 error
= venus_statfs(vftomi(vfsp
), l
->l_cred
, l
, &fsstat
);
454 sbp
->f_bsize
= 8192; /* XXX */
455 sbp
->f_frsize
= 8192; /* XXX */
456 sbp
->f_iosize
= 8192; /* XXX */
457 sbp
->f_blocks
= fsstat
.f_blocks
;
458 sbp
->f_bfree
= fsstat
.f_bfree
;
459 sbp
->f_bavail
= fsstat
.f_bavail
;
461 sbp
->f_files
= fsstat
.f_files
;
462 sbp
->f_ffree
= fsstat
.f_ffree
;
463 sbp
->f_favail
= fsstat
.f_ffree
;
465 copy_statvfs_info(sbp
, vfsp
);
468 MARK_INT_SAT(CODA_STATFS_STATS
);
473 * Flush any pending I/O.
476 coda_sync(struct mount
*vfsp
, int waitfor
,
480 MARK_ENTRY(CODA_SYNC_STATS
);
481 MARK_INT_SAT(CODA_SYNC_STATS
);
486 coda_vget(struct mount
*vfsp
, ino_t ino
,
494 * fhtovp is now what vget used to be in 4.3-derived systems. For
495 * some silly reason, vget is now keyed by a 32 bit ino_t, rather than
496 * a type-specific fid.
499 coda_fhtovp(struct mount
*vfsp
, struct fid
*fhp
, struct mbuf
*nam
,
500 struct vnode
**vpp
, int *exflagsp
,
501 kauth_cred_t
*creadanonp
)
503 struct cfid
*cfid
= (struct cfid
*)fhp
;
504 struct cnode
*cp
= 0;
506 struct lwp
*l
= curlwp
; /* XXX -mach */
512 MARK_ENTRY(CODA_VGET_STATS
);
513 /* Check for vget of control object. */
514 if (IS_CTL_FID(&cfid
->cfid_fid
)) {
517 MARK_INT_SAT(CODA_VGET_STATS
);
521 error
= venus_fhtovp(vftomi(vfsp
), &cfid
->cfid_fid
, l
->l_cred
, l
->l_proc
, &VFid
, &vtype
);
524 CODADEBUG(CODA_VGET
, myprintf(("vget error %d\n",error
));)
525 *vpp
= (struct vnode
*)0;
528 myprintf(("vget: %s type %d result %d\n",
529 coda_f2s(&VFid
), vtype
, error
)); )
531 cp
= make_coda_node(&VFid
, vfsp
, vtype
);
538 coda_vptofh(struct vnode
*vnp
, struct fid
*fidp
)
556 SYSCTL_SETUP(sysctl_vfs_coda_setup
, "sysctl vfs.coda subtree setup")
558 sysctl_createv(clog
, 0, NULL
, NULL
,
560 CTLTYPE_NODE
, "vfs", NULL
,
563 sysctl_createv(clog
, 0, NULL
, NULL
,
565 CTLTYPE_NODE
, "coda",
566 SYSCTL_DESCR("code vfs options"),
568 CTL_VFS
, 18, CTL_EOL
);
570 * XXX the "18" above could be dynamic, thereby eliminating
571 * one more instance of the "number to vfs" mapping problem,
572 * but "18" is the order as taken from sys/mount.h
576 sysctl_createv(clog, 0, NULL, NULL,
577 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
578 CTLTYPE_INT, "clusterread",
579 SYSCTL_DESCR( anyone? ),
580 NULL, 0, &doclusterread, 0,
581 CTL_VFS, 18, FFS_CLUSTERREAD, CTL_EOL);
586 * To allow for greater ease of use, some vnodes may be orphaned when
587 * Venus dies. Certain operations should still be allowed to go
588 * through, but without propagating orphan-ness. So this function will
589 * get a new vnode for the file from the current run of Venus.
593 getNewVnode(struct vnode
**vpp
)
596 struct coda_mntinfo
*mi
= vftomi((*vpp
)->v_mount
);
600 cfid
.cfid_len
= (short)sizeof(CodaFid
);
601 cfid
.cfid_fid
= VTOC(*vpp
)->c_fid
; /* Structure assignment. */
604 /* We're guessing that if set, the 1st element on the list is a
605 * valid vnode to use. If not, return ENODEV as venus is dead.
607 if (mi
->mi_vfsp
== NULL
)
610 return coda_fhtovp(mi
->mi_vfsp
, (struct fid
*)&cfid
, NULL
, vpp
,
614 #include <ufs/ufs/quota.h>
615 #include <ufs/ufs/ufsmount.h>
616 /* get the mount structure corresponding to a given device. Assume
617 * device corresponds to a UFS. Return NULL if no device is found.
619 struct mount
*devtomp(dev_t dev
)
621 struct mount
*mp
, *nmp
;
623 for (mp
= mountlist
.cqh_first
; mp
!= (void*)&mountlist
; mp
= nmp
) {
624 nmp
= mp
->mnt_list
.cqe_next
;
625 if ((!strcmp(mp
->mnt_op
->vfs_name
, MOUNT_UFS
)) &&
626 ((VFSTOUFS(mp
))->um_dev
== (dev_t
) dev
)) {
627 /* mount corresponds to UFS and the device matches one we want */
631 /* mount structure wasn't found */