xref: /netbsd-src/sys/ufs/mfs/mfs_vnops.c (revision f38668ff6c1902d12d5c4646ec116275adc80223)
1*f38668ffShannken /*	$NetBSD: mfs_vnops.c,v 1.64 2022/03/19 13:48:42 hannken Exp $	*/
2fccfa11aScgd 
3264b874cSmycroft /*
4264b874cSmycroft  * Copyright (c) 1989, 1993
5264b874cSmycroft  *	The Regents of the University of California.  All rights reserved.
6264b874cSmycroft  *
7264b874cSmycroft  * Redistribution and use in source and binary forms, with or without
8264b874cSmycroft  * modification, are permitted provided that the following conditions
9264b874cSmycroft  * are met:
10264b874cSmycroft  * 1. Redistributions of source code must retain the above copyright
11264b874cSmycroft  *    notice, this list of conditions and the following disclaimer.
12264b874cSmycroft  * 2. Redistributions in binary form must reproduce the above copyright
13264b874cSmycroft  *    notice, this list of conditions and the following disclaimer in the
14264b874cSmycroft  *    documentation and/or other materials provided with the distribution.
15aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
16264b874cSmycroft  *    may be used to endorse or promote products derived from this software
17264b874cSmycroft  *    without specific prior written permission.
18264b874cSmycroft  *
19264b874cSmycroft  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20264b874cSmycroft  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21264b874cSmycroft  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22264b874cSmycroft  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23264b874cSmycroft  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24264b874cSmycroft  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25264b874cSmycroft  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26264b874cSmycroft  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27264b874cSmycroft  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28264b874cSmycroft  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29264b874cSmycroft  * SUCH DAMAGE.
30264b874cSmycroft  *
31e5bc90f4Sfvdl  *	@(#)mfs_vnops.c	8.11 (Berkeley) 5/22/95
32264b874cSmycroft  */
33264b874cSmycroft 
34ec624546Slukem #include <sys/cdefs.h>
35*f38668ffShannken __KERNEL_RCSID(0, "$NetBSD: mfs_vnops.c,v 1.64 2022/03/19 13:48:42 hannken Exp $");
36ec624546Slukem 
37264b874cSmycroft #include <sys/param.h>
38264b874cSmycroft #include <sys/systm.h>
39264b874cSmycroft #include <sys/time.h>
40264b874cSmycroft #include <sys/kernel.h>
41264b874cSmycroft #include <sys/proc.h>
42264b874cSmycroft #include <sys/buf.h>
4305f25dccSyamt #include <sys/bufq.h>
44264b874cSmycroft #include <sys/vnode.h>
45021b86ddSad #include <sys/kmem.h>
46264b874cSmycroft 
47c52352c8Smycroft #include <miscfs/genfs/genfs.h>
48264b874cSmycroft #include <miscfs/specfs/specdev.h>
49264b874cSmycroft 
505026e056Sthorpej #include <machine/vmparam.h>
515026e056Sthorpej 
52264b874cSmycroft #include <ufs/mfs/mfsnode.h>
53264b874cSmycroft #include <ufs/mfs/mfs_extern.h>
54264b874cSmycroft 
55264b874cSmycroft /*
56264b874cSmycroft  * mfs vnode operations.
57264b874cSmycroft  */
5823ebf62dSxtraeme int (**mfs_vnodeop_p)(void *);
59d9466585Sjdolecek const struct vnodeopv_entry_desc mfs_vnodeop_entries[] = {
60264b874cSmycroft 	{ &vop_default_desc, vn_default_error },
61c6c16cd0Sdholland 	{ &vop_parsepath_desc, genfs_parsepath },	/* parsepath */
6241715070Sdholland 	{ &vop_lookup_desc, genfs_badop },		/* lookup */
6341715070Sdholland 	{ &vop_create_desc, genfs_badop },		/* create */
6441715070Sdholland 	{ &vop_mknod_desc, genfs_badop },		/* mknod */
65264b874cSmycroft 	{ &vop_open_desc, mfs_open },			/* open */
66264b874cSmycroft 	{ &vop_close_desc, mfs_close },			/* close */
6741715070Sdholland 	{ &vop_access_desc, genfs_badop },		/* access */
6841715070Sdholland 	{ &vop_accessx_desc, genfs_badop },		/* accessx */
6941715070Sdholland 	{ &vop_getattr_desc, genfs_badop },		/* getattr */
7041715070Sdholland 	{ &vop_setattr_desc, genfs_badop },		/* setattr */
7141715070Sdholland 	{ &vop_read_desc, genfs_badop },		/* read */
7241715070Sdholland 	{ &vop_write_desc, genfs_badop },		/* write */
7305d075b3Sdholland 	{ &vop_fallocate_desc, genfs_eopnotsupp },	/* fallocate */
7405d075b3Sdholland 	{ &vop_fdiscard_desc, genfs_eopnotsupp },	/* fdiscard */
7541715070Sdholland 	{ &vop_ioctl_desc, genfs_enoioctl },		/* ioctl */
7641715070Sdholland 	{ &vop_poll_desc, genfs_badop },		/* poll */
7741715070Sdholland 	{ &vop_revoke_desc, genfs_revoke },		/* revoke */
7841715070Sdholland 	{ &vop_mmap_desc, genfs_badop },		/* mmap */
79ee16aae1Schristos 	{ &vop_fsync_desc, spec_fsync },		/* fsync */
8041715070Sdholland 	{ &vop_seek_desc, genfs_badop },		/* seek */
8141715070Sdholland 	{ &vop_remove_desc, genfs_badop },		/* remove */
8241715070Sdholland 	{ &vop_link_desc, genfs_badop },		/* link */
8341715070Sdholland 	{ &vop_rename_desc, genfs_badop },		/* rename */
8441715070Sdholland 	{ &vop_mkdir_desc, genfs_badop },		/* mkdir */
8541715070Sdholland 	{ &vop_rmdir_desc, genfs_badop },		/* rmdir */
8641715070Sdholland 	{ &vop_symlink_desc, genfs_badop },		/* symlink */
8741715070Sdholland 	{ &vop_readdir_desc, genfs_badop },		/* readdir */
8841715070Sdholland 	{ &vop_readlink_desc, genfs_badop },		/* readlink */
8941715070Sdholland 	{ &vop_abortop_desc, genfs_badop },		/* abortop */
90264b874cSmycroft 	{ &vop_inactive_desc, mfs_inactive },		/* inactive */
91264b874cSmycroft 	{ &vop_reclaim_desc, mfs_reclaim },		/* reclaim */
92*f38668ffShannken 	{ &vop_lock_desc, genfs_lock },			/* lock */
93*f38668ffShannken 	{ &vop_unlock_desc, genfs_unlock },		/* unlock */
94264b874cSmycroft 	{ &vop_bmap_desc, mfs_bmap },			/* bmap */
95264b874cSmycroft 	{ &vop_strategy_desc, mfs_strategy },		/* strategy */
96264b874cSmycroft 	{ &vop_print_desc, mfs_print },			/* print */
97*f38668ffShannken 	{ &vop_islocked_desc, genfs_islocked },		/* islocked */
9841715070Sdholland 	{ &vop_pathconf_desc, genfs_badop },		/* pathconf */
9941715070Sdholland 	{ &vop_advlock_desc, genfs_badop },		/* advlock */
10041715070Sdholland 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
10141715070Sdholland 	{ &vop_putpages_desc, genfs_null_putpages },	/* putpages */
1025a690c92Schs 	{ NULL, NULL }
103264b874cSmycroft };
104d9466585Sjdolecek const struct vnodeopv_desc mfs_vnodeop_opv_desc =
105264b874cSmycroft 	{ &mfs_vnodeop_p, mfs_vnodeop_entries };
106264b874cSmycroft 
107264b874cSmycroft /*
108264b874cSmycroft  * Vnode Operations.
109264b874cSmycroft  *
110264b874cSmycroft  * Open called to allow memory filesystem to initialize and
111264b874cSmycroft  * validate before actual IO. Record our process identifier
112264b874cSmycroft  * so we can tell when we are doing I/O to ourself.
113264b874cSmycroft  */
114264b874cSmycroft /* ARGSUSED */
115264b874cSmycroft int
mfs_open(void * v)11623ebf62dSxtraeme mfs_open(void *v)
117573481f5Schristos {
118264b874cSmycroft 	struct vop_open_args /* {
119264b874cSmycroft 		struct vnode *a_vp;
120264b874cSmycroft 		int  a_mode;
121fc9422c9Selad 		kauth_cred_t a_cred;
122573481f5Schristos 	} */ *ap = v;
123264b874cSmycroft 
124264b874cSmycroft 	if (ap->a_vp->v_type != VBLK) {
12541715070Sdholland 		panic("mfs_open not VBLK");
126264b874cSmycroft 		/* NOTREACHED */
127264b874cSmycroft 	}
128264b874cSmycroft 	return (0);
129264b874cSmycroft }
130264b874cSmycroft 
131264b874cSmycroft /*
132264b874cSmycroft  * Pass I/O requests to the memory filesystem process.
133264b874cSmycroft  */
134264b874cSmycroft int
mfs_strategy(void * v)13523ebf62dSxtraeme mfs_strategy(void *v)
136573481f5Schristos {
137264b874cSmycroft 	struct vop_strategy_args /* {
13884b45bc3Shannken 		struct vnode *a_vp;
139264b874cSmycroft 		struct buf *a_bp;
140573481f5Schristos 	} */ *ap = v;
14184b45bc3Shannken 	struct vnode *vp = ap->a_vp;
142169ac5b3Saugustss 	struct buf *bp = ap->a_bp;
143169ac5b3Saugustss 	struct mfsnode *mfsp;
144264b874cSmycroft 
14523bf8800Sad 	if (vp->v_type != VBLK || vrefcnt(vp) == 0)
146264b874cSmycroft 		panic("mfs_strategy: bad dev");
147264b874cSmycroft 	mfsp = VTOMFS(vp);
1485026e056Sthorpej 	/* check for mini-root access */
1495026e056Sthorpej 	if (mfsp->mfs_proc == NULL) {
15053524e44Schristos 		void *base;
151264b874cSmycroft 
15253524e44Schristos 		base = (char *)mfsp->mfs_baseoff + (bp->b_blkno << DEV_BSHIFT);
153264b874cSmycroft 		if (bp->b_flags & B_READ)
15427ca6798Sperry 			memcpy(bp->b_data, base, bp->b_bcount);
155264b874cSmycroft 		else
15627ca6798Sperry 			memcpy(base, bp->b_data, bp->b_bcount);
157053e3ba1Sthorpej 		bp->b_resid = 0;
1585026e056Sthorpej 		biodone(bp);
159110d5cc2Sad 	} else if (mfsp->mfs_proc == curproc) {
1605026e056Sthorpej 		mfs_doio(bp, mfsp->mfs_baseoff);
161c4ae18d0Ssommerfeld 	} else if (doing_shutdown) {
162c4ae18d0Ssommerfeld 		/*
163c4ae18d0Ssommerfeld 		 * bitbucket I/O during shutdown.
164c4ae18d0Ssommerfeld 		 * Note that reads should *not* happen here, but..
165c4ae18d0Ssommerfeld 		 */
166c4ae18d0Ssommerfeld 		if (bp->b_flags & B_READ)
167c4ae18d0Ssommerfeld 			printf("warning: mfs read during shutdown\n");
168053e3ba1Sthorpej 		bp->b_resid = 0;
169c4ae18d0Ssommerfeld 		biodone(bp);
1705026e056Sthorpej 	} else {
171021b86ddSad 		mutex_enter(&mfs_lock);
17270de9736Syamt 		bufq_put(mfsp->mfs_buflist, bp);
173110d5cc2Sad 		cv_broadcast(&mfsp->mfs_cv);
174021b86ddSad 		mutex_exit(&mfs_lock);
1755026e056Sthorpej 	}
1765026e056Sthorpej 	return (0);
1775026e056Sthorpej }
1785026e056Sthorpej 
179264b874cSmycroft /*
1805026e056Sthorpej  * Memory file system I/O.
181264b874cSmycroft  */
1825026e056Sthorpej void
mfs_doio(struct buf * bp,void * base)18353524e44Schristos mfs_doio(struct buf *bp, void *base)
1845026e056Sthorpej {
185110d5cc2Sad 
18653524e44Schristos 	base = (char *)base + (bp->b_blkno << DEV_BSHIFT);
187264b874cSmycroft 	if (bp->b_flags & B_READ)
188264b874cSmycroft 		bp->b_error = copyin(base, bp->b_data, bp->b_bcount);
189264b874cSmycroft 	else
190264b874cSmycroft 		bp->b_error = copyout(bp->b_data, base, bp->b_bcount);
191a0d1fd8dSad 	if (bp->b_error == 0)
192462ac411Schs 		bp->b_resid = 0;
193264b874cSmycroft 	biodone(bp);
194264b874cSmycroft }
195264b874cSmycroft 
196264b874cSmycroft /*
197264b874cSmycroft  * This is a noop, simply returning what one has been given.
198264b874cSmycroft  */
199264b874cSmycroft int
mfs_bmap(void * v)20023ebf62dSxtraeme mfs_bmap(void *v)
201573481f5Schristos {
202264b874cSmycroft 	struct vop_bmap_args /* {
203264b874cSmycroft 		struct vnode *a_vp;
204264b874cSmycroft 		daddr_t  a_bn;
205264b874cSmycroft 		struct vnode **a_vpp;
206264b874cSmycroft 		daddr_t *a_bnp;
207264b874cSmycroft 		int *a_runp;
208573481f5Schristos 	} */ *ap = v;
209264b874cSmycroft 
210264b874cSmycroft 	if (ap->a_vpp != NULL)
211264b874cSmycroft 		*ap->a_vpp = ap->a_vp;
212264b874cSmycroft 	if (ap->a_bnp != NULL)
213264b874cSmycroft 		*ap->a_bnp = ap->a_bn;
214e5bc90f4Sfvdl 	if (ap->a_runp != NULL)
215e5bc90f4Sfvdl 		 *ap->a_runp = 0;
216264b874cSmycroft 	return (0);
217264b874cSmycroft }
218264b874cSmycroft 
219264b874cSmycroft /*
220264b874cSmycroft  * Memory filesystem close routine
221264b874cSmycroft  */
222264b874cSmycroft /* ARGSUSED */
223264b874cSmycroft int
mfs_close(void * v)22423ebf62dSxtraeme mfs_close(void *v)
225573481f5Schristos {
226264b874cSmycroft 	struct vop_close_args /* {
227264b874cSmycroft 		struct vnode *a_vp;
228264b874cSmycroft 		int  a_fflag;
229fc9422c9Selad 		kauth_cred_t a_cred;
230573481f5Schristos 	} */ *ap = v;
231169ac5b3Saugustss 	struct vnode *vp = ap->a_vp;
232169ac5b3Saugustss 	struct mfsnode *mfsp = VTOMFS(vp);
2335026e056Sthorpej 	struct buf *bp;
234264b874cSmycroft 	int error;
235264b874cSmycroft 
236264b874cSmycroft 	/*
2375026e056Sthorpej 	 * Finish any pending I/O requests.
2385026e056Sthorpej 	 */
239021b86ddSad 	mutex_enter(&mfs_lock);
24070de9736Syamt 	while ((bp = bufq_get(mfsp->mfs_buflist)) != NULL) {
241021b86ddSad 		mutex_exit(&mfs_lock);
2425026e056Sthorpej 		mfs_doio(bp, mfsp->mfs_baseoff);
243021b86ddSad 		mutex_enter(&mfs_lock);
2445026e056Sthorpej 	}
245021b86ddSad 	mutex_exit(&mfs_lock);
2465026e056Sthorpej 	/*
247264b874cSmycroft 	 * On last close of a memory filesystem
248264b874cSmycroft 	 * we must invalidate any in core blocks, so that
249264b874cSmycroft 	 * we can, free up its vnode.
250264b874cSmycroft 	 */
25161e8303eSpooka 	if ((error = vinvalbuf(vp, V_SAVE, ap->a_cred, curlwp, 0, 0)) != 0)
252264b874cSmycroft 		return (error);
253264b874cSmycroft 	/*
254264b874cSmycroft 	 * There should be no way to have any more uses of this
255264b874cSmycroft 	 * vnode, so if we find any other uses, it is a panic.
256264b874cSmycroft 	 */
25770de9736Syamt 	if (bufq_peek(mfsp->mfs_buflist) != NULL)
258264b874cSmycroft 		panic("mfs_close");
259264b874cSmycroft 	/*
260264b874cSmycroft 	 * Send a request to the filesystem server to exit.
261264b874cSmycroft 	 */
262021b86ddSad 	mutex_enter(&mfs_lock);
263d4c062b4Shannken 	mfsp->mfs_shutdown = 1;
264110d5cc2Sad 	cv_broadcast(&mfsp->mfs_cv);
265021b86ddSad 	mutex_exit(&mfs_lock);
266264b874cSmycroft 	return (0);
267264b874cSmycroft }
268264b874cSmycroft 
269264b874cSmycroft /*
270264b874cSmycroft  * Memory filesystem inactive routine
271264b874cSmycroft  */
272264b874cSmycroft /* ARGSUSED */
273264b874cSmycroft int
mfs_inactive(void * v)27423ebf62dSxtraeme mfs_inactive(void *v)
275573481f5Schristos {
27687fb3229Sriastradh 	struct vop_inactive_v2_args /* {
277264b874cSmycroft 		struct vnode *a_vp;
278573481f5Schristos 	} */ *ap = v;
279e5bc90f4Sfvdl 	struct vnode *vp = ap->a_vp;
280e5bc90f4Sfvdl 	struct mfsnode *mfsp = VTOMFS(vp);
281264b874cSmycroft 
28270de9736Syamt 	if (bufq_peek(mfsp->mfs_buflist) != NULL)
28348fda0b4Schristos 		panic("mfs_inactive: not inactive (mfs_buflist %p)",
28470de9736Syamt 			bufq_peek(mfsp->mfs_buflist));
2852547f842Shannken 
2862547f842Shannken 	return VOCALL(spec_vnodeop_p,  VOFFSET(vop_inactive), ap);
287264b874cSmycroft }
288264b874cSmycroft 
289264b874cSmycroft /*
290264b874cSmycroft  * Reclaim a memory filesystem devvp so that it can be reused.
291264b874cSmycroft  */
292264b874cSmycroft int
mfs_reclaim(void * v)29323ebf62dSxtraeme mfs_reclaim(void *v)
294573481f5Schristos {
2957f7aad09Sriastradh 	struct vop_reclaim_v2_args /* {
296264b874cSmycroft 		struct vnode *a_vp;
297573481f5Schristos 	} */ *ap = v;
298169ac5b3Saugustss 	struct vnode *vp = ap->a_vp;
299110d5cc2Sad 	struct mfsnode *mfsp = VTOMFS(vp);
300021b86ddSad 	int refcnt;
301110d5cc2Sad 
302021b86ddSad 	mutex_enter(&mfs_lock);
303264b874cSmycroft 	vp->v_data = NULL;
304021b86ddSad 	refcnt = --mfsp->mfs_refcnt;
305021b86ddSad 	mutex_exit(&mfs_lock);
306021b86ddSad 
307021b86ddSad 	if (refcnt == 0) {
308021b86ddSad 		bufq_free(mfsp->mfs_buflist);
309021b86ddSad 		cv_destroy(&mfsp->mfs_cv);
310021b86ddSad 		kmem_free(mfsp, sizeof(*mfsp));
311021b86ddSad 	}
312021b86ddSad 
3132547f842Shannken 	return VOCALL(spec_vnodeop_p,  VOFFSET(vop_reclaim), ap);
314264b874cSmycroft }
315264b874cSmycroft 
316264b874cSmycroft /*
317264b874cSmycroft  * Print out the contents of an mfsnode.
318264b874cSmycroft  */
319264b874cSmycroft int
mfs_print(void * v)32023ebf62dSxtraeme mfs_print(void *v)
321573481f5Schristos {
322264b874cSmycroft 	struct vop_print_args /* {
323264b874cSmycroft 		struct vnode *a_vp;
324573481f5Schristos 	} */ *ap = v;
325169ac5b3Saugustss 	struct mfsnode *mfsp = VTOMFS(ap->a_vp);
326264b874cSmycroft 
3276d7f14dcSthorpej 	printf("tag VT_MFS, pid %d, base %p, size %ld\n",
3286d7f14dcSthorpej 	    (mfsp->mfs_proc != NULL) ? mfsp->mfs_proc->p_pid : 0,
3299c956342Scgd 	    mfsp->mfs_baseoff, mfsp->mfs_size);
330264b874cSmycroft 	return (0);
331264b874cSmycroft }
332