xref: /netbsd-src/sys/ufs/mfs/mfs_vfsops.c (revision de1dfb1250df962f1ff3a011772cf58e605aed11)
1 /*	$NetBSD: mfs_vfsops.c,v 1.61 2004/07/05 07:28:46 pk 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. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  *	@(#)mfs_vfsops.c	8.11 (Berkeley) 6/19/95
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: mfs_vfsops.c,v 1.61 2004/07/05 07:28:46 pk Exp $");
36 
37 #if defined(_KERNEL_OPT)
38 #include "opt_compat_netbsd.h"
39 #endif
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/sysctl.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 <miscfs/syncfs/syncfs.h>
54 
55 #include <ufs/ufs/quota.h>
56 #include <ufs/ufs/inode.h>
57 #include <ufs/ufs/ufsmount.h>
58 #include <ufs/ufs/ufs_extern.h>
59 
60 #include <ufs/ffs/fs.h>
61 #include <ufs/ffs/ffs_extern.h>
62 
63 #include <ufs/mfs/mfsnode.h>
64 #include <ufs/mfs/mfs_extern.h>
65 
66 caddr_t	mfs_rootbase;	/* address of mini-root in kernel virtual memory */
67 u_long	mfs_rootsize;	/* size of mini-root in bytes */
68 
69 static	int mfs_minor;	/* used for building internal dev_t */
70 
71 extern int (**mfs_vnodeop_p) __P((void *));
72 
73 MALLOC_DEFINE(M_MFSNODE, "MFS node", "MFS vnode private part");
74 
75 /*
76  * mfs vfs operations.
77  */
78 
79 extern const struct vnodeopv_desc mfs_vnodeop_opv_desc;
80 
81 const struct vnodeopv_desc * const mfs_vnodeopv_descs[] = {
82 	&mfs_vnodeop_opv_desc,
83 	NULL,
84 };
85 
86 struct vfsops mfs_vfsops = {
87 	MOUNT_MFS,
88 	mfs_mount,
89 	mfs_start,
90 	ffs_unmount,
91 	ufs_root,
92 	ufs_quotactl,
93 	mfs_statvfs,
94 	ffs_sync,
95 	ffs_vget,
96 	ffs_fhtovp,
97 	ffs_vptofh,
98 	mfs_init,
99 	mfs_reinit,
100 	mfs_done,
101 	NULL,
102 	NULL,
103 	ufs_check_export,
104 	(int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
105 	mfs_vnodeopv_descs,
106 };
107 
108 SYSCTL_SETUP(sysctl_vfs_mfs_setup, "sysctl vfs.mfs subtree setup")
109 {
110 
111 	sysctl_createv(clog, 0, NULL, NULL,
112 		       CTLFLAG_PERMANENT,
113 		       CTLTYPE_NODE, "vfs", NULL,
114 		       NULL, 0, NULL, 0,
115 		       CTL_VFS, CTL_EOL);
116 	sysctl_createv(clog, 0, NULL, NULL,
117 		       CTLFLAG_PERMANENT|CTLFLAG_ALIAS,
118 		       CTLTYPE_NODE, "mfs",
119 		       SYSCTL_DESCR("Memory based file system"),
120 		       NULL, 1, NULL, 0,
121 		       CTL_VFS, 3, CTL_EOL);
122 	/*
123 	 * XXX the "1" and the "3" above could be dynamic, thereby
124 	 * eliminating one more instance of the "number to vfs"
125 	 * mapping problem, but they are in order as taken from
126 	 * sys/mount.h
127 	 */
128 }
129 
130 /*
131  * Memory based filesystem initialization.
132  */
133 void
134 mfs_init()
135 {
136 #ifdef _LKM
137 	malloc_type_attach(M_MFSNODE);
138 #endif
139 	/*
140 	 * ffs_init() ensures to initialize necessary resources
141 	 * only once.
142 	 */
143 	ffs_init();
144 }
145 
146 void
147 mfs_reinit()
148 {
149 	ffs_reinit();
150 }
151 
152 void
153 mfs_done()
154 {
155 	/*
156 	 * ffs_done() ensures to free necessary resources
157 	 * only once, when it's no more needed.
158 	 */
159 	ffs_done();
160 #ifdef _LKM
161 	malloc_type_detach(M_MFSNODE);
162 #endif
163 }
164 
165 /*
166  * Called by main() when mfs is going to be mounted as root.
167  */
168 
169 int
170 mfs_mountroot()
171 {
172 	struct fs *fs;
173 	struct mount *mp;
174 	struct proc *p = curproc;	/* XXX */
175 	struct ufsmount *ump;
176 	struct mfsnode *mfsp;
177 	int error = 0;
178 
179 	/*
180 	 * Get vnodes for rootdev.
181 	 */
182 	if (bdevvp(rootdev, &rootvp)) {
183 		printf("mfs_mountroot: can't setup bdevvp's");
184 		return (error);
185 	}
186 
187 	if ((error = vfs_rootmountalloc(MOUNT_MFS, "mfs_root", &mp))) {
188 		vrele(rootvp);
189 		return (error);
190 	}
191 
192 	mfsp = malloc(sizeof *mfsp, M_MFSNODE, M_WAITOK);
193 	rootvp->v_data = mfsp;
194 	rootvp->v_op = mfs_vnodeop_p;
195 	rootvp->v_tag = VT_MFS;
196 	mfsp->mfs_baseoff = mfs_rootbase;
197 	mfsp->mfs_size = mfs_rootsize;
198 	mfsp->mfs_vnode = rootvp;
199 	mfsp->mfs_proc = NULL;		/* indicate kernel space */
200 	mfsp->mfs_shutdown = 0;
201 	bufq_alloc(&mfsp->mfs_buflist, BUFQ_FCFS);
202 	if ((error = ffs_mountfs(rootvp, mp, p)) != 0) {
203 		mp->mnt_op->vfs_refcount--;
204 		vfs_unbusy(mp);
205 		bufq_free(&mfsp->mfs_buflist);
206 		free(mp, M_MOUNT);
207 		free(mfsp, M_MFSNODE);
208 		vrele(rootvp);
209 		return (error);
210 	}
211 	simple_lock(&mountlist_slock);
212 	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
213 	simple_unlock(&mountlist_slock);
214 	mp->mnt_vnodecovered = NULLVP;
215 	ump = VFSTOUFS(mp);
216 	fs = ump->um_fs;
217 	(void) copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0);
218 	(void)ffs_statvfs(mp, &mp->mnt_stat, p);
219 	vfs_unbusy(mp);
220 	return (0);
221 }
222 
223 /*
224  * This is called early in boot to set the base address and size
225  * of the mini-root.
226  */
227 int
228 mfs_initminiroot(base)
229 	caddr_t base;
230 {
231 	struct fs *fs = (struct fs *)(base + SBLOCK_UFS1);
232 
233 	/* check for valid super block */
234 	if (fs->fs_magic != FS_UFS1_MAGIC || fs->fs_bsize > MAXBSIZE ||
235 	    fs->fs_bsize < sizeof(struct fs))
236 		return (0);
237 	mountroot = mfs_mountroot;
238 	mfs_rootbase = base;
239 	mfs_rootsize = fs->fs_fsize * fs->fs_size;
240 	rootdev = makedev(255, mfs_minor);
241 	mfs_minor++;
242 	return (mfs_rootsize);
243 }
244 
245 /*
246  * VFS Operations.
247  *
248  * mount system call
249  */
250 /* ARGSUSED */
251 int
252 mfs_mount(mp, path, data, ndp, p)
253 	struct mount *mp;
254 	const char *path;
255 	void *data;
256 	struct nameidata *ndp;
257 	struct proc *p;
258 {
259 	struct vnode *devvp;
260 	struct mfs_args args;
261 	struct ufsmount *ump;
262 	struct fs *fs;
263 	struct mfsnode *mfsp;
264 	int flags, error;
265 
266 	if (mp->mnt_flag & MNT_GETARGS) {
267 		struct vnode *vp;
268 		struct mfsnode *mfsp;
269 
270 		ump = VFSTOUFS(mp);
271 		if (ump == NULL)
272 			return EIO;
273 
274 		vp = ump->um_devvp;
275 		if (vp == NULL)
276 			return EIO;
277 
278 		mfsp = VTOMFS(vp);
279 		if (mfsp == NULL)
280 			return EIO;
281 
282 		args.fspec = NULL;
283 		vfs_showexport(mp, &args.export, &ump->um_export);
284 		args.base = mfsp->mfs_baseoff;
285 		args.size = mfsp->mfs_size;
286 		return copyout(&args, data, sizeof(args));
287 	}
288 	/*
289 	 * XXX turn off async to avoid hangs when writing lots of data.
290 	 * the problem is that MFS needs to allocate pages to clean pages,
291 	 * so if we wait until the last minute to clean pages then there
292 	 * may not be any pages available to do the cleaning.
293 	 * ... and since the default partially-synchronous mode turns out
294 	 * to not be sufficient under heavy load, make it full synchronous.
295 	 */
296 	mp->mnt_flag &= ~MNT_ASYNC;
297 	mp->mnt_flag |= MNT_SYNCHRONOUS;
298 
299 	error = copyin(data, (caddr_t)&args, sizeof (struct mfs_args));
300 	if (error)
301 		return (error);
302 
303 	/*
304 	 * If updating, check whether changing from read-only to
305 	 * read/write; if there is no device name, that's all we do.
306 	 */
307 	if (mp->mnt_flag & MNT_UPDATE) {
308 		ump = VFSTOUFS(mp);
309 		fs = ump->um_fs;
310 		if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
311 			flags = WRITECLOSE;
312 			if (mp->mnt_flag & MNT_FORCE)
313 				flags |= FORCECLOSE;
314 			error = ffs_flushfiles(mp, flags, p);
315 			if (error)
316 				return (error);
317 		}
318 		if (fs->fs_ronly && (mp->mnt_iflag & IMNT_WANTRDWR))
319 			fs->fs_ronly = 0;
320 		if (args.fspec == 0)
321 			return (vfs_export(mp, &ump->um_export, &args.export));
322 		return (0);
323 	}
324 	error = getnewvnode(VT_MFS, (struct mount *)0, mfs_vnodeop_p, &devvp);
325 	if (error)
326 		return (error);
327 	devvp->v_type = VBLK;
328 	if (checkalias(devvp, makedev(255, mfs_minor), (struct mount *)0))
329 		panic("mfs_mount: dup dev");
330 	mfs_minor++;
331 	mfsp = (struct mfsnode *)malloc(sizeof *mfsp, M_MFSNODE, M_WAITOK);
332 	devvp->v_data = mfsp;
333 	mfsp->mfs_baseoff = args.base;
334 	mfsp->mfs_size = args.size;
335 	mfsp->mfs_vnode = devvp;
336 	mfsp->mfs_proc = p;
337 	mfsp->mfs_shutdown = 0;
338 	bufq_alloc(&mfsp->mfs_buflist, BUFQ_FCFS);
339 	if ((error = ffs_mountfs(devvp, mp, p)) != 0) {
340 		mfsp->mfs_shutdown = 1;
341 		vrele(devvp);
342 		return (error);
343 	}
344 	ump = VFSTOUFS(mp);
345 	fs = ump->um_fs;
346 	error = set_statvfs_info(path, UIO_USERSPACE, args.fspec,
347 	    UIO_USERSPACE, mp, p);
348 	if (error)
349 		return error;
350 	(void)strncpy(fs->fs_fsmnt, mp->mnt_stat.f_mntonname,
351 		sizeof(fs->fs_fsmnt));
352 	fs->fs_fsmnt[sizeof(fs->fs_fsmnt) - 1] = '\0';
353 	/* XXX: cleanup on error */
354 	return 0;
355 }
356 
357 int	mfs_pri = PWAIT | PCATCH;		/* XXX prob. temp */
358 
359 /*
360  * Used to grab the process and keep it in the kernel to service
361  * memory filesystem I/O requests.
362  *
363  * Loop servicing I/O requests.
364  * Copy the requested data into or out of the memory filesystem
365  * address space.
366  */
367 /* ARGSUSED */
368 int
369 mfs_start(mp, flags, p)
370 	struct mount *mp;
371 	int flags;
372 	struct proc *p;
373 {
374 	struct vnode *vp = VFSTOUFS(mp)->um_devvp;
375 	struct mfsnode *mfsp = VTOMFS(vp);
376 	struct buf *bp;
377 	caddr_t base;
378 	int sleepreturn = 0;
379 	struct lwp *l; /* XXX NJWLWP */
380 
381 	/* XXX NJWLWP the vnode interface again gives us a proc in a
382 	 * place where we want a execution context. Cheat.
383 	 */
384 	KASSERT(curproc == p);
385 	l = curlwp;
386 	base = mfsp->mfs_baseoff;
387 	while (mfsp->mfs_shutdown != 1) {
388 		while ((bp = BUFQ_GET(&mfsp->mfs_buflist)) != NULL) {
389 			mfs_doio(bp, base);
390 			wakeup((caddr_t)bp);
391 		}
392 		/*
393 		 * If a non-ignored signal is received, try to unmount.
394 		 * If that fails, or the filesystem is already in the
395 		 * process of being unmounted, clear the signal (it has been
396 		 * "processed"), otherwise we will loop here, as tsleep
397 		 * will always return EINTR/ERESTART.
398 		 */
399 		if (sleepreturn != 0) {
400 			/*
401 			 * XXX Freeze syncer.  Must do this before locking
402 			 * the mount point.  See dounmount() for details.
403 			 */
404 			lockmgr(&syncer_lock, LK_EXCLUSIVE, NULL);
405 			if (vfs_busy(mp, LK_NOWAIT, 0) != 0)
406 				lockmgr(&syncer_lock, LK_RELEASE, NULL);
407 			else if (dounmount(mp, 0, p) != 0)
408 				CLRSIG(p, CURSIG(l));
409 			sleepreturn = 0;
410 			continue;
411 		}
412 
413 		sleepreturn = tsleep(vp, mfs_pri, "mfsidl", 0);
414 	}
415 	KASSERT(BUFQ_PEEK(&mfsp->mfs_buflist) == NULL);
416 	bufq_free(&mfsp->mfs_buflist);
417 	return (sleepreturn);
418 }
419 
420 /*
421  * Get file system statistics.
422  */
423 int
424 mfs_statvfs(mp, sbp, p)
425 	struct mount *mp;
426 	struct statvfs *sbp;
427 	struct proc *p;
428 {
429 	int error;
430 
431 	error = ffs_statvfs(mp, sbp, p);
432 	if (error)
433 		return error;
434 	(void)strncpy(sbp->f_fstypename, mp->mnt_op->vfs_name,
435 	    sizeof(sbp->f_fstypename));
436 	sbp->f_fstypename[sizeof(sbp->f_fstypename) - 1] = '\0';
437 	return 0;
438 }
439