1139745Simp/*-
238759Srvb *             Coda: an Experimental Distributed File System
338759Srvb *                              Release 3.1
4176139Srwatson *
538759Srvb *           Copyright (c) 1987-1998 Carnegie Mellon University
638759Srvb *                          All Rights Reserved
7176139Srwatson *
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.
16176139Srwatson *
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.
23176139Srwatson *
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.
27176139Srwatson *
2839085Srvb *  	@(#) src/sys/cfs/coda_vfsops.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
2938759Srvb */
30176139Srwatson
31139745Simp/*-
3238625Srvb * Mach Operating System
3338625Srvb * Copyright (c) 1989 Carnegie-Mellon University
3438625Srvb * All rights reserved.  The CMU software License Agreement specifies
3538625Srvb * the terms and conditions for use and redistribution.
3638625Srvb */
3738625Srvb
3838625Srvb/*
3996755Strhodes * This code was written for the Coda filesystem at Carnegie Mellon
4038625Srvb * University.  Contributers include David Steere, James Kistler, and
41176139Srwatson * M. Satyanarayanan.
4238625Srvb */
4338625Srvb
44116173Sobrien#include <sys/cdefs.h>
45116173Sobrien__FBSDID("$FreeBSD$");
46116173Sobrien
4738625Srvb#include <sys/param.h>
4838625Srvb#include <sys/systm.h>
4976166Smarkm#include <sys/conf.h>
50177785Skib#include <sys/fcntl.h>
5138759Srvb#include <sys/kernel.h>
5276166Smarkm#include <sys/lock.h>
5338625Srvb#include <sys/malloc.h>
5476166Smarkm#include <sys/mount.h>
5538625Srvb#include <sys/namei.h>
5676166Smarkm#include <sys/proc.h>
5738625Srvb
58171416Srwatson#include <fs/coda/coda.h>
59171416Srwatson#include <fs/coda/cnode.h>
60171416Srwatson#include <fs/coda/coda_vfsops.h>
61171416Srwatson#include <fs/coda/coda_venus.h>
62171416Srwatson#include <fs/coda/coda_subr.h>
63171416Srwatson#include <fs/coda/coda_opstats.h>
6438759Srvb
65151897SrwatsonMALLOC_DEFINE(M_CODA, "coda", "Various Coda Structures");
6638625Srvb
6739085Srvbint codadebug = 0;
6839085Srvbint coda_vfsop_print_entry = 0;
69176139Srwatson#define	ENTRY do {							\
70176139Srwatson	if (coda_vfsop_print_entry)					\
71176139Srwatson		myprintf(("Entered %s\n", __func__));			\
72176139Srwatson} while (0)
7338625Srvb
7439085Srvbstruct vnode *coda_ctlvp;
7538625Srvb
76176139Srwatson/*
77176139Srwatson * Structure to keep statistics of internally generated/satisfied calls.
78176139Srwatson */
79176139Srwatsonstatic struct coda_op_stats coda_vfsopstats[CODA_VFSOPS_SIZE];
8038625Srvb
81176139Srwatson#define	MARK_ENTRY(op)		(coda_vfsopstats[op].entries++)
82176139Srwatson#define	MARK_INT_SAT(op)	(coda_vfsopstats[op].sat_intrn++)
83176139Srwatson#define	MARK_INT_FAIL(op)	(coda_vfsopstats[op].unsat_intrn++)
84176139Srwatson#define	MARK_INT_GEN(op)	(coda_vfsopstats[op].gen_intrn++)
8538625Srvb
8638625Srvbint
8739085Srvbcoda_vfsopstats_init(void)
8838625Srvb{
89176139Srwatson	int i;
90176139Srwatson
91176139Srwatson	for (i=0; i<CODA_VFSOPS_SIZE;i++) {
9239085Srvb		coda_vfsopstats[i].opcode = i;
9339085Srvb		coda_vfsopstats[i].entries = 0;
9439085Srvb		coda_vfsopstats[i].sat_intrn = 0;
9539085Srvb		coda_vfsopstats[i].unsat_intrn = 0;
9639085Srvb		coda_vfsopstats[i].gen_intrn = 0;
9738625Srvb	}
98176139Srwatson	return (0);
9938625Srvb}
10038625Srvb
101138478Sphkstatic const char *coda_opts[] = { "from", NULL };
10238625Srvb/*
10338625Srvb * cfs mount vfsop
104176139Srwatson *
10538625Srvb * Set up mount info record and attach it to vfs struct.
10638625Srvb */
10738625Srvb/*ARGSUSED*/
10838625Srvbint
109191990Sattiliocoda_mount(struct mount *vfsp)
11038625Srvb{
111176139Srwatson	struct vnode *dvp;
112176139Srwatson	struct cnode *cp;
113176139Srwatson	struct cdev *dev;
114176139Srwatson	struct coda_mntinfo *mi;
115176139Srwatson	struct vnode *rootvp;
116206210Srwatson	struct CodaFid rootfid = INVAL_FID;
117206210Srwatson	struct CodaFid ctlfid = CTL_FID;
118176139Srwatson	int error;
119176139Srwatson	struct nameidata ndp;
120176139Srwatson	ENTRY;
121176139Srwatson	char *from;
12238625Srvb
123176139Srwatson	if (vfs_filteropt(vfsp->mnt_optnew, coda_opts))
124176139Srwatson		return (EINVAL);
125176139Srwatson	from = vfs_getopts(vfsp->mnt_optnew, "from", &error);
126176139Srwatson	if (error)
127176139Srwatson		return (error);
128176139Srwatson	coda_vfsopstats_init();
129176139Srwatson	coda_vnodeopstats_init();
130176139Srwatson	MARK_ENTRY(CODA_MOUNT_STATS);
131176139Srwatson	if (CODA_MOUNTED(vfsp)) {
132176139Srwatson		MARK_INT_FAIL(CODA_MOUNT_STATS);
133176139Srwatson		return (EBUSY);
134176139Srwatson	}
135138478Sphk
136176139Srwatson	/*
137176139Srwatson	 * Validate mount device.  Similar to getmdev().
138176139Srwatson	 */
139191990Sattilio	NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, from, curthread);
140176139Srwatson	error = namei(&ndp);
141176139Srwatson	dvp = ndp.ni_vp;
142176139Srwatson	if (error) {
143176139Srwatson		MARK_INT_FAIL(CODA_MOUNT_STATS);
144176139Srwatson		return (error);
145176139Srwatson	}
146176139Srwatson	if (dvp->v_type != VCHR) {
147176139Srwatson		MARK_INT_FAIL(CODA_MOUNT_STATS);
148176139Srwatson		vrele(dvp);
149176139Srwatson		NDFREE(&ndp, NDF_ONLY_PNBUF);
150176139Srwatson		return (ENXIO);
151176139Srwatson	}
152176139Srwatson	dev = dvp->v_rdev;
15338625Srvb	vrele(dvp);
154132902Sphk	NDFREE(&ndp, NDF_ONLY_PNBUF);
15538625Srvb
156176139Srwatson	/*
157176139Srwatson	 * Initialize the mount record and link it to the vfs struct.
158176139Srwatson	 */
159176139Srwatson	mi = dev2coda_mntinfo(dev);
160176139Srwatson	if (!mi) {
161176139Srwatson		MARK_INT_FAIL(CODA_MOUNT_STATS);
162176139Srwatson		printf("Coda mount: %s is not a cfs device\n", from);
163176139Srwatson		return (ENXIO);
164176139Srwatson	}
165176139Srwatson	if (!VC_OPEN(&mi->mi_vcomm)) {
166176139Srwatson		MARK_INT_FAIL(CODA_MOUNT_STATS);
167176139Srwatson		return (ENODEV);
168176139Srwatson	}
16938625Srvb
170176139Srwatson	/*
171176139Srwatson	 * No initialization (here) of mi_vcomm!
172176139Srwatson	 */
173176139Srwatson	vfsp->mnt_data = mi;
174176139Srwatson	vfs_getnewfsid (vfsp);
175176139Srwatson	mi->mi_vfsp = vfsp;
176176139Srwatson	mi->mi_started = 0;			/* XXX See coda_root() */
17738625Srvb
178176139Srwatson	/*
179176139Srwatson	 * Make a root vnode to placate the Vnode interface, but don't
180176139Srwatson	 * actually make the CODA_ROOT call to venus until the first call to
181176139Srwatson	 * coda_root in case a server is down while venus is starting.
182176139Srwatson	 */
183176139Srwatson	cp = make_coda_node(&rootfid, vfsp, VDIR);
184176139Srwatson	rootvp = CTOV(cp);
185176139Srwatson	rootvp->v_vflag |= VV_ROOT;
186176139Srwatson	cp = make_coda_node(&ctlfid, vfsp, VREG);
187176139Srwatson	coda_ctlvp = CTOV(cp);
188176139Srwatson
189176139Srwatson	/*
190176139Srwatson	 * Add vfs and rootvp to chain of vfs hanging off mntinfo.
191176139Srwatson	 */
192176139Srwatson	mi->mi_vfsp = vfsp;
193176139Srwatson	mi->mi_rootvp = rootvp;
194176139Srwatson	vfs_mountedfrom(vfsp, from);
195176139Srwatson
196176139Srwatson	/*
197176139Srwatson	 * Error is currently guaranteed to be zero, but in case some code
198176139Srwatson	 * changes...
199176139Srwatson	 */
200176139Srwatson	CODADEBUG(1, myprintf(("coda_mount returned %d\n", error)););
201176139Srwatson	if (error)
202176139Srwatson		MARK_INT_FAIL(CODA_MOUNT_STATS);
203176139Srwatson	else
204176139Srwatson		MARK_INT_SAT(CODA_MOUNT_STATS);
205176139Srwatson	return (error);
20638625Srvb}
20738625Srvb
20838625Srvbint
209191990Sattiliocoda_unmount(struct mount *vfsp, int mntflags)
21038625Srvb{
211176139Srwatson	struct coda_mntinfo *mi = vftomi(vfsp);
212176139Srwatson	int active, error = 0;
21338625Srvb
214176139Srwatson	ENTRY;
215176139Srwatson	MARK_ENTRY(CODA_UMOUNT_STATS);
216176139Srwatson	if (!CODA_MOUNTED(vfsp)) {
217176139Srwatson		MARK_INT_FAIL(CODA_UMOUNT_STATS);
218176139Srwatson		return (EINVAL);
219176139Srwatson	}
220176139Srwatson	if (mi->mi_vfsp == vfsp) {
221176139Srwatson		/*
222176139Srwatson		 * We found the victim.
223176139Srwatson		 */
224176139Srwatson		if (!IS_UNMOUNTING(VTOC(mi->mi_rootvp)))
225176139Srwatson			return (EBUSY); 	/* Venus is still running */
226176139Srwatson#ifdef DEBUG
227176139Srwatson		printf("coda_unmount: ROOT: vp %p, cp %p\n", mi->mi_rootvp,
228176139Srwatson		    VTOC(mi->mi_rootvp));
22938625Srvb#endif
230176139Srwatson		vrele(mi->mi_rootvp);
231176139Srwatson		mi->mi_rootvp = NULL;
232176139Srwatson		vrele(coda_ctlvp);
233176139Srwatson		coda_ctlvp = NULL;
234176139Srwatson		active = coda_kill(vfsp, NOT_DOWNCALL);
235191990Sattilio		error = vflush(mi->mi_vfsp, 0, FORCECLOSE, curthread);
236120011Stjr#ifdef CODA_VERBOSE
237176139Srwatson		printf("coda_unmount: active = %d, vflush active %d\n",
238176139Srwatson		    active, error);
239120011Stjr#endif
240176139Srwatson		error = 0;
241176139Srwatson		/*
242176139Srwatson		 * I'm going to take this out to allow lookups to go through.
243176139Srwatson		 * I'm not sure it's important anyway. -- DCS 2/2/94
244176139Srwatson		 */
245176139Srwatson		/* vfsp->VFS_DATA = NULL; */
24638625Srvb
247176139Srwatson		/*
248176139Srwatson		 * No more vfsp's to hold onto.
249176139Srwatson		 */
250176139Srwatson		mi->mi_vfsp = NULL;
25138625Srvb
252176139Srwatson		if (error)
253176139Srwatson			MARK_INT_FAIL(CODA_UMOUNT_STATS);
254176139Srwatson		else
255176139Srwatson			MARK_INT_SAT(CODA_UMOUNT_STATS);
256176139Srwatson		return (error);
257176139Srwatson	}
258176139Srwatson	return (EINVAL);
25938625Srvb}
26038625Srvb
26138625Srvb/*
262176139Srwatson * Find root of cfs.
26338625Srvb */
26438625Srvbint
265191990Sattiliocoda_root(struct mount *vfsp, int flags, struct vnode **vpp)
26638625Srvb{
267176139Srwatson	struct coda_mntinfo *mi = vftomi(vfsp);
268176139Srwatson	int error;
269191990Sattilio	struct proc *p;
270191990Sattilio	struct thread *td;
271206210Srwatson	struct CodaFid VFid;
272206210Srwatson	static const struct CodaFid invalfid = INVAL_FID;
273176139Srwatson
274191990Sattilio	td = curthread;
275191990Sattilio	p = td->td_proc;
276176139Srwatson	ENTRY;
277176139Srwatson	MARK_ENTRY(CODA_ROOT_STATS);
278176139Srwatson	if (vfsp == mi->mi_vfsp) {
279176139Srwatson		/*
280176139Srwatson		 * Cache the root across calls.  We only need to pass the
281176139Srwatson		 * request on to Venus if the root vnode is the dummy we
282176139Srwatson		 * installed in coda_mount() with all c_fid members zeroed.
283176139Srwatson		 *
284176139Srwatson		 * XXX In addition, we assume that the first call to
285176139Srwatson		 * coda_root() is from vfs_mount() (before the call to
286176139Srwatson		 * checkdirs()) and return the dummy root node to avoid a
287176139Srwatson		 * deadlock.  This bug is fixed in the Coda CVS repository
288176139Srwatson		 * but not in any released versions as of 6 Mar 2003.
289176139Srwatson		 */
290176139Srwatson		if (memcmp(&VTOC(mi->mi_rootvp)->c_fid, &invalfid,
291206210Srwatson		    sizeof(struct CodaFid)) != 0 || mi->mi_started == 0) {
292176139Srwatson			/*
293176139Srwatson			 * Found valid root.
294176139Srwatson			 */
295176139Srwatson			*vpp = mi->mi_rootvp;
296176139Srwatson			mi->mi_started = 1;
297176139Srwatson
298176139Srwatson			/*
299176139Srwatson			 * On Mach, this is vref.  On FreeBSD, vref +
300176139Srwatson			 * vn_lock.
301176139Srwatson			 */
302176139Srwatson			vref(*vpp);
303176139Srwatson			vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
304176139Srwatson			MARK_INT_SAT(CODA_ROOT_STATS);
305176139Srwatson			return (0);
306176139Srwatson		}
307176139Srwatson	}
308176139Srwatson
309176139Srwatson	error = venus_root(vftomi(vfsp), td->td_ucred, p, &VFid);
310176139Srwatson	if (!error) {
311176139Srwatson		/*
312176139Srwatson		 * Save the new rootfid in the cnode, and rehash the cnode
313176139Srwatson		 * into the cnode hash with the new fid key.
314176139Srwatson		 */
315176139Srwatson		coda_unsave(VTOC(mi->mi_rootvp));
316176139Srwatson		VTOC(mi->mi_rootvp)->c_fid = VFid;
317176139Srwatson		coda_save(VTOC(mi->mi_rootvp));
31838625Srvb		*vpp = mi->mi_rootvp;
31938625Srvb		vref(*vpp);
320176121Srwatson		vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
32139085Srvb		MARK_INT_SAT(CODA_ROOT_STATS);
322176139Srwatson	} else if (error == ENODEV || error == EINTR) {
323176139Srwatson		/*
324176139Srwatson		 * Gross hack here!
325176139Srwatson		 *
326176139Srwatson		 * If Venus fails to respond to the CODA_ROOT call, coda_call
327176139Srwatson		 * returns ENODEV. Return the uninitialized root vnode to
328176139Srwatson		 * allow vfs operations such as unmount to continue.  Without
329176139Srwatson		 * this hack, there is no way to do an unmount if Venus dies
330176139Srwatson		 * before a successful CODA_ROOT call is done.  All vnode
331176139Srwatson		 * operations will fail.
332176139Srwatson		 */
333176139Srwatson		*vpp = mi->mi_rootvp;
334176139Srwatson		vref(*vpp);
335176139Srwatson		vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
336176139Srwatson		MARK_INT_FAIL(CODA_ROOT_STATS);
337176139Srwatson		error = 0;
338176139Srwatson	} else {
339176139Srwatson		CODADEBUG(CODA_ROOT, myprintf(("error %d in CODA_ROOT\n",
340176139Srwatson		    error)););
341176139Srwatson		MARK_INT_FAIL(CODA_ROOT_STATS);
342176139Srwatson	}
343176139Srwatson	return (error);
34438625Srvb}
34538625Srvb
34638625Srvb/*
34796755Strhodes * Get filesystem statistics.
34838625Srvb */
34938625Srvbint
350191990Sattiliocoda_statfs(struct mount *vfsp, struct statfs *sbp)
35138625Srvb{
352176139Srwatson
353176139Srwatson	ENTRY;
354176139Srwatson	MARK_ENTRY(CODA_STATFS_STATS);
355176139Srwatson	if (!CODA_MOUNTED(vfsp)) {
356176139Srwatson		MARK_INT_FAIL(CODA_STATFS_STATS);
357176139Srwatson		return (EINVAL);
358176139Srwatson	}
359176139Srwatson
360176139Srwatson	/*
361176139Srwatson	 * XXX - what to do about f_flags, others? --bnoble
362176139Srwatson	 *
363176139Srwatson	 * We just make up free space counts that are sufficiently large.
364176139Srwatson	 */
365176139Srwatson	sbp->f_flags = 0;
366176139Srwatson	sbp->f_bsize = 8192; /* XXX */
367176139Srwatson	sbp->f_iosize = 8192; /* XXX */
368176139Srwatson#define	CODA_SFS_SIZ	0x8AB75D
369176139Srwatson	sbp->f_blocks = CODA_SFS_SIZ;
370176139Srwatson	sbp->f_bfree = CODA_SFS_SIZ;
371176139Srwatson	sbp->f_bavail = CODA_SFS_SIZ;
372176139Srwatson	sbp->f_files = CODA_SFS_SIZ;
373176139Srwatson	sbp->f_ffree = CODA_SFS_SIZ;
374176139Srwatson	MARK_INT_SAT(CODA_STATFS_STATS);
375176139Srwatson	return (0);
37638625Srvb}
37738625Srvb
37838625Srvb/*
37938625Srvb * Flush any pending I/O.
38038625Srvb */
38138625Srvbint
382191990Sattiliocoda_sync(struct mount *vfsp, int waitfor)
38338625Srvb{
384176139Srwatson
385176139Srwatson	ENTRY;
386176139Srwatson	MARK_ENTRY(CODA_SYNC_STATS);
387176139Srwatson	MARK_INT_SAT(CODA_SYNC_STATS);
388176139Srwatson	return (0);
38938625Srvb}
39038625Srvb
391176139Srwatson/*
392176139Srwatson * fhtovp is now what vget used to be in 4.3-derived systems.  For some silly
393176139Srwatson * reason, vget is now keyed by a 32 bit ino_t, rather than a type-specific
394176139Srwatson * fid.
395176131Srwatson *
396176131Srwatson * XXX: coda_fhtovp is currently not hooked up, so no NFS export for Coda.
397176131Srwatson * We leave it here in the hopes that someone will find it someday and hook
398176131Srwatson * it up.  Among other things, it will need some reworking to match the
399176131Srwatson * vfs_fhtovp_t prototype.
40038625Srvb */
40138625Srvbint
402176139Srwatsoncoda_fhtovp(struct mount *vfsp, struct fid *fhp, struct mbuf *nam,
403176139Srwatson    struct vnode **vpp, int *exflagsp, struct ucred **creadanonp)
40438625Srvb{
405176139Srwatson	struct cfid *cfid = (struct cfid *)fhp;
406176139Srwatson	struct cnode *cp = NULL;
407176139Srwatson	int error;
408176139Srwatson	struct thread *td = curthread; /* XXX -mach */
409176139Srwatson	struct proc *p = td->td_proc;
410206210Srwatson	struct CodaFid VFid;
411176139Srwatson	int vtype;
41238625Srvb
413176139Srwatson	ENTRY;
414176139Srwatson	MARK_ENTRY(CODA_VGET_STATS);
415176139Srwatson
416176139Srwatson	/*
417176139Srwatson	 * Check for vget of control object.
418176139Srwatson	 */
419176139Srwatson	if (IS_CTL_FID(&cfid->cfid_fid)) {
420176139Srwatson		*vpp = coda_ctlvp;
421176139Srwatson		vref(coda_ctlvp);
422176139Srwatson		MARK_INT_SAT(CODA_VGET_STATS);
423176139Srwatson		return (0);
424176139Srwatson	}
425176139Srwatson	error = venus_fhtovp(vftomi(vfsp), &cfid->cfid_fid, td->td_ucred, p,
426176139Srwatson	    &VFid, &vtype);
427176139Srwatson	if (error) {
428176139Srwatson		CODADEBUG(CODA_VGET, myprintf(("vget error %d\n",error)););
429176139Srwatson		*vpp = NULL;
430176139Srwatson	} else {
431176139Srwatson		CODADEBUG(CODA_VGET, myprintf(("vget: %s type %d result "
432176139Srwatson		    "%d\n", coda_f2s(&VFid), vtype, error)););
433176139Srwatson		cp = make_coda_node(&VFid, vfsp, vtype);
434176139Srwatson		*vpp = CTOV(cp);
435176139Srwatson	}
436176139Srwatson	return (error);
43738625Srvb}
43838625Srvb
43939650Srvbstruct vfsops coda_vfsops = {
440176139Srwatson	.vfs_mount =		coda_mount,
441176139Srwatson	.vfs_root = 		coda_root,
442176139Srwatson	.vfs_statfs =		coda_statfs,
443176139Srwatson	.vfs_sync = 		coda_sync,
444176139Srwatson	.vfs_unmount =		coda_unmount,
44539650Srvb};
44639650SrvbVFS_SET(coda_vfsops, coda, VFCF_NETWORK);
447