mfs_vfsops.c revision 1.113
1/* $NetBSD: mfs_vfsops.c,v 1.113 2017/04/17 08:32:02 hannken 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.113 2017/04/17 08:32:02 hannken 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/bufq.h> 49#include <sys/mount.h> 50#include <sys/signalvar.h> 51#include <sys/vnode.h> 52#include <sys/kmem.h> 53#include <sys/module.h> 54 55#include <miscfs/genfs/genfs.h> 56#include <miscfs/specfs/specdev.h> 57 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> 62 63#include <ufs/ffs/fs.h> 64#include <ufs/ffs/ffs_extern.h> 65 66#include <ufs/mfs/mfsnode.h> 67#include <ufs/mfs/mfs_extern.h> 68 69MODULE(MODULE_CLASS_VFS, mfs, "ffs"); 70 71kmutex_t mfs_lock; /* global lock */ 72 73/* used for building internal dev_t, minor == 0 reserved for miniroot */ 74static devminor_t mfs_minor = 1; 75static int mfs_initcnt; 76 77extern int (**mfs_vnodeop_p)(void *); 78 79static struct sysctllog *mfs_sysctl_log; 80 81/* 82 * mfs vfs operations. 83 */ 84 85extern const struct vnodeopv_desc mfs_vnodeop_opv_desc; 86 87const struct vnodeopv_desc * const mfs_vnodeopv_descs[] = { 88 &mfs_vnodeop_opv_desc, 89 NULL, 90}; 91 92struct 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, 98 .vfs_root = ufs_root, 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 = genfs_suspendctl, 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 117}; 118 119static int 120mfs_modcmd(modcmd_t cmd, void *arg) 121{ 122 int error; 123 124 switch (cmd) { 125 case MODULE_CMD_INIT: 126 error = vfs_attach(&mfs_vfsops); 127 if (error != 0) 128 break; 129 sysctl_createv(&mfs_sysctl_log, 0, NULL, NULL, 130 CTLFLAG_PERMANENT|CTLFLAG_ALIAS, 131 CTLTYPE_NODE, "mfs", 132 SYSCTL_DESCR("Memory based file system"), 133 NULL, 1, NULL, 0, 134 CTL_VFS, 3, CTL_EOL); 135 /* 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 139 * sys/mount.h 140 */ 141 break; 142 case MODULE_CMD_FINI: 143 error = vfs_detach(&mfs_vfsops); 144 if (error != 0) 145 break; 146 sysctl_teardown(&mfs_sysctl_log); 147 break; 148 default: 149 error = ENOTTY; 150 break; 151 } 152 153 return (error); 154} 155 156/* 157 * Memory based filesystem initialization. 158 */ 159void 160mfs_init(void) 161{ 162 163 if (mfs_initcnt++ == 0) { 164 mutex_init(&mfs_lock, MUTEX_DEFAULT, IPL_NONE); 165 ffs_init(); 166 } 167} 168 169void 170mfs_reinit(void) 171{ 172 173 ffs_reinit(); 174} 175 176void 177mfs_done(void) 178{ 179 180 if (--mfs_initcnt == 0) { 181 ffs_done(); 182 mutex_destroy(&mfs_lock); 183 } 184} 185 186/* 187 * Called by main() when mfs is going to be mounted as root. 188 */ 189 190int 191mfs_mountroot(void) 192{ 193 struct fs *fs; 194 struct mount *mp; 195 struct lwp *l = curlwp; /* XXX */ 196 struct ufsmount *ump; 197 struct mfsnode *mfsp; 198 int error = 0; 199 200 if ((error = vfs_rootmountalloc(MOUNT_MFS, "mfs_root", &mp))) { 201 vrele(rootvp); 202 return (error); 203 } 204 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); 219 bufq_free(mfsp->mfs_buflist); 220 vfs_rele(mp); 221 kmem_free(mfsp, sizeof(*mfsp)); 222 return (error); 223 } 224 mountlist_append(mp); 225 mp->mnt_vnodecovered = NULLVP; 226 ump = VFSTOUFS(mp); 227 fs = ump->um_fs; 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); 231 return (0); 232} 233 234/* 235 * VFS Operations. 236 * 237 * mount system call 238 */ 239/* ARGSUSED */ 240int 241mfs_mount(struct mount *mp, const char *path, void *data, size_t *data_len) 242{ 243 struct lwp *l = curlwp; 244 struct vnode *devvp; 245 struct mfs_args *args = data; 246 struct ufsmount *ump; 247 struct fs *fs; 248 struct mfsnode *mfsp; 249 struct proc *p; 250 devminor_t minor; 251 int flags, error = 0; 252 253 if (args == NULL) 254 return EINVAL; 255 if (*data_len < sizeof *args) 256 return EINVAL; 257 258 p = l->l_proc; 259 if (mp->mnt_flag & MNT_GETARGS) { 260 struct vnode *vp; 261 262 ump = VFSTOUFS(mp); 263 if (ump == NULL) 264 return EIO; 265 266 vp = ump->um_devvp; 267 if (vp == NULL) 268 return EIO; 269 270 mfsp = VTOMFS(vp); 271 if (mfsp == NULL) 272 return EIO; 273 274 args->fspec = NULL; 275 args->base = mfsp->mfs_baseoff; 276 args->size = mfsp->mfs_size; 277 *data_len = sizeof *args; 278 return 0; 279 } 280 /* 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. 287 */ 288 mp->mnt_flag &= ~MNT_ASYNC; 289 mp->mnt_flag |= MNT_SYNCHRONOUS; 290 291 /* 292 * If updating, check whether changing from read-only to 293 * read/write; if there is no device name, that's all we do. 294 */ 295 if (mp->mnt_flag & MNT_UPDATE) { 296 ump = VFSTOUFS(mp); 297 fs = ump->um_fs; 298 if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 299 flags = WRITECLOSE; 300 if (mp->mnt_flag & MNT_FORCE) 301 flags |= FORCECLOSE; 302 error = ffs_flushfiles(mp, flags, l); 303 if (error) 304 return (error); 305 } 306 if (fs->fs_ronly && (mp->mnt_iflag & IMNT_WANTRDWR)) 307 fs->fs_ronly = 0; 308 if (args->fspec == NULL) 309 return EINVAL; 310 return (0); 311 } 312 mutex_enter(&mfs_lock); 313 minor = mfs_minor++; 314 mutex_exit(&mfs_lock); 315 error = bdevvp(makedev(255, minor), &devvp); 316 if (error) 317 return (error); 318 mfsp = kmem_alloc(sizeof(*mfsp), KM_SLEEP); 319 /* 320 * Changing v_op and v_data here is safe as we are 321 * the exclusive owner of this device node. 322 */ 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; 330 mfsp->mfs_proc = p; 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; 337 vrele(devvp); 338 return (error); 339 } 340 ump = VFSTOUFS(mp); 341 fs = ump->um_fs; 342 error = set_statvfs_info(path, UIO_USERSPACE, args->fspec, 343 UIO_USERSPACE, mp->mnt_op->vfs_name, mp, l); 344 if (error) 345 return error; 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 */ 350 return 0; 351} 352 353/* 354 * Used to grab the process and keep it in the kernel to service 355 * memory filesystem I/O requests. 356 * 357 * Loop servicing I/O requests. 358 * Copy the requested data into or out of the memory filesystem 359 * address space. 360 */ 361/* ARGSUSED */ 362int 363mfs_start(struct mount *mp, int flags) 364{ 365 struct vnode *vp; 366 struct mfsnode *mfsp; 367 struct proc *p; 368 struct buf *bp; 369 void *base; 370 int sleepreturn = 0, refcnt, error; 371 ksiginfoq_t kq; 372 373 /* 374 * Ensure that file system is still mounted when getting mfsnode. 375 * Add a reference to the mfsnode to prevent it disappearing in 376 * this routine. 377 */ 378 if ((error = vfs_busy(mp)) != 0) 379 return error; 380 vp = VFSTOUFS(mp)->um_devvp; 381 mfsp = VTOMFS(vp); 382 mutex_enter(&mfs_lock); 383 mfsp->mfs_refcnt++; 384 mutex_exit(&mfs_lock); 385 vfs_unbusy(mp); 386 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); 392 mfs_doio(bp, base); 393 mutex_enter(&mfs_lock); 394 } 395 /* 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. 401 */ 402 if (sleepreturn != 0) { 403 mutex_exit(&mfs_lock); 404 if (dounmount(mp, 0, curlwp) != 0) { 405 p = curproc; 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); 411 } 412 sleepreturn = 0; 413 mutex_enter(&mfs_lock); 414 continue; 415 } 416 417 sleepreturn = cv_wait_sig(&mfsp->mfs_cv, &mfs_lock); 418 } 419 KASSERT(bufq_peek(mfsp->mfs_buflist) == NULL); 420 refcnt = --mfsp->mfs_refcnt; 421 mutex_exit(&mfs_lock); 422 if (refcnt == 0) { 423 bufq_free(mfsp->mfs_buflist); 424 cv_destroy(&mfsp->mfs_cv); 425 kmem_free(mfsp, sizeof(*mfsp)); 426 } 427 return (sleepreturn); 428} 429 430/* 431 * Get file system statistics. 432 */ 433int 434mfs_statvfs(struct mount *mp, struct statvfs *sbp) 435{ 436 int error; 437 438 error = ffs_statvfs(mp, sbp); 439 if (error) 440 return error; 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'; 444 return 0; 445} 446