1 /* $NetBSD: mfs_vfsops.c,v 1.103 2011/06/12 03:36:01 rmind 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.103 2011/06/12 03:36:01 rmind 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 kmutex_t mfs_lock
; /* global lock */
73 /* used for building internal dev_t, minor == 0 reserved for miniroot */
74 static int mfs_minor
= 1;
75 static int mfs_initcnt
;
77 extern int (**mfs_vnodeop_p
)(void *);
79 static struct sysctllog
*mfs_sysctl_log
;
85 extern const struct vnodeopv_desc mfs_vnodeop_opv_desc
;
87 const struct vnodeopv_desc
* const mfs_vnodeopv_descs
[] = {
88 &mfs_vnodeop_opv_desc
,
92 struct vfsops mfs_vfsops
= {
94 sizeof (struct mfs_args
),
109 (int (*)(struct mount
*, struct vnode
*, struct timespec
*)) eopnotsupp
,
111 (void *)eopnotsupp
, /* vfs_suspendctl */
112 genfs_renamelock_enter
,
113 genfs_renamelock_exit
,
121 mfs_modcmd(modcmd_t cmd
, void *arg
)
126 case MODULE_CMD_INIT
:
127 error
= vfs_attach(&mfs_vfsops
);
130 sysctl_createv(&mfs_sysctl_log
, 0, NULL
, NULL
,
132 CTLTYPE_NODE
, "vfs", NULL
,
135 sysctl_createv(&mfs_sysctl_log
, 0, NULL
, NULL
,
136 CTLFLAG_PERMANENT
|CTLFLAG_ALIAS
,
138 SYSCTL_DESCR("Memory based file system"),
140 CTL_VFS
, 3, CTL_EOL
);
142 * XXX the "1" and the "3" above could be dynamic, thereby
143 * eliminating one more instance of the "number to vfs"
144 * mapping problem, but they are in order as taken from
148 case MODULE_CMD_FINI
:
149 error
= vfs_detach(&mfs_vfsops
);
152 sysctl_teardown(&mfs_sysctl_log
);
163 * Memory based filesystem initialization.
169 if (mfs_initcnt
++ == 0) {
170 mutex_init(&mfs_lock
, MUTEX_DEFAULT
, IPL_NONE
);
186 if (--mfs_initcnt
== 0) {
188 mutex_destroy(&mfs_lock
);
193 * Called by main() when mfs is going to be mounted as root.
201 struct lwp
*l
= curlwp
; /* XXX */
202 struct ufsmount
*ump
;
203 struct mfsnode
*mfsp
;
206 if ((error
= vfs_rootmountalloc(MOUNT_MFS
, "mfs_root", &mp
))) {
211 mfsp
= kmem_alloc(sizeof(*mfsp
), KM_SLEEP
);
212 rootvp
->v_data
= mfsp
;
213 rootvp
->v_op
= mfs_vnodeop_p
;
214 rootvp
->v_tag
= VT_MFS
;
215 mfsp
->mfs_baseoff
= mfs_rootbase
;
216 mfsp
->mfs_size
= mfs_rootsize
;
217 mfsp
->mfs_vnode
= rootvp
;
218 mfsp
->mfs_proc
= NULL
; /* indicate kernel space */
219 mfsp
->mfs_shutdown
= 0;
220 cv_init(&mfsp
->mfs_cv
, "mfs");
221 mfsp
->mfs_refcnt
= 1;
222 bufq_alloc(&mfsp
->mfs_buflist
, "fcfs", 0);
223 if ((error
= ffs_mountfs(rootvp
, mp
, l
)) != 0) {
224 vfs_unbusy(mp
, false, NULL
);
225 bufq_free(mfsp
->mfs_buflist
);
227 kmem_free(mfsp
, sizeof(*mfsp
));
230 mutex_enter(&mountlist_lock
);
231 CIRCLEQ_INSERT_TAIL(&mountlist
, mp
, mnt_list
);
232 mutex_exit(&mountlist_lock
);
233 mp
->mnt_vnodecovered
= NULLVP
;
236 (void) copystr(mp
->mnt_stat
.f_mntonname
, fs
->fs_fsmnt
, MNAMELEN
- 1, 0);
237 (void)ffs_statvfs(mp
, &mp
->mnt_stat
);
238 vfs_unbusy(mp
, false, NULL
);
249 mfs_mount(struct mount
*mp
, const char *path
, void *data
, size_t *data_len
)
251 struct lwp
*l
= curlwp
;
253 struct mfs_args
*args
= data
;
254 struct ufsmount
*ump
;
256 struct mfsnode
*mfsp
;
258 int flags
, error
= 0;
260 if (*data_len
< sizeof *args
)
264 if (mp
->mnt_flag
& MNT_GETARGS
) {
280 args
->base
= mfsp
->mfs_baseoff
;
281 args
->size
= mfsp
->mfs_size
;
282 *data_len
= sizeof *args
;
286 * XXX turn off async to avoid hangs when writing lots of data.
287 * the problem is that MFS needs to allocate pages to clean pages,
288 * so if we wait until the last minute to clean pages then there
289 * may not be any pages available to do the cleaning.
290 * ... and since the default partially-synchronous mode turns out
291 * to not be sufficient under heavy load, make it full synchronous.
293 mp
->mnt_flag
&= ~MNT_ASYNC
;
294 mp
->mnt_flag
|= MNT_SYNCHRONOUS
;
297 * If updating, check whether changing from read-only to
298 * read/write; if there is no device name, that's all we do.
300 if (mp
->mnt_flag
& MNT_UPDATE
) {
303 if (fs
->fs_ronly
== 0 && (mp
->mnt_flag
& MNT_RDONLY
)) {
305 if (mp
->mnt_flag
& MNT_FORCE
)
307 error
= ffs_flushfiles(mp
, flags
, l
);
311 if (fs
->fs_ronly
&& (mp
->mnt_iflag
& IMNT_WANTRDWR
))
313 if (args
->fspec
== NULL
)
317 error
= getnewvnode(VT_MFS
, NULL
, mfs_vnodeop_p
, NULL
, &devvp
);
320 devvp
->v_vflag
|= VV_MPSAFE
;
321 devvp
->v_type
= VBLK
;
322 spec_node_init(devvp
, makedev(255, mfs_minor
));
324 mfsp
= kmem_alloc(sizeof(*mfsp
), KM_SLEEP
);
325 devvp
->v_data
= mfsp
;
326 mfsp
->mfs_baseoff
= args
->base
;
327 mfsp
->mfs_size
= args
->size
;
328 mfsp
->mfs_vnode
= devvp
;
330 mfsp
->mfs_shutdown
= 0;
331 cv_init(&mfsp
->mfs_cv
, "mfsidl");
332 mfsp
->mfs_refcnt
= 1;
333 bufq_alloc(&mfsp
->mfs_buflist
, "fcfs", 0);
334 if ((error
= ffs_mountfs(devvp
, mp
, l
)) != 0) {
335 mfsp
->mfs_shutdown
= 1;
341 error
= set_statvfs_info(path
, UIO_USERSPACE
, args
->fspec
,
342 UIO_USERSPACE
, mp
->mnt_op
->vfs_name
, mp
, l
);
345 (void)strncpy(fs
->fs_fsmnt
, mp
->mnt_stat
.f_mntonname
,
346 sizeof(fs
->fs_fsmnt
));
347 fs
->fs_fsmnt
[sizeof(fs
->fs_fsmnt
) - 1] = '\0';
348 /* XXX: cleanup on error */
353 * Used to grab the process and keep it in the kernel to service
354 * memory filesystem I/O requests.
356 * Loop servicing I/O requests.
357 * Copy the requested data into or out of the memory filesystem
362 mfs_start(struct mount
*mp
, int flags
)
365 struct mfsnode
*mfsp
;
369 int sleepreturn
= 0, refcnt
, error
;
373 * Ensure that file system is still mounted when getting mfsnode.
374 * Add a reference to the mfsnode to prevent it disappearing in
377 if ((error
= vfs_busy(mp
, NULL
)) != 0)
379 vp
= VFSTOUFS(mp
)->um_devvp
;
381 mutex_enter(&mfs_lock
);
383 mutex_exit(&mfs_lock
);
384 vfs_unbusy(mp
, false, NULL
);
386 base
= mfsp
->mfs_baseoff
;
387 mutex_enter(&mfs_lock
);
388 while (mfsp
->mfs_shutdown
!= 1) {
389 while ((bp
= bufq_get(mfsp
->mfs_buflist
)) != NULL
) {
390 mutex_exit(&mfs_lock
);
392 mutex_enter(&mfs_lock
);
395 * If a non-ignored signal is received, try to unmount.
396 * If that fails, or the filesystem is already in the
397 * process of being unmounted, clear the signal (it has been
398 * "processed"), otherwise we will loop here, as tsleep
399 * will always return EINTR/ERESTART.
401 if (sleepreturn
!= 0) {
402 mutex_exit(&mfs_lock
);
403 if (dounmount(mp
, 0, curlwp
) != 0) {
405 ksiginfo_queue_init(&kq
);
406 mutex_enter(p
->p_lock
);
407 sigclearall(p
, NULL
, &kq
);
408 mutex_exit(p
->p_lock
);
409 ksiginfo_queue_drain(&kq
);
412 mutex_enter(&mfs_lock
);
416 sleepreturn
= cv_wait_sig(&mfsp
->mfs_cv
, &mfs_lock
);
418 KASSERT(bufq_peek(mfsp
->mfs_buflist
) == NULL
);
419 refcnt
= --mfsp
->mfs_refcnt
;
420 mutex_exit(&mfs_lock
);
422 bufq_free(mfsp
->mfs_buflist
);
423 cv_destroy(&mfsp
->mfs_cv
);
424 kmem_free(mfsp
, sizeof(*mfsp
));
426 return (sleepreturn
);
430 * Get file system statistics.
433 mfs_statvfs(struct mount
*mp
, struct statvfs
*sbp
)
437 error
= ffs_statvfs(mp
, sbp
);
440 (void)strncpy(sbp
->f_fstypename
, mp
->mnt_op
->vfs_name
,
441 sizeof(sbp
->f_fstypename
));
442 sbp
->f_fstypename
[sizeof(sbp
->f_fstypename
) - 1] = '\0';