1 /* $NetBSD: mfs_vfsops.c,v 1.110 2015/03/17 09:39:29 hannken 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.110 2015/03/17 09:39:29 hannken 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 devminor_t 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
= {
93 .vfs_name
= MOUNT_MFS
,
94 .vfs_min_mount_data
= sizeof (struct mfs_args
),
95 .vfs_mount
= mfs_mount
,
96 .vfs_start
= mfs_start
,
97 .vfs_unmount
= ffs_unmount
,
99 .vfs_quotactl
= ufs_quotactl
,
100 .vfs_statvfs
= mfs_statvfs
,
101 .vfs_sync
= ffs_sync
,
102 .vfs_vget
= ufs_vget
,
103 .vfs_loadvnode
= ffs_loadvnode
,
104 .vfs_newvnode
= ffs_newvnode
,
105 .vfs_fhtovp
= ffs_fhtovp
,
106 .vfs_vptofh
= ffs_vptofh
,
107 .vfs_init
= mfs_init
,
108 .vfs_reinit
= mfs_reinit
,
109 .vfs_done
= mfs_done
,
110 .vfs_snapshot
= (void *)eopnotsupp
,
111 .vfs_extattrctl
= vfs_stdextattrctl
,
112 .vfs_suspendctl
= (void *)eopnotsupp
,
113 .vfs_renamelock_enter
= genfs_renamelock_enter
,
114 .vfs_renamelock_exit
= genfs_renamelock_exit
,
115 .vfs_fsync
= (void *)eopnotsupp
,
116 .vfs_opv_descs
= mfs_vnodeopv_descs
120 mfs_modcmd(modcmd_t cmd
, void *arg
)
125 case MODULE_CMD_INIT
:
126 error
= vfs_attach(&mfs_vfsops
);
129 sysctl_createv(&mfs_sysctl_log
, 0, NULL
, NULL
,
130 CTLFLAG_PERMANENT
|CTLFLAG_ALIAS
,
132 SYSCTL_DESCR("Memory based file system"),
134 CTL_VFS
, 3, CTL_EOL
);
136 * XXX the "1" and the "3" above could be dynamic, thereby
137 * eliminating one more instance of the "number to vfs"
138 * mapping problem, but they are in order as taken from
142 case MODULE_CMD_FINI
:
143 error
= vfs_detach(&mfs_vfsops
);
146 sysctl_teardown(&mfs_sysctl_log
);
157 * Memory based filesystem initialization.
163 if (mfs_initcnt
++ == 0) {
164 mutex_init(&mfs_lock
, MUTEX_DEFAULT
, IPL_NONE
);
180 if (--mfs_initcnt
== 0) {
182 mutex_destroy(&mfs_lock
);
187 * Called by main() when mfs is going to be mounted as root.
195 struct lwp
*l
= curlwp
; /* XXX */
196 struct ufsmount
*ump
;
197 struct mfsnode
*mfsp
;
200 if ((error
= vfs_rootmountalloc(MOUNT_MFS
, "mfs_root", &mp
))) {
205 mfsp
= kmem_alloc(sizeof(*mfsp
), KM_SLEEP
);
206 rootvp
->v_data
= mfsp
;
207 rootvp
->v_op
= mfs_vnodeop_p
;
208 rootvp
->v_tag
= VT_MFS
;
209 mfsp
->mfs_baseoff
= mfs_rootbase
;
210 mfsp
->mfs_size
= mfs_rootsize
;
211 mfsp
->mfs_vnode
= rootvp
;
212 mfsp
->mfs_proc
= NULL
; /* indicate kernel space */
213 mfsp
->mfs_shutdown
= 0;
214 cv_init(&mfsp
->mfs_cv
, "mfs");
215 mfsp
->mfs_refcnt
= 1;
216 bufq_alloc(&mfsp
->mfs_buflist
, "fcfs", 0);
217 if ((error
= ffs_mountfs(rootvp
, mp
, l
)) != 0) {
218 vfs_unbusy(mp
, false, NULL
);
219 bufq_free(mfsp
->mfs_buflist
);
221 kmem_free(mfsp
, sizeof(*mfsp
));
224 mountlist_append(mp
);
225 mp
->mnt_vnodecovered
= NULLVP
;
228 (void) copystr(mp
->mnt_stat
.f_mntonname
, fs
->fs_fsmnt
, MNAMELEN
- 1, 0);
229 (void)ffs_statvfs(mp
, &mp
->mnt_stat
);
230 vfs_unbusy(mp
, false, NULL
);
241 mfs_mount(struct mount
*mp
, const char *path
, void *data
, size_t *data_len
)
243 struct lwp
*l
= curlwp
;
245 struct mfs_args
*args
= data
;
246 struct ufsmount
*ump
;
248 struct mfsnode
*mfsp
;
251 int flags
, error
= 0;
255 if (*data_len
< sizeof *args
)
259 if (mp
->mnt_flag
& MNT_GETARGS
) {
275 args
->base
= mfsp
->mfs_baseoff
;
276 args
->size
= mfsp
->mfs_size
;
277 *data_len
= sizeof *args
;
281 * XXX turn off async to avoid hangs when writing lots of data.
282 * the problem is that MFS needs to allocate pages to clean pages,
283 * so if we wait until the last minute to clean pages then there
284 * may not be any pages available to do the cleaning.
285 * ... and since the default partially-synchronous mode turns out
286 * to not be sufficient under heavy load, make it full synchronous.
288 mp
->mnt_flag
&= ~MNT_ASYNC
;
289 mp
->mnt_flag
|= MNT_SYNCHRONOUS
;
292 * If updating, check whether changing from read-only to
293 * read/write; if there is no device name, that's all we do.
295 if (mp
->mnt_flag
& MNT_UPDATE
) {
298 if (fs
->fs_ronly
== 0 && (mp
->mnt_flag
& MNT_RDONLY
)) {
300 if (mp
->mnt_flag
& MNT_FORCE
)
302 error
= ffs_flushfiles(mp
, flags
, l
);
306 if (fs
->fs_ronly
&& (mp
->mnt_iflag
& IMNT_WANTRDWR
))
308 if (args
->fspec
== NULL
)
312 mutex_enter(&mfs_lock
);
314 mutex_exit(&mfs_lock
);
315 error
= bdevvp(makedev(255, minor
), &devvp
);
318 mfsp
= kmem_alloc(sizeof(*mfsp
), KM_SLEEP
);
320 * Changing v_op and v_data here is safe as we are
321 * the exclusive owner of this device node.
323 KASSERT(devvp
->v_op
== spec_vnodeop_p
);
324 KASSERT(devvp
->v_data
== NULL
);
325 devvp
->v_op
= mfs_vnodeop_p
;
326 devvp
->v_data
= mfsp
;
327 mfsp
->mfs_baseoff
= args
->base
;
328 mfsp
->mfs_size
= args
->size
;
329 mfsp
->mfs_vnode
= devvp
;
331 mfsp
->mfs_shutdown
= 0;
332 cv_init(&mfsp
->mfs_cv
, "mfsidl");
333 mfsp
->mfs_refcnt
= 1;
334 bufq_alloc(&mfsp
->mfs_buflist
, "fcfs", 0);
335 if ((error
= ffs_mountfs(devvp
, mp
, l
)) != 0) {
336 mfsp
->mfs_shutdown
= 1;
342 error
= set_statvfs_info(path
, UIO_USERSPACE
, args
->fspec
,
343 UIO_USERSPACE
, mp
->mnt_op
->vfs_name
, mp
, l
);
346 (void)strncpy(fs
->fs_fsmnt
, mp
->mnt_stat
.f_mntonname
,
347 sizeof(fs
->fs_fsmnt
));
348 fs
->fs_fsmnt
[sizeof(fs
->fs_fsmnt
) - 1] = '\0';
349 /* XXX: cleanup on error */
354 * Used to grab the process and keep it in the kernel to service
355 * memory filesystem I/O requests.
357 * Loop servicing I/O requests.
358 * Copy the requested data into or out of the memory filesystem
363 mfs_start(struct mount
*mp
, int flags
)
366 struct mfsnode
*mfsp
;
370 int sleepreturn
= 0, refcnt
, error
;
374 * Ensure that file system is still mounted when getting mfsnode.
375 * Add a reference to the mfsnode to prevent it disappearing in
378 if ((error
= vfs_busy(mp
, NULL
)) != 0)
380 vp
= VFSTOUFS(mp
)->um_devvp
;
382 mutex_enter(&mfs_lock
);
384 mutex_exit(&mfs_lock
);
385 vfs_unbusy(mp
, false, NULL
);
387 base
= mfsp
->mfs_baseoff
;
388 mutex_enter(&mfs_lock
);
389 while (mfsp
->mfs_shutdown
!= 1) {
390 while ((bp
= bufq_get(mfsp
->mfs_buflist
)) != NULL
) {
391 mutex_exit(&mfs_lock
);
393 mutex_enter(&mfs_lock
);
396 * If a non-ignored signal is received, try to unmount.
397 * If that fails, or the filesystem is already in the
398 * process of being unmounted, clear the signal (it has been
399 * "processed"), otherwise we will loop here, as tsleep
400 * will always return EINTR/ERESTART.
402 if (sleepreturn
!= 0) {
403 mutex_exit(&mfs_lock
);
404 if (dounmount(mp
, 0, curlwp
) != 0) {
406 ksiginfo_queue_init(&kq
);
407 mutex_enter(p
->p_lock
);
408 sigclearall(p
, NULL
, &kq
);
409 mutex_exit(p
->p_lock
);
410 ksiginfo_queue_drain(&kq
);
413 mutex_enter(&mfs_lock
);
417 sleepreturn
= cv_wait_sig(&mfsp
->mfs_cv
, &mfs_lock
);
419 KASSERT(bufq_peek(mfsp
->mfs_buflist
) == NULL
);
420 refcnt
= --mfsp
->mfs_refcnt
;
421 mutex_exit(&mfs_lock
);
423 bufq_free(mfsp
->mfs_buflist
);
424 cv_destroy(&mfsp
->mfs_cv
);
425 kmem_free(mfsp
, sizeof(*mfsp
));
427 return (sleepreturn
);
431 * Get file system statistics.
434 mfs_statvfs(struct mount
*mp
, struct statvfs
*sbp
)
438 error
= ffs_statvfs(mp
, sbp
);
441 (void)strncpy(sbp
->f_fstypename
, mp
->mnt_op
->vfs_name
,
442 sizeof(sbp
->f_fstypename
));
443 sbp
->f_fstypename
[sizeof(sbp
->f_fstypename
) - 1] = '\0';