xref: /openbsd/sys/miscfs/deadfs/dead_vnops.c (revision 7b36286a)
1 /*	$OpenBSD: dead_vnops.c,v 1.21 2008/05/08 17:45:45 thib Exp $	*/
2 /*	$NetBSD: dead_vnops.c,v 1.16 1996/02/13 13:12:48 mycroft Exp $	*/
3 
4 /*
5  * Copyright (c) 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)dead_vnops.c	8.2 (Berkeley) 11/21/94
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/time.h>
38 #include <sys/vnode.h>
39 #include <sys/errno.h>
40 #include <sys/namei.h>
41 #include <sys/buf.h>
42 #include <sys/proc.h>
43 #include <sys/poll.h>
44 
45 /*
46  * Prototypes for dead operations on vnodes.
47  */
48 int	dead_badop(void *);
49 int	dead_ebadf(void *);
50 
51 int	dead_open(void *);
52 int	dead_read(void *);
53 int	dead_write(void *);
54 int	dead_ioctl(void *);
55 int	dead_poll(void *);
56 int	dead_lock(void *);
57 int	dead_bmap(void *);
58 int	dead_strategy(void *);
59 int	dead_print(void *);
60 
61 int	chkvnlock(struct vnode *);
62 
63 int (**dead_vnodeop_p)(void *);
64 
65 struct vnodeopv_entry_desc dead_vnodeop_entries[] = {
66 	{ &vop_default_desc, eopnotsupp },
67 	{ &vop_lookup_desc, vop_generic_lookup },	/* lookup */
68 	{ &vop_create_desc, dead_badop },	/* create */
69 	{ &vop_mknod_desc, dead_badop },	/* mknod */
70 	{ &vop_open_desc, dead_open },		/* open */
71 	{ &vop_close_desc, nullop },		/* close */
72 	{ &vop_access_desc, dead_ebadf },	/* access */
73 	{ &vop_getattr_desc, dead_ebadf },	/* getattr */
74 	{ &vop_setattr_desc, dead_ebadf },	/* setattr */
75 	{ &vop_read_desc, dead_read },		/* read */
76 	{ &vop_write_desc, dead_write },	/* write */
77 	{ &vop_ioctl_desc, dead_ioctl },	/* ioctl */
78 	{ &vop_poll_desc, dead_poll },		/* poll */
79 	{ &vop_fsync_desc, nullop },		/* fsync */
80 	{ &vop_remove_desc, dead_badop },	/* remove */
81 	{ &vop_link_desc, dead_badop },		/* link */
82 	{ &vop_rename_desc, dead_badop },	/* rename */
83 	{ &vop_mkdir_desc, dead_badop },	/* mkdir */
84 	{ &vop_rmdir_desc, dead_badop },	/* rmdir */
85 	{ &vop_symlink_desc, dead_badop },	/* symlink */
86 	{ &vop_readdir_desc, dead_ebadf },	/* readdir */
87 	{ &vop_readlink_desc, dead_ebadf },	/* readlink */
88 	{ &vop_abortop_desc, dead_badop },	/* abortop */
89 	{ &vop_inactive_desc, nullop },		/* inactive */
90 	{ &vop_reclaim_desc, nullop },		/* reclaim */
91 	{ &vop_lock_desc, dead_lock },		/* lock */
92 	{ &vop_unlock_desc, vop_generic_unlock },	/* unlock */
93 	{ &vop_bmap_desc, dead_bmap },		/* bmap */
94 	{ &vop_strategy_desc, dead_strategy },	/* strategy */
95 	{ &vop_print_desc, dead_print },	/* print */
96 	{ &vop_islocked_desc, vop_generic_islocked },	/* islocked */
97 	{ &vop_pathconf_desc, dead_ebadf },	/* pathconf */
98 	{ &vop_advlock_desc, dead_ebadf },	/* advlock */
99 	{ &vop_bwrite_desc, nullop },		/* bwrite */
100 	{ (struct vnodeop_desc*)NULL, (int(*)(void *))NULL }
101 };
102 struct vnodeopv_desc dead_vnodeop_opv_desc =
103 	{ &dead_vnodeop_p, dead_vnodeop_entries };
104 
105 /*
106  * Open always fails as if device did not exist.
107  */
108 /* ARGSUSED */
109 int
110 dead_open(void *v)
111 {
112 	return (ENXIO);
113 }
114 
115 /*
116  * Vnode op for read
117  */
118 /* ARGSUSED */
119 int
120 dead_read(void *v)
121 {
122 	struct vop_read_args *ap = v;
123 
124 	if (chkvnlock(ap->a_vp))
125 		panic("dead_read: lock");
126 	/*
127 	 * Return EOF for tty devices, EIO for others
128 	 */
129 	if ((ap->a_vp->v_flag & VISTTY) == 0)
130 		return (EIO);
131 	return (0);
132 }
133 
134 /*
135  * Vnode op for write
136  */
137 /* ARGSUSED */
138 int
139 dead_write(void *v)
140 {
141 	struct vop_write_args *ap = v;
142 
143 	if (chkvnlock(ap->a_vp))
144 		panic("dead_write: lock");
145 	return (EIO);
146 }
147 
148 /*
149  * Device ioctl operation.
150  */
151 /* ARGSUSED */
152 int
153 dead_ioctl(void *v)
154 {
155 	struct vop_ioctl_args *ap = v;
156 
157 	if (!chkvnlock(ap->a_vp))
158 		return (EBADF);
159 	return (VCALL(ap->a_vp, VOFFSET(vop_ioctl), ap));
160 }
161 
162 /* ARGSUSED */
163 int
164 dead_poll(void *v)
165 {
166 #if 0
167 	struct vop_poll_args *ap = v;
168 #endif
169 
170 	/*
171 	 * Let the user find out that the descriptor is gone.
172 	 */
173 	return (POLLHUP);
174 }
175 
176 /*
177  * Just call the device strategy routine
178  */
179 int
180 dead_strategy(void *v)
181 {
182 	struct vop_strategy_args *ap = v;
183 	int s;
184 
185 	if (ap->a_bp->b_vp == NULL || !chkvnlock(ap->a_bp->b_vp)) {
186 		ap->a_bp->b_flags |= B_ERROR;
187 		s = splbio();
188 		biodone(ap->a_bp);
189 		splx(s);
190 		return (EIO);
191 	}
192 	return (VOP_STRATEGY(ap->a_bp));
193 }
194 
195 /*
196  * Wait until the vnode has finished changing state.
197  */
198 int
199 dead_lock(void *v)
200 {
201 	struct vop_lock_args *ap = v;
202 	struct vnode *vp = ap->a_vp;
203 
204 	if (ap->a_flags & LK_DRAIN || !chkvnlock(vp))
205 		return (0);
206 
207 	return (VCALL(vp, VOFFSET(vop_lock), ap));
208 }
209 
210 /*
211  * Wait until the vnode has finished changing state.
212  */
213 int
214 dead_bmap(void *v)
215 {
216 	struct vop_bmap_args *ap = v;
217 
218 	if (!chkvnlock(ap->a_vp))
219 		return (EIO);
220 	return (VOP_BMAP(ap->a_vp, ap->a_bn, ap->a_vpp, ap->a_bnp, ap->a_runp));
221 }
222 
223 /*
224  * Print out the contents of a dead vnode.
225  */
226 /* ARGSUSED */
227 int
228 dead_print(void *v)
229 {
230 	printf("tag VT_NON, dead vnode\n");
231 	return 0;
232 }
233 
234 /*
235  * Empty vnode failed operation
236  */
237 /*ARGSUSED*/
238 int
239 dead_ebadf(void *v)
240 {
241 	return (EBADF);
242 }
243 
244 /*
245  * Empty vnode bad operation
246  */
247 /*ARGSUSED*/
248 int
249 dead_badop(void *v)
250 {
251 	panic("dead_badop called");
252 	/* NOTREACHED */
253 }
254 
255 /*
256  * We have to wait during times when the vnode is
257  * in a state of change.
258  */
259 int
260 chkvnlock(struct vnode *vp)
261 {
262 	int locked = 0;
263 
264 	while (vp->v_flag & VXLOCK) {
265 		vp->v_flag |= VXWANT;
266 		tsleep(vp, PINOD, "chkvnlock", 0);
267 		locked = 1;
268 	}
269 	return (locked);
270 }
271