/* $NetBSD: mfs_vnops.c,v 1.59 2019/02/20 10:03:55 hannken Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)mfs_vnops.c 8.11 (Berkeley) 5/22/95 */ #include __KERNEL_RCSID(0, "$NetBSD: mfs_vnops.c,v 1.59 2019/02/20 10:03:55 hannken Exp $"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * mfs vnode operations. */ int (**mfs_vnodeop_p)(void *); const struct vnodeopv_entry_desc mfs_vnodeop_entries[] = { { &vop_default_desc, vn_default_error }, { &vop_lookup_desc, mfs_lookup }, /* lookup */ { &vop_create_desc, mfs_create }, /* create */ { &vop_mknod_desc, mfs_mknod }, /* mknod */ { &vop_open_desc, mfs_open }, /* open */ { &vop_close_desc, mfs_close }, /* close */ { &vop_access_desc, mfs_access }, /* access */ { &vop_getattr_desc, mfs_getattr }, /* getattr */ { &vop_setattr_desc, mfs_setattr }, /* setattr */ { &vop_read_desc, mfs_read }, /* read */ { &vop_write_desc, mfs_write }, /* write */ { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ { &vop_ioctl_desc, mfs_ioctl }, /* ioctl */ { &vop_poll_desc, mfs_poll }, /* poll */ { &vop_revoke_desc, mfs_revoke }, /* revoke */ { &vop_mmap_desc, mfs_mmap }, /* mmap */ { &vop_fsync_desc, spec_fsync }, /* fsync */ { &vop_seek_desc, mfs_seek }, /* seek */ { &vop_remove_desc, mfs_remove }, /* remove */ { &vop_link_desc, mfs_link }, /* link */ { &vop_rename_desc, mfs_rename }, /* rename */ { &vop_mkdir_desc, mfs_mkdir }, /* mkdir */ { &vop_rmdir_desc, mfs_rmdir }, /* rmdir */ { &vop_symlink_desc, mfs_symlink }, /* symlink */ { &vop_readdir_desc, mfs_readdir }, /* readdir */ { &vop_readlink_desc, mfs_readlink }, /* readlink */ { &vop_abortop_desc, mfs_abortop }, /* abortop */ { &vop_inactive_desc, mfs_inactive }, /* inactive */ { &vop_reclaim_desc, mfs_reclaim }, /* reclaim */ { &vop_lock_desc, genfs_nolock }, /* lock */ { &vop_unlock_desc, genfs_nounlock }, /* unlock */ { &vop_bmap_desc, mfs_bmap }, /* bmap */ { &vop_strategy_desc, mfs_strategy }, /* strategy */ { &vop_print_desc, mfs_print }, /* print */ { &vop_islocked_desc, mfs_islocked }, /* islocked */ { &vop_pathconf_desc, mfs_pathconf }, /* pathconf */ { &vop_advlock_desc, mfs_advlock }, /* advlock */ { &vop_bwrite_desc, mfs_bwrite }, /* bwrite */ { &vop_putpages_desc, mfs_putpages }, /* putpages */ { NULL, NULL } }; const struct vnodeopv_desc mfs_vnodeop_opv_desc = { &mfs_vnodeop_p, mfs_vnodeop_entries }; /* * Vnode Operations. * * Open called to allow memory filesystem to initialize and * validate before actual IO. Record our process identifier * so we can tell when we are doing I/O to ourself. */ /* ARGSUSED */ int mfs_open(void *v) { struct vop_open_args /* { struct vnode *a_vp; int a_mode; kauth_cred_t a_cred; } */ *ap = v; if (ap->a_vp->v_type != VBLK) { panic("mfs_ioctl not VBLK"); /* NOTREACHED */ } return (0); } /* * Pass I/O requests to the memory filesystem process. */ int mfs_strategy(void *v) { struct vop_strategy_args /* { struct vnode *a_vp; struct buf *a_bp; } */ *ap = v; struct vnode *vp = ap->a_vp; struct buf *bp = ap->a_bp; struct mfsnode *mfsp; if (vp->v_type != VBLK || vp->v_usecount == 0) panic("mfs_strategy: bad dev"); mfsp = VTOMFS(vp); /* check for mini-root access */ if (mfsp->mfs_proc == NULL) { void *base; base = (char *)mfsp->mfs_baseoff + (bp->b_blkno << DEV_BSHIFT); if (bp->b_flags & B_READ) memcpy(bp->b_data, base, bp->b_bcount); else memcpy(base, bp->b_data, bp->b_bcount); bp->b_resid = 0; biodone(bp); } else if (mfsp->mfs_proc == curproc) { mfs_doio(bp, mfsp->mfs_baseoff); } else if (doing_shutdown) { /* * bitbucket I/O during shutdown. * Note that reads should *not* happen here, but.. */ if (bp->b_flags & B_READ) printf("warning: mfs read during shutdown\n"); bp->b_resid = 0; biodone(bp); } else { mutex_enter(&mfs_lock); bufq_put(mfsp->mfs_buflist, bp); cv_broadcast(&mfsp->mfs_cv); mutex_exit(&mfs_lock); } return (0); } /* * Memory file system I/O. */ void mfs_doio(struct buf *bp, void *base) { base = (char *)base + (bp->b_blkno << DEV_BSHIFT); if (bp->b_flags & B_READ) bp->b_error = copyin(base, bp->b_data, bp->b_bcount); else bp->b_error = copyout(bp->b_data, base, bp->b_bcount); if (bp->b_error == 0) bp->b_resid = 0; biodone(bp); } /* * This is a noop, simply returning what one has been given. */ int mfs_bmap(void *v) { struct vop_bmap_args /* { struct vnode *a_vp; daddr_t a_bn; struct vnode **a_vpp; daddr_t *a_bnp; int *a_runp; } */ *ap = v; if (ap->a_vpp != NULL) *ap->a_vpp = ap->a_vp; if (ap->a_bnp != NULL) *ap->a_bnp = ap->a_bn; if (ap->a_runp != NULL) *ap->a_runp = 0; return (0); } /* * Memory filesystem close routine */ /* ARGSUSED */ int mfs_close(void *v) { struct vop_close_args /* { struct vnode *a_vp; int a_fflag; kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp = ap->a_vp; struct mfsnode *mfsp = VTOMFS(vp); struct buf *bp; int error; /* * Finish any pending I/O requests. */ mutex_enter(&mfs_lock); while ((bp = bufq_get(mfsp->mfs_buflist)) != NULL) { mutex_exit(&mfs_lock); mfs_doio(bp, mfsp->mfs_baseoff); mutex_enter(&mfs_lock); } mutex_exit(&mfs_lock); /* * On last close of a memory filesystem * we must invalidate any in core blocks, so that * we can, free up its vnode. */ if ((error = vinvalbuf(vp, V_SAVE, ap->a_cred, curlwp, 0, 0)) != 0) return (error); /* * There should be no way to have any more uses of this * vnode, so if we find any other uses, it is a panic. */ if (bufq_peek(mfsp->mfs_buflist) != NULL) panic("mfs_close"); /* * Send a request to the filesystem server to exit. */ mutex_enter(&mfs_lock); mfsp->mfs_shutdown = 1; cv_broadcast(&mfsp->mfs_cv); mutex_exit(&mfs_lock); return (0); } /* * Memory filesystem inactive routine */ /* ARGSUSED */ int mfs_inactive(void *v) { struct vop_inactive_v2_args /* { struct vnode *a_vp; } */ *ap = v; struct vnode *vp = ap->a_vp; struct mfsnode *mfsp = VTOMFS(vp); if (bufq_peek(mfsp->mfs_buflist) != NULL) panic("mfs_inactive: not inactive (mfs_buflist %p)", bufq_peek(mfsp->mfs_buflist)); return VOCALL(spec_vnodeop_p, VOFFSET(vop_inactive), ap); } /* * Reclaim a memory filesystem devvp so that it can be reused. */ int mfs_reclaim(void *v) { struct vop_reclaim_v2_args /* { struct vnode *a_vp; } */ *ap = v; struct vnode *vp = ap->a_vp; struct mfsnode *mfsp = VTOMFS(vp); int refcnt; mutex_enter(&mfs_lock); vp->v_data = NULL; refcnt = --mfsp->mfs_refcnt; mutex_exit(&mfs_lock); if (refcnt == 0) { bufq_free(mfsp->mfs_buflist); cv_destroy(&mfsp->mfs_cv); kmem_free(mfsp, sizeof(*mfsp)); } return VOCALL(spec_vnodeop_p, VOFFSET(vop_reclaim), ap); } /* * Print out the contents of an mfsnode. */ int mfs_print(void *v) { struct vop_print_args /* { struct vnode *a_vp; } */ *ap = v; struct mfsnode *mfsp = VTOMFS(ap->a_vp); printf("tag VT_MFS, pid %d, base %p, size %ld\n", (mfsp->mfs_proc != NULL) ? mfsp->mfs_proc->p_pid : 0, mfsp->mfs_baseoff, mfsp->mfs_size); return (0); }