coda_vfsops.c revision 176131
1139745Simp/*-
238759Srvb *             Coda: an Experimental Distributed File System
338759Srvb *                              Release 3.1
438759Srvb *
538759Srvb *           Copyright (c) 1987-1998 Carnegie Mellon University
638759Srvb *                          All Rights Reserved
738759Srvb *
838759Srvb * Permission  to  use, copy, modify and distribute this software and its
938759Srvb * documentation is hereby granted,  provided  that  both  the  copyright
1038759Srvb * notice  and  this  permission  notice  appear  in  all  copies  of the
1138759Srvb * software, derivative works or  modified  versions,  and  any  portions
1238759Srvb * thereof, and that both notices appear in supporting documentation, and
1338759Srvb * that credit is given to Carnegie Mellon University  in  all  documents
1438759Srvb * and publicity pertaining to direct or indirect use of this code or its
1538759Srvb * derivatives.
1638759Srvb *
1738759Srvb * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS  KNOWN  TO  HAVE  BUGS,
1838759Srvb * SOME  OF  WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON ALLOWS
1938759Srvb * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.   CARNEGIE  MELLON
2038759Srvb * DISCLAIMS  ANY  LIABILITY  OF  ANY  KIND  FOR  ANY  DAMAGES WHATSOEVER
2138759Srvb * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE  OR  OF
2238759Srvb * ANY DERIVATIVE WORK.
2338759Srvb *
2438759Srvb * Carnegie  Mellon  encourages  users  of  this  software  to return any
2538759Srvb * improvements or extensions that  they  make,  and  to  grant  Carnegie
2638759Srvb * Mellon the rights to redistribute these changes without encumbrance.
2738759Srvb *
2839085Srvb *  	@(#) src/sys/cfs/coda_vfsops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
2938759Srvb */
30139745Simp/*-
3138625Srvb * Mach Operating System
3238625Srvb * Copyright (c) 1989 Carnegie-Mellon University
3338625Srvb * All rights reserved.  The CMU software License Agreement specifies
3438625Srvb * the terms and conditions for use and redistribution.
3538625Srvb */
3638625Srvb
3738625Srvb/*
3896755Strhodes * This code was written for the Coda filesystem at Carnegie Mellon
3938625Srvb * University.  Contributers include David Steere, James Kistler, and
4038625Srvb * M. Satyanarayanan.
4138625Srvb */
4238625Srvb
43116173Sobrien#include <sys/cdefs.h>
44116173Sobrien__FBSDID("$FreeBSD: head/sys/fs/coda/coda_vfsops.c 176131 2008-02-09 12:49:18Z rwatson $");
45116173Sobrien
4638625Srvb#include <sys/param.h>
4738625Srvb#include <sys/systm.h>
4876166Smarkm#include <sys/conf.h>
4938759Srvb#include <sys/kernel.h>
5076166Smarkm#include <sys/lock.h>
5138625Srvb#include <sys/malloc.h>
5276166Smarkm#include <sys/mount.h>
5338625Srvb#include <sys/namei.h>
5476166Smarkm#include <sys/proc.h>
5538625Srvb
56171416Srwatson#include <fs/coda/coda.h>
57171416Srwatson#include <fs/coda/cnode.h>
58171416Srwatson#include <fs/coda/coda_vfsops.h>
59171416Srwatson#include <fs/coda/coda_venus.h>
60171416Srwatson#include <fs/coda/coda_subr.h>
61171416Srwatson#include <fs/coda/coda_opstats.h>
6238759Srvb
63151897SrwatsonMALLOC_DEFINE(M_CODA, "coda", "Various Coda Structures");
6438625Srvb
6539085Srvbint codadebug = 0;
6639085Srvbint coda_vfsop_print_entry = 0;
6787599Sobrien#define ENTRY    if(coda_vfsop_print_entry) myprintf(("Entered %s\n",__func__))
6838625Srvb
6939085Srvbstruct vnode *coda_ctlvp;
7038625Srvb
7138625Srvb/* structure to keep statistics of internally generated/satisfied calls */
7238625Srvb
7339085Srvbstruct coda_op_stats coda_vfsopstats[CODA_VFSOPS_SIZE];
7438625Srvb
7539085Srvb#define MARK_ENTRY(op) (coda_vfsopstats[op].entries++)
7639085Srvb#define MARK_INT_SAT(op) (coda_vfsopstats[op].sat_intrn++)
7739085Srvb#define MARK_INT_FAIL(op) (coda_vfsopstats[op].unsat_intrn++)
78154144Smaxim#define MARK_INT_GEN(op) (coda_vfsopstats[op].gen_intrn++)
7938625Srvb
8038625Srvbint
8139085Srvbcoda_vfsopstats_init(void)
8238625Srvb{
8338625Srvb	register int i;
8438625Srvb
8539085Srvb	for (i=0;i<CODA_VFSOPS_SIZE;i++) {
8639085Srvb		coda_vfsopstats[i].opcode = i;
8739085Srvb		coda_vfsopstats[i].entries = 0;
8839085Srvb		coda_vfsopstats[i].sat_intrn = 0;
8939085Srvb		coda_vfsopstats[i].unsat_intrn = 0;
9039085Srvb		coda_vfsopstats[i].gen_intrn = 0;
9138625Srvb	}
9238625Srvb
9338625Srvb	return 0;
9438625Srvb}
9538625Srvb
96138478Sphkstatic const char *coda_opts[] = { "from", NULL };
9738625Srvb/*
9838625Srvb * cfs mount vfsop
9938625Srvb * Set up mount info record and attach it to vfs struct.
10038625Srvb */
10138625Srvb/*ARGSUSED*/
10238625Srvbint
103138478Sphkcoda_mount(struct mount *vfsp, struct thread *td)
10438625Srvb{
10538625Srvb    struct vnode *dvp;
10638625Srvb    struct cnode *cp;
107130585Sphk    struct cdev *dev;
10839085Srvb    struct coda_mntinfo *mi;
10938625Srvb    struct vnode *rootvp;
110119832Stjr    CodaFid rootfid = INVAL_FID;
111119832Stjr    CodaFid ctlfid = CTL_FID;
11238625Srvb    int error;
113132902Sphk    struct nameidata ndp;
11438625Srvb    ENTRY;
115138478Sphk    char *from;
11638625Srvb
117138478Sphk    if (vfs_filteropt(vfsp->mnt_optnew, coda_opts))
118138478Sphk	return (EINVAL);
119138478Sphk
120138478Sphk    from = vfs_getopts(vfsp->mnt_optnew, "from", &error);
121138478Sphk    if (error)
122138478Sphk	return (error);
123138478Sphk
12439085Srvb    coda_vfsopstats_init();
12539085Srvb    coda_vnodeopstats_init();
12638625Srvb
12739085Srvb    MARK_ENTRY(CODA_MOUNT_STATS);
12839085Srvb    if (CODA_MOUNTED(vfsp)) {
12939085Srvb	MARK_INT_FAIL(CODA_MOUNT_STATS);
13038625Srvb	return(EBUSY);
13138625Srvb    }
13238625Srvb
13338625Srvb    /* Validate mount device.  Similar to getmdev(). */
134138478Sphk    NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, td);
135132902Sphk    error = namei(&ndp);
136132902Sphk    dvp = ndp.ni_vp;
13738625Srvb
13838625Srvb    if (error) {
13939085Srvb	MARK_INT_FAIL(CODA_MOUNT_STATS);
14038625Srvb	return (error);
14138625Srvb    }
14238625Srvb    if (dvp->v_type != VCHR) {
14339085Srvb	MARK_INT_FAIL(CODA_MOUNT_STATS);
14438625Srvb	vrele(dvp);
145132902Sphk	NDFREE(&ndp, NDF_ONLY_PNBUF);
14638625Srvb	return(ENXIO);
14738625Srvb    }
14848926Sphk    dev = dvp->v_rdev;
14938625Srvb    vrele(dvp);
150132902Sphk    NDFREE(&ndp, NDF_ONLY_PNBUF);
15138625Srvb
15238625Srvb    /*
153171375Srwatson     * Initialize the mount record and link it to the vfs struct
15438625Srvb     */
155171375Srwatson    mi = dev2coda_mntinfo(dev);
156171375Srwatson    if (!mi) {
15739085Srvb	MARK_INT_FAIL(CODA_MOUNT_STATS);
158171375Srwatson	printf("Coda mount: %s is not a cfs device\n", from);
15938625Srvb	return(ENXIO);
16038625Srvb    }
16138625Srvb
16238625Srvb    if (!VC_OPEN(&mi->mi_vcomm)) {
16339085Srvb	MARK_INT_FAIL(CODA_MOUNT_STATS);
16438625Srvb	return(ENODEV);
16538625Srvb    }
16638625Srvb
16738625Srvb    /* No initialization (here) of mi_vcomm! */
168172697Salfred    vfsp->mnt_data = mi;
16938625Srvb    vfs_getnewfsid (vfsp);
17038625Srvb
17138625Srvb    mi->mi_vfsp = vfsp;
172111945Stjr    mi->mi_started = 0;			/* XXX See coda_root() */
17338625Srvb
17438625Srvb    /*
17538625Srvb     * Make a root vnode to placate the Vnode interface, but don't
17639085Srvb     * actually make the CODA_ROOT call to venus until the first call
17739085Srvb     * to coda_root in case a server is down while venus is starting.
17838625Srvb     */
17939085Srvb    cp = make_coda_node(&rootfid, vfsp, VDIR);
18038625Srvb    rootvp = CTOV(cp);
181101308Sjeff    rootvp->v_vflag |= VV_ROOT;
18238625Srvb
183171379Srwatson    cp = make_coda_node(&ctlfid, vfsp, VREG);
18439085Srvb    coda_ctlvp = CTOV(cp);
18538625Srvb
18638625Srvb    /* Add vfs and rootvp to chain of vfs hanging off mntinfo */
18738625Srvb    mi->mi_vfsp = vfsp;
18838625Srvb    mi->mi_rootvp = rootvp;
18938625Srvb
190138478Sphk    vfs_mountedfrom(vfsp, from);
19138625Srvb    /* error is currently guaranteed to be zero, but in case some
19238625Srvb       code changes... */
19339085Srvb    CODADEBUG(1,
194132902Sphk	     myprintf(("coda_omount returned %d\n",error)););
19538625Srvb    if (error)
19639085Srvb	MARK_INT_FAIL(CODA_MOUNT_STATS);
19738625Srvb    else
19839085Srvb	MARK_INT_SAT(CODA_MOUNT_STATS);
19938625Srvb
20038625Srvb    return(error);
20138625Srvb}
20238625Srvb
20338625Srvbint
20483366Sjuliancoda_unmount(vfsp, mntflags, td)
20538625Srvb    struct mount *vfsp;
20638625Srvb    int mntflags;
20783366Sjulian    struct thread *td;
20838625Srvb{
20939085Srvb    struct coda_mntinfo *mi = vftomi(vfsp);
21038625Srvb    int active, error = 0;
21138625Srvb
21238625Srvb    ENTRY;
21339085Srvb    MARK_ENTRY(CODA_UMOUNT_STATS);
21439085Srvb    if (!CODA_MOUNTED(vfsp)) {
21539085Srvb	MARK_INT_FAIL(CODA_UMOUNT_STATS);
21638625Srvb	return(EINVAL);
21738625Srvb    }
21838625Srvb
21938625Srvb    if (mi->mi_vfsp == vfsp) {	/* We found the victim */
22038625Srvb	if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp)))
22138625Srvb	    return (EBUSY); 	/* Venus is still running */
22238625Srvb
22338625Srvb#ifdef	DEBUG
22439085Srvb	printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp, VTOC(mi->mi_rootvp));
22538625Srvb#endif
22638625Srvb	vrele(mi->mi_rootvp);
227175479Srwatson	mi->mi_rootvp = NULL;
228171518Srwatson	vrele(coda_ctlvp);
229175479Srwatson	coda_ctlvp = NULL;
23039085Srvb	active = coda_kill(vfsp, NOT_DOWNCALL);
231132023Salfred	error = vflush(mi->mi_vfsp, 0, FORCECLOSE, td);
232120011Stjr#ifdef CODA_VERBOSE
23339085Srvb	printf("coda_unmount: active = %d, vflush active %d\n", active, error);
234120011Stjr#endif
23538625Srvb	error = 0;
23638625Srvb	/* I'm going to take this out to allow lookups to go through. I'm
23738625Srvb	 * not sure it's important anyway. -- DCS 2/2/94
23838625Srvb	 */
23938625Srvb	/* vfsp->VFS_DATA = NULL; */
24038625Srvb
24138625Srvb	/* No more vfsp's to hold onto */
24238625Srvb	mi->mi_vfsp = NULL;
24338625Srvb
24438625Srvb	if (error)
24539085Srvb	    MARK_INT_FAIL(CODA_UMOUNT_STATS);
24638625Srvb	else
24739085Srvb	    MARK_INT_SAT(CODA_UMOUNT_STATS);
24838625Srvb
24938625Srvb	return(error);
25038625Srvb    }
25138625Srvb    return (EINVAL);
25238625Srvb}
25338625Srvb
25438625Srvb/*
25538625Srvb * find root of cfs
25638625Srvb */
25738625Srvbint
258144059Sjeffcoda_root(vfsp, flags, vpp, td)
25938625Srvb	struct mount *vfsp;
260144059Sjeff	int flags;
26138625Srvb	struct vnode **vpp;
262132023Salfred	struct thread *td;
26338625Srvb{
26439085Srvb    struct coda_mntinfo *mi = vftomi(vfsp);
26538625Srvb    struct vnode **result;
26638625Srvb    int error;
26783366Sjulian    struct proc *p = td->td_proc;
268119832Stjr    CodaFid VFid;
269119832Stjr    static const CodaFid invalfid = INVAL_FID;
27083366Sjulian
27183366Sjulian    ENTRY;
27239085Srvb    MARK_ENTRY(CODA_ROOT_STATS);
27338625Srvb    result = NULL;
27438625Srvb
27538625Srvb    if (vfsp == mi->mi_vfsp) {
276111945Stjr	/*
277111945Stjr	 * Cache the root across calls. We only need to pass the request
278111945Stjr	 * on to Venus if the root vnode is the dummy we installed in
279132902Sphk	 * coda_omount() with all c_fid members zeroed.
280111945Stjr	 *
281142152Sdas	 * XXX In addition, we assume that the first call to coda_root()
282142152Sdas	 * is from vfs_omount()
283111945Stjr	 * (before the call to checkdirs()) and return the dummy root
284111945Stjr	 * node to avoid a deadlock. This bug is fixed in the Coda CVS
285111945Stjr	 * repository but not in any released versions as of 6 Mar 2003.
286111945Stjr	 */
287119832Stjr	if (memcmp(&VTOC(mi->mi_rootvp)->c_fid, &invalfid,
288119832Stjr	    sizeof(CodaFid)) != 0 || mi->mi_started == 0)
28938625Srvb	    { /* Found valid root. */
29038625Srvb		*vpp = mi->mi_rootvp;
291142152Sdas		mi->mi_started = 1;
292142152Sdas
293176120Srwatson		/* On Mach, this is vref.  On FreeBSD, vref + vn_lock. */
29438625Srvb		vref(*vpp);
295176121Srwatson		vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
29639085Srvb		MARK_INT_SAT(CODA_ROOT_STATS);
29738625Srvb		return(0);
29838625Srvb	    }
29938625Srvb    }
30038625Srvb
30191406Sjhb    error = venus_root(vftomi(vfsp), td->td_ucred, p, &VFid);
30238625Srvb
30338625Srvb    if (!error) {
30438625Srvb	/*
30538625Srvb	 * Save the new rootfid in the cnode, and rehash the cnode into the
30638625Srvb	 * cnode hash with the new fid key.
30738625Srvb	 */
30839085Srvb	coda_unsave(VTOC(mi->mi_rootvp));
30938625Srvb	VTOC(mi->mi_rootvp)->c_fid = VFid;
31039085Srvb	coda_save(VTOC(mi->mi_rootvp));
31138625Srvb
31238625Srvb	*vpp = mi->mi_rootvp;
31338625Srvb	vref(*vpp);
314176121Srwatson	vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
31538759Srvb
31639085Srvb	MARK_INT_SAT(CODA_ROOT_STATS);
31738625Srvb	goto exit;
31841202Srvb    } else if (error == ENODEV || error == EINTR) {
31938625Srvb	/* Gross hack here! */
32038625Srvb	/*
32139085Srvb	 * If Venus fails to respond to the CODA_ROOT call, coda_call returns
32238625Srvb	 * ENODEV. Return the uninitialized root vnode to allow vfs
32338625Srvb	 * operations such as unmount to continue. Without this hack,
32438625Srvb	 * there is no way to do an unmount if Venus dies before a
32539085Srvb	 * successful CODA_ROOT call is done. All vnode operations
32638625Srvb	 * will fail.
32738625Srvb	 */
32838625Srvb	*vpp = mi->mi_rootvp;
32938625Srvb	vref(*vpp);
330176121Srwatson	vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
33138759Srvb
33239085Srvb	MARK_INT_FAIL(CODA_ROOT_STATS);
33338625Srvb	error = 0;
33438625Srvb	goto exit;
33538625Srvb    } else {
33639085Srvb	CODADEBUG( CODA_ROOT, myprintf(("error %d in CODA_ROOT\n", error)); );
33739085Srvb	MARK_INT_FAIL(CODA_ROOT_STATS);
33838625Srvb
33938625Srvb	goto exit;
34038625Srvb    }
34138759Srvb
34238625Srvb exit:
34338625Srvb    return(error);
34438625Srvb}
34538625Srvb
34638625Srvb/*
34796755Strhodes * Get filesystem statistics.
34838625Srvb */
34938625Srvbint
350176131Srwatsoncoda_statfs(vfsp, sbp, td)
35138625Srvb    register struct mount *vfsp;
35238625Srvb    struct statfs *sbp;
35383366Sjulian    struct thread *td;
35438625Srvb{
35538625Srvb    ENTRY;
356176130Srwatson    MARK_ENTRY(CODA_STATFS_STATS);
35739085Srvb    if (!CODA_MOUNTED(vfsp)) {
358176130Srwatson	MARK_INT_FAIL(CODA_STATFS_STATS);
35938625Srvb	return(EINVAL);
36038625Srvb    }
36138625Srvb
36238625Srvb    /* XXX - what to do about f_flags, others? --bnoble */
36338625Srvb    /* Below This is what AFS does
364176131Srwatson    	#define CODA_SFS_SIZ 0x895440
36538625Srvb     */
366175481Srwatson    sbp->f_flags = 0;
36738625Srvb    sbp->f_bsize = 8192; /* XXX */
36838625Srvb    sbp->f_iosize = 8192; /* XXX */
369176131Srwatson#define CODA_SFS_SIZ 0x8AB75D
370176131Srwatson    sbp->f_blocks = CODA_SFS_SIZ;
371176131Srwatson    sbp->f_bfree = CODA_SFS_SIZ;
372176131Srwatson    sbp->f_bavail = CODA_SFS_SIZ;
373176131Srwatson    sbp->f_files = CODA_SFS_SIZ;
374176131Srwatson    sbp->f_ffree = CODA_SFS_SIZ;
375176130Srwatson    MARK_INT_SAT(CODA_STATFS_STATS);
37638625Srvb    return(0);
37738625Srvb}
37838625Srvb
37938625Srvb/*
38038625Srvb * Flush any pending I/O.
38138625Srvb */
38238625Srvbint
383140048Sphkcoda_sync(vfsp, waitfor, td)
38438625Srvb    struct mount *vfsp;
38538625Srvb    int    waitfor;
38683366Sjulian    struct thread *td;
38738625Srvb{
38838625Srvb    ENTRY;
38939085Srvb    MARK_ENTRY(CODA_SYNC_STATS);
39039085Srvb    MARK_INT_SAT(CODA_SYNC_STATS);
39138625Srvb    return(0);
39238625Srvb}
39338625Srvb
39438625Srvb/*
39538625Srvb * fhtovp is now what vget used to be in 4.3-derived systems.  For
39638625Srvb * some silly reason, vget is now keyed by a 32 bit ino_t, rather than
39738625Srvb * a type-specific fid.
398176131Srwatson *
399176131Srwatson * XXX: coda_fhtovp is currently not hooked up, so no NFS export for Coda.
400176131Srwatson * We leave it here in the hopes that someone will find it someday and hook
401176131Srwatson * it up.  Among other things, it will need some reworking to match the
402176131Srwatson * vfs_fhtovp_t prototype.
40338625Srvb */
40438625Srvbint
40539085Srvbcoda_fhtovp(vfsp, fhp, nam, vpp, exflagsp, creadanonp)
40638625Srvb    register struct mount *vfsp;
40738625Srvb    struct fid *fhp;
40838625Srvb    struct mbuf *nam;
40938625Srvb    struct vnode **vpp;
41038625Srvb    int *exflagsp;
41138625Srvb    struct ucred **creadanonp;
41238625Srvb{
41338625Srvb    struct cfid *cfid = (struct cfid *)fhp;
41438625Srvb    struct cnode *cp = 0;
41538625Srvb    int error;
41683366Sjulian    struct thread *td = curthread; /* XXX -mach */
41783366Sjulian    struct proc *p = td->td_proc;
418119832Stjr    CodaFid VFid;
41938625Srvb    int vtype;
42038625Srvb
42138625Srvb    ENTRY;
42238625Srvb
42339085Srvb    MARK_ENTRY(CODA_VGET_STATS);
42438625Srvb    /* Check for vget of control object. */
42538625Srvb    if (IS_CTL_FID(&cfid->cfid_fid)) {
42639085Srvb	*vpp = coda_ctlvp;
42739085Srvb	vref(coda_ctlvp);
42839085Srvb	MARK_INT_SAT(CODA_VGET_STATS);
42938625Srvb	return(0);
43038625Srvb    }
43138625Srvb
43291406Sjhb    error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, td->td_ucred, p, &VFid, &vtype);
43338625Srvb
43438625Srvb    if (error) {
43539085Srvb	CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error));)
43638625Srvb	    *vpp = (struct vnode *)0;
43738625Srvb    } else {
43839085Srvb	CODADEBUG(CODA_VGET,
439119832Stjr		 myprintf(("vget: %s type %d result %d\n",
440119832Stjr			coda_f2s(&VFid), vtype, error)); )
44139085Srvb	cp = make_coda_node(&VFid, vfsp, vtype);
44238625Srvb	*vpp = CTOV(cp);
44338625Srvb    }
44438625Srvb    return(error);
44538625Srvb}
44638625Srvb
44739650Srvbstruct vfsops coda_vfsops = {
448138478Sphk    .vfs_mount =		coda_mount,
449116271Sphk    .vfs_root = 		coda_root,
450176131Srwatson    .vfs_statfs =		coda_statfs,
451116271Sphk    .vfs_sync = 		coda_sync,
452116271Sphk    .vfs_unmount =		coda_unmount,
45339650Srvb};
45439650Srvb
45539650SrvbVFS_SET(coda_vfsops, coda, VFCF_NETWORK);
456