1 /* $NetBSD: mfs_vnops.c,v 1.64 2022/03/19 13:48:42 hannken Exp $ */
2
3 /*
4 * Copyright (c) 1989, 1993
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_vnops.c 8.11 (Berkeley) 5/22/95
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: mfs_vnops.c,v 1.64 2022/03/19 13:48:42 hannken Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/time.h>
40 #include <sys/kernel.h>
41 #include <sys/proc.h>
42 #include <sys/buf.h>
43 #include <sys/bufq.h>
44 #include <sys/vnode.h>
45 #include <sys/kmem.h>
46
47 #include <miscfs/genfs/genfs.h>
48 #include <miscfs/specfs/specdev.h>
49
50 #include <machine/vmparam.h>
51
52 #include <ufs/mfs/mfsnode.h>
53 #include <ufs/mfs/mfs_extern.h>
54
55 /*
56 * mfs vnode operations.
57 */
58 int (**mfs_vnodeop_p)(void *);
59 const struct vnodeopv_entry_desc mfs_vnodeop_entries[] = {
60 { &vop_default_desc, vn_default_error },
61 { &vop_parsepath_desc, genfs_parsepath }, /* parsepath */
62 { &vop_lookup_desc, genfs_badop }, /* lookup */
63 { &vop_create_desc, genfs_badop }, /* create */
64 { &vop_mknod_desc, genfs_badop }, /* mknod */
65 { &vop_open_desc, mfs_open }, /* open */
66 { &vop_close_desc, mfs_close }, /* close */
67 { &vop_access_desc, genfs_badop }, /* access */
68 { &vop_accessx_desc, genfs_badop }, /* accessx */
69 { &vop_getattr_desc, genfs_badop }, /* getattr */
70 { &vop_setattr_desc, genfs_badop }, /* setattr */
71 { &vop_read_desc, genfs_badop }, /* read */
72 { &vop_write_desc, genfs_badop }, /* write */
73 { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */
74 { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */
75 { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */
76 { &vop_poll_desc, genfs_badop }, /* poll */
77 { &vop_revoke_desc, genfs_revoke }, /* revoke */
78 { &vop_mmap_desc, genfs_badop }, /* mmap */
79 { &vop_fsync_desc, spec_fsync }, /* fsync */
80 { &vop_seek_desc, genfs_badop }, /* seek */
81 { &vop_remove_desc, genfs_badop }, /* remove */
82 { &vop_link_desc, genfs_badop }, /* link */
83 { &vop_rename_desc, genfs_badop }, /* rename */
84 { &vop_mkdir_desc, genfs_badop }, /* mkdir */
85 { &vop_rmdir_desc, genfs_badop }, /* rmdir */
86 { &vop_symlink_desc, genfs_badop }, /* symlink */
87 { &vop_readdir_desc, genfs_badop }, /* readdir */
88 { &vop_readlink_desc, genfs_badop }, /* readlink */
89 { &vop_abortop_desc, genfs_badop }, /* abortop */
90 { &vop_inactive_desc, mfs_inactive }, /* inactive */
91 { &vop_reclaim_desc, mfs_reclaim }, /* reclaim */
92 { &vop_lock_desc, genfs_lock }, /* lock */
93 { &vop_unlock_desc, genfs_unlock }, /* unlock */
94 { &vop_bmap_desc, mfs_bmap }, /* bmap */
95 { &vop_strategy_desc, mfs_strategy }, /* strategy */
96 { &vop_print_desc, mfs_print }, /* print */
97 { &vop_islocked_desc, genfs_islocked }, /* islocked */
98 { &vop_pathconf_desc, genfs_badop }, /* pathconf */
99 { &vop_advlock_desc, genfs_badop }, /* advlock */
100 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
101 { &vop_putpages_desc, genfs_null_putpages }, /* putpages */
102 { NULL, NULL }
103 };
104 const struct vnodeopv_desc mfs_vnodeop_opv_desc =
105 { &mfs_vnodeop_p, mfs_vnodeop_entries };
106
107 /*
108 * Vnode Operations.
109 *
110 * Open called to allow memory filesystem to initialize and
111 * validate before actual IO. Record our process identifier
112 * so we can tell when we are doing I/O to ourself.
113 */
114 /* ARGSUSED */
115 int
mfs_open(void * v)116 mfs_open(void *v)
117 {
118 struct vop_open_args /* {
119 struct vnode *a_vp;
120 int a_mode;
121 kauth_cred_t a_cred;
122 } */ *ap = v;
123
124 if (ap->a_vp->v_type != VBLK) {
125 panic("mfs_open not VBLK");
126 /* NOTREACHED */
127 }
128 return (0);
129 }
130
131 /*
132 * Pass I/O requests to the memory filesystem process.
133 */
134 int
mfs_strategy(void * v)135 mfs_strategy(void *v)
136 {
137 struct vop_strategy_args /* {
138 struct vnode *a_vp;
139 struct buf *a_bp;
140 } */ *ap = v;
141 struct vnode *vp = ap->a_vp;
142 struct buf *bp = ap->a_bp;
143 struct mfsnode *mfsp;
144
145 if (vp->v_type != VBLK || vrefcnt(vp) == 0)
146 panic("mfs_strategy: bad dev");
147 mfsp = VTOMFS(vp);
148 /* check for mini-root access */
149 if (mfsp->mfs_proc == NULL) {
150 void *base;
151
152 base = (char *)mfsp->mfs_baseoff + (bp->b_blkno << DEV_BSHIFT);
153 if (bp->b_flags & B_READ)
154 memcpy(bp->b_data, base, bp->b_bcount);
155 else
156 memcpy(base, bp->b_data, bp->b_bcount);
157 bp->b_resid = 0;
158 biodone(bp);
159 } else if (mfsp->mfs_proc == curproc) {
160 mfs_doio(bp, mfsp->mfs_baseoff);
161 } else if (doing_shutdown) {
162 /*
163 * bitbucket I/O during shutdown.
164 * Note that reads should *not* happen here, but..
165 */
166 if (bp->b_flags & B_READ)
167 printf("warning: mfs read during shutdown\n");
168 bp->b_resid = 0;
169 biodone(bp);
170 } else {
171 mutex_enter(&mfs_lock);
172 bufq_put(mfsp->mfs_buflist, bp);
173 cv_broadcast(&mfsp->mfs_cv);
174 mutex_exit(&mfs_lock);
175 }
176 return (0);
177 }
178
179 /*
180 * Memory file system I/O.
181 */
182 void
mfs_doio(struct buf * bp,void * base)183 mfs_doio(struct buf *bp, void *base)
184 {
185
186 base = (char *)base + (bp->b_blkno << DEV_BSHIFT);
187 if (bp->b_flags & B_READ)
188 bp->b_error = copyin(base, bp->b_data, bp->b_bcount);
189 else
190 bp->b_error = copyout(bp->b_data, base, bp->b_bcount);
191 if (bp->b_error == 0)
192 bp->b_resid = 0;
193 biodone(bp);
194 }
195
196 /*
197 * This is a noop, simply returning what one has been given.
198 */
199 int
mfs_bmap(void * v)200 mfs_bmap(void *v)
201 {
202 struct vop_bmap_args /* {
203 struct vnode *a_vp;
204 daddr_t a_bn;
205 struct vnode **a_vpp;
206 daddr_t *a_bnp;
207 int *a_runp;
208 } */ *ap = v;
209
210 if (ap->a_vpp != NULL)
211 *ap->a_vpp = ap->a_vp;
212 if (ap->a_bnp != NULL)
213 *ap->a_bnp = ap->a_bn;
214 if (ap->a_runp != NULL)
215 *ap->a_runp = 0;
216 return (0);
217 }
218
219 /*
220 * Memory filesystem close routine
221 */
222 /* ARGSUSED */
223 int
mfs_close(void * v)224 mfs_close(void *v)
225 {
226 struct vop_close_args /* {
227 struct vnode *a_vp;
228 int a_fflag;
229 kauth_cred_t a_cred;
230 } */ *ap = v;
231 struct vnode *vp = ap->a_vp;
232 struct mfsnode *mfsp = VTOMFS(vp);
233 struct buf *bp;
234 int error;
235
236 /*
237 * Finish any pending I/O requests.
238 */
239 mutex_enter(&mfs_lock);
240 while ((bp = bufq_get(mfsp->mfs_buflist)) != NULL) {
241 mutex_exit(&mfs_lock);
242 mfs_doio(bp, mfsp->mfs_baseoff);
243 mutex_enter(&mfs_lock);
244 }
245 mutex_exit(&mfs_lock);
246 /*
247 * On last close of a memory filesystem
248 * we must invalidate any in core blocks, so that
249 * we can, free up its vnode.
250 */
251 if ((error = vinvalbuf(vp, V_SAVE, ap->a_cred, curlwp, 0, 0)) != 0)
252 return (error);
253 /*
254 * There should be no way to have any more uses of this
255 * vnode, so if we find any other uses, it is a panic.
256 */
257 if (bufq_peek(mfsp->mfs_buflist) != NULL)
258 panic("mfs_close");
259 /*
260 * Send a request to the filesystem server to exit.
261 */
262 mutex_enter(&mfs_lock);
263 mfsp->mfs_shutdown = 1;
264 cv_broadcast(&mfsp->mfs_cv);
265 mutex_exit(&mfs_lock);
266 return (0);
267 }
268
269 /*
270 * Memory filesystem inactive routine
271 */
272 /* ARGSUSED */
273 int
mfs_inactive(void * v)274 mfs_inactive(void *v)
275 {
276 struct vop_inactive_v2_args /* {
277 struct vnode *a_vp;
278 } */ *ap = v;
279 struct vnode *vp = ap->a_vp;
280 struct mfsnode *mfsp = VTOMFS(vp);
281
282 if (bufq_peek(mfsp->mfs_buflist) != NULL)
283 panic("mfs_inactive: not inactive (mfs_buflist %p)",
284 bufq_peek(mfsp->mfs_buflist));
285
286 return VOCALL(spec_vnodeop_p, VOFFSET(vop_inactive), ap);
287 }
288
289 /*
290 * Reclaim a memory filesystem devvp so that it can be reused.
291 */
292 int
mfs_reclaim(void * v)293 mfs_reclaim(void *v)
294 {
295 struct vop_reclaim_v2_args /* {
296 struct vnode *a_vp;
297 } */ *ap = v;
298 struct vnode *vp = ap->a_vp;
299 struct mfsnode *mfsp = VTOMFS(vp);
300 int refcnt;
301
302 mutex_enter(&mfs_lock);
303 vp->v_data = NULL;
304 refcnt = --mfsp->mfs_refcnt;
305 mutex_exit(&mfs_lock);
306
307 if (refcnt == 0) {
308 bufq_free(mfsp->mfs_buflist);
309 cv_destroy(&mfsp->mfs_cv);
310 kmem_free(mfsp, sizeof(*mfsp));
311 }
312
313 return VOCALL(spec_vnodeop_p, VOFFSET(vop_reclaim), ap);
314 }
315
316 /*
317 * Print out the contents of an mfsnode.
318 */
319 int
mfs_print(void * v)320 mfs_print(void *v)
321 {
322 struct vop_print_args /* {
323 struct vnode *a_vp;
324 } */ *ap = v;
325 struct mfsnode *mfsp = VTOMFS(ap->a_vp);
326
327 printf("tag VT_MFS, pid %d, base %p, size %ld\n",
328 (mfsp->mfs_proc != NULL) ? mfsp->mfs_proc->p_pid : 0,
329 mfsp->mfs_baseoff, mfsp->mfs_size);
330 return (0);
331 }
332