1 /* $NetBSD: mfs_vfsops.c,v 1.100 2008/12/19 17:11:57 pgoyette Exp $ */
4 * Copyright (c) 1989, 1990, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
31 * @(#)mfs_vfsops.c 8.11 (Berkeley) 6/19/95
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: mfs_vfsops.c,v 1.100 2008/12/19 17:11:57 pgoyette Exp $");
37 #if defined(_KERNEL_OPT)
38 #include "opt_compat_netbsd.h"
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/sysctl.h>
45 #include <sys/kernel.h>
49 #include <sys/mount.h>
50 #include <sys/signalvar.h>
51 #include <sys/vnode.h>
53 #include <sys/module.h>
55 #include <miscfs/genfs/genfs.h>
56 #include <miscfs/specfs/specdev.h>
58 #include <ufs/ufs/quota.h>
59 #include <ufs/ufs/inode.h>
60 #include <ufs/ufs/ufsmount.h>
61 #include <ufs/ufs/ufs_extern.h>
63 #include <ufs/ffs/fs.h>
64 #include <ufs/ffs/ffs_extern.h>
66 #include <ufs/mfs/mfsnode.h>
67 #include <ufs/mfs/mfs_extern.h>
69 MODULE(MODULE_CLASS_VFS
, mfs
, "ffs");
71 void * mfs_rootbase
; /* address of mini-root in kernel virtual memory */
72 u_long mfs_rootsize
; /* size of mini-root in bytes */
73 kmutex_t mfs_lock
; /* global lock */
75 static int mfs_minor
; /* used for building internal dev_t */
76 static int mfs_initcnt
;
78 extern int (**mfs_vnodeop_p
)(void *);
80 static struct sysctllog
*mfs_sysctl_log
;
86 extern const struct vnodeopv_desc mfs_vnodeop_opv_desc
;
88 const struct vnodeopv_desc
* const mfs_vnodeopv_descs
[] = {
89 &mfs_vnodeop_opv_desc
,
93 struct vfsops mfs_vfsops
= {
95 sizeof (struct mfs_args
),
110 (int (*)(struct mount
*, struct vnode
*, struct timespec
*)) eopnotsupp
,
112 (void *)eopnotsupp
, /* vfs_suspendctl */
113 genfs_renamelock_enter
,
114 genfs_renamelock_exit
,
122 mfs_modcmd(modcmd_t cmd
, void *arg
)
127 case MODULE_CMD_INIT
:
128 error
= vfs_attach(&mfs_vfsops
);
131 sysctl_createv(&mfs_sysctl_log
, 0, NULL
, NULL
,
133 CTLTYPE_NODE
, "vfs", NULL
,
136 sysctl_createv(&mfs_sysctl_log
, 0, NULL
, NULL
,
137 CTLFLAG_PERMANENT
|CTLFLAG_ALIAS
,
139 SYSCTL_DESCR("Memory based file system"),
141 CTL_VFS
, 3, CTL_EOL
);
143 * XXX the "1" and the "3" above could be dynamic, thereby
144 * eliminating one more instance of the "number to vfs"
145 * mapping problem, but they are in order as taken from
149 case MODULE_CMD_FINI
:
150 error
= vfs_detach(&mfs_vfsops
);
153 sysctl_teardown(&mfs_sysctl_log
);
164 * Memory based filesystem initialization.
170 if (mfs_initcnt
++ == 0) {
171 mutex_init(&mfs_lock
, MUTEX_DEFAULT
, IPL_NONE
);
187 if (--mfs_initcnt
== 0) {
189 mutex_destroy(&mfs_lock
);
194 * Called by main() when mfs is going to be mounted as root.
202 struct lwp
*l
= curlwp
; /* XXX */
203 struct ufsmount
*ump
;
204 struct mfsnode
*mfsp
;
207 if ((error
= vfs_rootmountalloc(MOUNT_MFS
, "mfs_root", &mp
))) {
212 mfsp
= kmem_alloc(sizeof(*mfsp
), KM_SLEEP
);
213 rootvp
->v_data
= mfsp
;
214 rootvp
->v_op
= mfs_vnodeop_p
;
215 rootvp
->v_tag
= VT_MFS
;
216 mfsp
->mfs_baseoff
= mfs_rootbase
;
217 mfsp
->mfs_size
= mfs_rootsize
;
218 mfsp
->mfs_vnode
= rootvp
;
219 mfsp
->mfs_proc
= NULL
; /* indicate kernel space */
220 mfsp
->mfs_shutdown
= 0;
221 cv_init(&mfsp
->mfs_cv
, "mfs");
222 mfsp
->mfs_refcnt
= 1;
223 bufq_alloc(&mfsp
->mfs_buflist
, "fcfs", 0);
224 if ((error
= ffs_mountfs(rootvp
, mp
, l
)) != 0) {
225 vfs_unbusy(mp
, false, NULL
);
226 bufq_free(mfsp
->mfs_buflist
);
228 kmem_free(mfsp
, sizeof(*mfsp
));
231 mutex_enter(&mountlist_lock
);
232 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
233 mutex_exit(&mountlist_lock
);
234 mp
->mnt_vnodecovered
= NULLVP
;
237 (void) copystr(mp
->mnt_stat
.f_mntonname
, fs
->fs_fsmnt
, MNAMELEN
- 1, 0);
238 (void)ffs_statvfs(mp
, &mp
->mnt_stat
);
239 vfs_unbusy(mp
, false, NULL
);
244 * This is called early in boot to set the base address and size
248 mfs_initminiroot(void *base
)
250 struct fs
*fs
= (struct fs
*)((char *)base
+ SBLOCK_UFS1
);
252 /* check for valid super block */
253 if (fs
->fs_magic
!= FS_UFS1_MAGIC
|| fs
->fs_bsize
> MAXBSIZE
||
254 fs
->fs_bsize
< sizeof(struct fs
))
256 rootfstype
= MOUNT_MFS
;
258 mfs_rootsize
= fs
->fs_fsize
* fs
->fs_size
;
259 rootdev
= makedev(255, mfs_minor
);
261 return (mfs_rootsize
);
271 mfs_mount(struct mount
*mp
, const char *path
, void *data
, size_t *data_len
)
273 struct lwp
*l
= curlwp
;
275 struct mfs_args
*args
= data
;
276 struct ufsmount
*ump
;
278 struct mfsnode
*mfsp
;
280 int flags
, error
= 0;
282 if (*data_len
< sizeof *args
)
286 if (mp
->mnt_flag
& MNT_GETARGS
) {
302 args
->base
= mfsp
->mfs_baseoff
;
303 args
->size
= mfsp
->mfs_size
;
304 *data_len
= sizeof *args
;
308 * XXX turn off async to avoid hangs when writing lots of data.
309 * the problem is that MFS needs to allocate pages to clean pages,
310 * so if we wait until the last minute to clean pages then there
311 * may not be any pages available to do the cleaning.
312 * ... and since the default partially-synchronous mode turns out
313 * to not be sufficient under heavy load, make it full synchronous.
315 mp
->mnt_flag
&= ~MNT_ASYNC
;
316 mp
->mnt_flag
|= MNT_SYNCHRONOUS
;
319 * If updating, check whether changing from read-only to
320 * read/write; if there is no device name, that's all we do.
322 if (mp
->mnt_flag
& MNT_UPDATE
) {
325 if (fs
->fs_ronly
== 0 && (mp
->mnt_flag
& MNT_RDONLY
)) {
327 if (mp
->mnt_flag
& MNT_FORCE
)
329 error
= ffs_flushfiles(mp
, flags
, l
);
333 if (fs
->fs_ronly
&& (mp
->mnt_iflag
& IMNT_WANTRDWR
))
335 if (args
->fspec
== NULL
)
339 error
= getnewvnode(VT_MFS
, (struct mount
*)0, mfs_vnodeop_p
, &devvp
);
342 devvp
->v_vflag
|= VV_MPSAFE
;
343 devvp
->v_type
= VBLK
;
344 spec_node_init(devvp
, makedev(255, mfs_minor
));
346 mfsp
= kmem_alloc(sizeof(*mfsp
), KM_SLEEP
);
347 devvp
->v_data
= mfsp
;
348 mfsp
->mfs_baseoff
= args
->base
;
349 mfsp
->mfs_size
= args
->size
;
350 mfsp
->mfs_vnode
= devvp
;
352 mfsp
->mfs_shutdown
= 0;
353 cv_init(&mfsp
->mfs_cv
, "mfsidl");
354 mfsp
->mfs_refcnt
= 1;
355 bufq_alloc(&mfsp
->mfs_buflist
, "fcfs", 0);
356 if ((error
= ffs_mountfs(devvp
, mp
, l
)) != 0) {
357 mfsp
->mfs_shutdown
= 1;
363 error
= set_statvfs_info(path
, UIO_USERSPACE
, args
->fspec
,
364 UIO_USERSPACE
, mp
->mnt_op
->vfs_name
, mp
, l
);
367 (void)strncpy(fs
->fs_fsmnt
, mp
->mnt_stat
.f_mntonname
,
368 sizeof(fs
->fs_fsmnt
));
369 fs
->fs_fsmnt
[sizeof(fs
->fs_fsmnt
) - 1] = '\0';
370 /* XXX: cleanup on error */
375 * Used to grab the process and keep it in the kernel to service
376 * memory filesystem I/O requests.
378 * Loop servicing I/O requests.
379 * Copy the requested data into or out of the memory filesystem
384 mfs_start(struct mount
*mp
, int flags
)
387 struct mfsnode
*mfsp
;
391 int sleepreturn
= 0, refcnt
, error
;
395 * Ensure that file system is still mounted when getting mfsnode.
396 * Add a reference to the mfsnode to prevent it disappearing in
399 if ((error
= vfs_busy(mp
, NULL
)) != 0)
401 vp
= VFSTOUFS(mp
)->um_devvp
;
403 mutex_enter(&mfs_lock
);
405 mutex_exit(&mfs_lock
);
406 vfs_unbusy(mp
, false, NULL
);
408 base
= mfsp
->mfs_baseoff
;
409 mutex_enter(&mfs_lock
);
410 while (mfsp
->mfs_shutdown
!= 1) {
411 while ((bp
= bufq_get(mfsp
->mfs_buflist
)) != NULL
) {
412 mutex_exit(&mfs_lock
);
414 mutex_enter(&mfs_lock
);
417 * If a non-ignored signal is received, try to unmount.
418 * If that fails, or the filesystem is already in the
419 * process of being unmounted, clear the signal (it has been
420 * "processed"), otherwise we will loop here, as tsleep
421 * will always return EINTR/ERESTART.
423 if (sleepreturn
!= 0) {
424 mutex_exit(&mfs_lock
);
425 if (dounmount(mp
, 0, curlwp
) != 0) {
427 ksiginfo_queue_init(&kq
);
428 mutex_enter(p
->p_lock
);
429 sigclearall(p
, NULL
, &kq
);
430 mutex_exit(p
->p_lock
);
431 ksiginfo_queue_drain(&kq
);
434 mutex_enter(&mfs_lock
);
438 sleepreturn
= cv_wait_sig(&mfsp
->mfs_cv
, &mfs_lock
);
440 KASSERT(bufq_peek(mfsp
->mfs_buflist
) == NULL
);
441 refcnt
= --mfsp
->mfs_refcnt
;
442 mutex_exit(&mfs_lock
);
444 bufq_free(mfsp
->mfs_buflist
);
445 cv_destroy(&mfsp
->mfs_cv
);
446 kmem_free(mfsp
, sizeof(*mfsp
));
448 return (sleepreturn
);
452 * Get file system statistics.
455 mfs_statvfs(struct mount
*mp
, struct statvfs
*sbp
)
459 error
= ffs_statvfs(mp
, sbp
);
462 (void)strncpy(sbp
->f_fstypename
, mp
->mnt_op
->vfs_name
,
463 sizeof(sbp
->f_fstypename
));
464 sbp
->f_fstypename
[sizeof(sbp
->f_fstypename
) - 1] = '\0';