mfs_vfsops.c revision 1.23
1/*	$NetBSD: mfs_vfsops.c,v 1.23 2000/03/16 18:20:07 jdolecek Exp $	*/
2
3/*
4 * Copyright (c) 1989, 1990, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *	@(#)mfs_vfsops.c	8.11 (Berkeley) 6/19/95
36 */
37
38#if defined(_KERNEL) && !defined(_LKM)
39#include "opt_compat_netbsd.h"
40#endif
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/time.h>
45#include <sys/kernel.h>
46#include <sys/proc.h>
47#include <sys/buf.h>
48#include <sys/mount.h>
49#include <sys/signalvar.h>
50#include <sys/vnode.h>
51#include <sys/malloc.h>
52
53#include <ufs/ufs/quota.h>
54#include <ufs/ufs/inode.h>
55#include <ufs/ufs/ufsmount.h>
56#include <ufs/ufs/ufs_extern.h>
57
58#include <ufs/ffs/fs.h>
59#include <ufs/ffs/ffs_extern.h>
60
61#include <ufs/mfs/mfsnode.h>
62#include <ufs/mfs/mfs_extern.h>
63
64caddr_t	mfs_rootbase;	/* address of mini-root in kernel virtual memory */
65u_long	mfs_rootsize;	/* size of mini-root in bytes */
66
67static	int mfs_minor;	/* used for building internal dev_t */
68
69extern int (**mfs_vnodeop_p) __P((void *));
70
71/*
72 * mfs vfs operations.
73 */
74
75extern struct vnodeopv_desc mfs_vnodeop_opv_desc;
76
77struct vnodeopv_desc *mfs_vnodeopv_descs[] = {
78	&mfs_vnodeop_opv_desc,
79	NULL,
80};
81
82struct vfsops mfs_vfsops = {
83	MOUNT_MFS,
84	mfs_mount,
85	mfs_start,
86	ffs_unmount,
87	ufs_root,
88	ufs_quotactl,
89	mfs_statfs,
90	ffs_sync,
91	ffs_vget,
92	ffs_fhtovp,
93	ffs_vptofh,
94	mfs_init,
95	mfs_done,
96	ffs_sysctl,
97	NULL,
98	ufs_check_export,
99	mfs_vnodeopv_descs,
100};
101
102/*
103 * Memory based filesystem initialization.
104 */
105void
106mfs_init()
107{
108	/*
109	 * ffs_init() ensures to initialize necessary resources
110	 * only once.
111	 */
112	ffs_init();
113}
114
115void
116mfs_done()
117{
118	/*
119	 * ffs_done() ensures to free necessary resources
120	 * only once, when it's no more needed.
121	 */
122	ffs_done();
123}
124
125/*
126 * Called by main() when mfs is going to be mounted as root.
127 */
128
129int
130mfs_mountroot()
131{
132	extern struct vnode *rootvp;
133	struct fs *fs;
134	struct mount *mp;
135	struct proc *p = curproc;	/* XXX */
136	struct ufsmount *ump;
137	struct mfsnode *mfsp;
138	int error = 0;
139
140	/*
141	 * Get vnodes for rootdev.
142	 */
143	if (bdevvp(rootdev, &rootvp)) {
144		printf("mfs_mountroot: can't setup bdevvp's");
145		return (error);
146	}
147
148	if ((error = vfs_rootmountalloc(MOUNT_MFS, "mfs_root", &mp))) {
149		vrele(rootvp);
150		return (error);
151	}
152
153	mfsp = malloc(sizeof *mfsp, M_MFSNODE, M_WAITOK);
154	rootvp->v_data = mfsp;
155	rootvp->v_op = mfs_vnodeop_p;
156	rootvp->v_tag = VT_MFS;
157	mfsp->mfs_baseoff = mfs_rootbase;
158	mfsp->mfs_size = mfs_rootsize;
159	mfsp->mfs_vnode = rootvp;
160	mfsp->mfs_pid = p->p_pid;
161	BUFQ_INIT(&mfsp->mfs_buflist);
162	if ((error = ffs_mountfs(rootvp, mp, p)) != 0) {
163		mp->mnt_op->vfs_refcount--;
164		vfs_unbusy(mp);
165		free(mp, M_MOUNT);
166		free(mfsp, M_MFSNODE);
167		vrele(rootvp);
168		return (error);
169	}
170	simple_lock(&mountlist_slock);
171	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
172	simple_unlock(&mountlist_slock);
173	mp->mnt_vnodecovered = NULLVP;
174	ump = VFSTOUFS(mp);
175	fs = ump->um_fs;
176	(void) copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0);
177	(void)ffs_statfs(mp, &mp->mnt_stat, p);
178	vfs_unbusy(mp);
179	inittodr((time_t)0);
180	return (0);
181}
182
183/*
184 * This is called early in boot to set the base address and size
185 * of the mini-root.
186 */
187int
188mfs_initminiroot(base)
189	caddr_t base;
190{
191	struct fs *fs = (struct fs *)(base + SBOFF);
192	extern int (*mountroot) __P((void));
193
194	/* check for valid super block */
195	if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
196	    fs->fs_bsize < sizeof(struct fs))
197		return (0);
198	mountroot = mfs_mountroot;
199	mfs_rootbase = base;
200	mfs_rootsize = fs->fs_fsize * fs->fs_size;
201	rootdev = makedev(255, mfs_minor++);
202	return (mfs_rootsize);
203}
204
205/*
206 * VFS Operations.
207 *
208 * mount system call
209 */
210/* ARGSUSED */
211int
212mfs_mount(mp, path, data, ndp, p)
213	register struct mount *mp;
214	const char *path;
215	void *data;
216	struct nameidata *ndp;
217	struct proc *p;
218{
219	struct vnode *devvp;
220	struct mfs_args args;
221	struct ufsmount *ump;
222	register struct fs *fs;
223	register struct mfsnode *mfsp;
224	size_t size;
225	int flags, error;
226
227	error = copyin(data, (caddr_t)&args, sizeof (struct mfs_args));
228	if (error)
229		return (error);
230
231	/*
232	 * If updating, check whether changing from read-only to
233	 * read/write; if there is no device name, that's all we do.
234	 */
235	if (mp->mnt_flag & MNT_UPDATE) {
236		ump = VFSTOUFS(mp);
237		fs = ump->um_fs;
238		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
239			flags = WRITECLOSE;
240			if (mp->mnt_flag & MNT_FORCE)
241				flags |= FORCECLOSE;
242			error = ffs_flushfiles(mp, flags, p);
243			if (error)
244				return (error);
245		}
246		if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR))
247			fs->fs_ronly = 0;
248		if (args.fspec == 0)
249			return (vfs_export(mp, &ump->um_export, &args.export));
250		return (0);
251	}
252	error = getnewvnode(VT_MFS, (struct mount *)0, mfs_vnodeop_p, &devvp);
253	if (error)
254		return (error);
255	devvp->v_type = VBLK;
256	if (checkalias(devvp, makedev(255, mfs_minor++), (struct mount *)0))
257		panic("mfs_mount: dup dev");
258	mfsp = (struct mfsnode *)malloc(sizeof *mfsp, M_MFSNODE, M_WAITOK);
259	devvp->v_data = mfsp;
260	mfsp->mfs_baseoff = args.base;
261	mfsp->mfs_size = args.size;
262	mfsp->mfs_vnode = devvp;
263	mfsp->mfs_pid = p->p_pid;
264	BUFQ_INIT(&mfsp->mfs_buflist);
265	if ((error = ffs_mountfs(devvp, mp, p)) != 0) {
266		BUFQ_FIRST(&mfsp->mfs_buflist) = (struct buf *) -1;
267		vrele(devvp);
268		return (error);
269	}
270	ump = VFSTOUFS(mp);
271	fs = ump->um_fs;
272	(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
273	memset(fs->fs_fsmnt + size, 0, sizeof(fs->fs_fsmnt) - size);
274	memcpy(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN);
275	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
276	    &size);
277	memset(mp->mnt_stat.f_mntfromname + size, 0, MNAMELEN - size);
278	return (0);
279}
280
281int	mfs_pri = PWAIT | PCATCH;		/* XXX prob. temp */
282
283/*
284 * Used to grab the process and keep it in the kernel to service
285 * memory filesystem I/O requests.
286 *
287 * Loop servicing I/O requests.
288 * Copy the requested data into or out of the memory filesystem
289 * address space.
290 */
291/* ARGSUSED */
292int
293mfs_start(mp, flags, p)
294	struct mount *mp;
295	int flags;
296	struct proc *p;
297{
298	register struct vnode *vp = VFSTOUFS(mp)->um_devvp;
299	register struct mfsnode *mfsp = VTOMFS(vp);
300	register struct buf *bp;
301	register caddr_t base;
302	int sleepreturn = 0;
303
304	base = mfsp->mfs_baseoff;
305	while (BUFQ_FIRST(&mfsp->mfs_buflist) != (struct buf *) -1) {
306		/*
307		 * If a non-ignored signal is received, try to unmount.
308		 * If that fails, or the filesystem is already in the
309		 * process of being unmounted, clear the signal (it has been
310		 * "processed"), otherwise we will loop here, as tsleep
311		 * will always return EINTR/ERESTART.
312		 */
313		if (sleepreturn != 0) {
314			if (vfs_busy(mp, LK_NOWAIT, 0) ||
315			    dounmount(mp, 0, p) != 0)
316				CLRSIG(p, CURSIG(p));
317			sleepreturn = 0;
318			continue;
319		}
320
321		while ((bp = BUFQ_FIRST(&mfsp->mfs_buflist)) != NULL) {
322			BUFQ_REMOVE(&mfsp->mfs_buflist, bp);
323			mfs_doio(bp, base);
324			wakeup((caddr_t)bp);
325		}
326		sleepreturn = tsleep(vp, mfs_pri, "mfsidl", 0);
327	}
328	return (sleepreturn);
329}
330
331/*
332 * Get file system statistics.
333 */
334int
335mfs_statfs(mp, sbp, p)
336	struct mount *mp;
337	struct statfs *sbp;
338	struct proc *p;
339{
340	int error;
341
342	error = ffs_statfs(mp, sbp, p);
343#ifdef COMPAT_09
344	sbp->f_type = 3;
345#else
346	sbp->f_type = 0;
347#endif
348	strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
349	return (error);
350}
351