coda_psdev.c revision 1.2 1 1.2 rvb /* $NetBSD: coda_psdev.c,v 1.2 1998/09/08 17:12:47 rvb Exp $ */
2 1.2 rvb
3 1.1 rvb /*
4 1.2 rvb *
5 1.2 rvb * Coda: an Experimental Distributed File System
6 1.2 rvb * Release 3.1
7 1.2 rvb *
8 1.2 rvb * Copyright (c) 1987-1998 Carnegie Mellon University
9 1.2 rvb * All Rights Reserved
10 1.2 rvb *
11 1.2 rvb * Permission to use, copy, modify and distribute this software and its
12 1.2 rvb * documentation is hereby granted, provided that both the copyright
13 1.2 rvb * notice and this permission notice appear in all copies of the
14 1.2 rvb * software, derivative works or modified versions, and any portions
15 1.2 rvb * thereof, and that both notices appear in supporting documentation, and
16 1.2 rvb * that credit is given to Carnegie Mellon University in all documents
17 1.2 rvb * and publicity pertaining to direct or indirect use of this code or its
18 1.2 rvb * derivatives.
19 1.2 rvb *
20 1.2 rvb * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS,
21 1.2 rvb * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS
22 1.2 rvb * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON
23 1.2 rvb * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
24 1.2 rvb * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF
25 1.2 rvb * ANY DERIVATIVE WORK.
26 1.2 rvb *
27 1.2 rvb * Carnegie Mellon encourages users of this software to return any
28 1.2 rvb * improvements or extensions that they make, and to grant Carnegie
29 1.2 rvb * Mellon the rights to redistribute these changes without encumbrance.
30 1.2 rvb *
31 1.2 rvb * @(#) cfs/cfs_psdev.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $
32 1.2 rvb */
33 1.1 rvb
34 1.1 rvb /*
35 1.1 rvb * Mach Operating System
36 1.1 rvb * Copyright (c) 1989 Carnegie-Mellon University
37 1.1 rvb * All rights reserved. The CMU software License Agreement specifies
38 1.1 rvb * the terms and conditions for use and redistribution.
39 1.1 rvb */
40 1.1 rvb
41 1.1 rvb /*
42 1.1 rvb * This code was written for the Coda file system at Carnegie Mellon
43 1.1 rvb * University. Contributers include David Steere, James Kistler, and
44 1.1 rvb * M. Satyanarayanan. */
45 1.1 rvb
46 1.1 rvb /* These routines define the psuedo device for communication between
47 1.1 rvb * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
48 1.1 rvb * but I moved them to make it easier to port the Minicache without
49 1.1 rvb * porting coda. -- DCS 10/12/94
50 1.1 rvb */
51 1.1 rvb
52 1.1 rvb /*
53 1.1 rvb * HISTORY
54 1.1 rvb * $Log: coda_psdev.c,v $
55 1.2 rvb * Revision 1.2 1998/09/08 17:12:47 rvb
56 1.2 rvb * Pass2 complete
57 1.2 rvb *
58 1.1 rvb * Revision 1.1.1.1 1998/08/29 21:26:45 rvb
59 1.1 rvb * Very Preliminary Coda
60 1.1 rvb *
61 1.1 rvb * Revision 1.9 1998/08/28 18:12:17 rvb
62 1.1 rvb * Now it also works on FreeBSD -current. This code will be
63 1.1 rvb * committed to the FreeBSD -current and NetBSD -current
64 1.1 rvb * trees. It will then be tailored to the particular platform
65 1.1 rvb * by flushing conditional code.
66 1.1 rvb *
67 1.1 rvb * Revision 1.8 1998/08/18 17:05:15 rvb
68 1.1 rvb * Don't use __RCSID now
69 1.1 rvb *
70 1.1 rvb * Revision 1.7 1998/08/18 16:31:41 rvb
71 1.1 rvb * Sync the code for NetBSD -current; test on 1.3 later
72 1.1 rvb *
73 1.1 rvb * Revision 1.8 1998/06/09 23:30:42 rvb
74 1.1 rvb * Try to allow ^C -- take 1
75 1.1 rvb *
76 1.1 rvb * Revision 1.5.2.8 98/01/23 11:21:04 rvb
77 1.1 rvb * Sync with 2.2.5
78 1.1 rvb *
79 1.1 rvb * Revision 1.5.2.7 98/01/22 22:22:21 rvb
80 1.1 rvb * sync 1.2 and 1.3
81 1.1 rvb *
82 1.1 rvb * Revision 1.5.2.6 98/01/22 13:11:24 rvb
83 1.1 rvb * Move makecfsnode ctlfid later so vfsp is known; work on ^c and ^z
84 1.1 rvb *
85 1.1 rvb * Revision 1.5.2.5 97/12/16 22:01:27 rvb
86 1.1 rvb * Oops add cfs_subr.h cfs_venus.h; sync with peter
87 1.1 rvb *
88 1.1 rvb * Revision 1.5.2.4 97/12/16 12:40:05 rvb
89 1.1 rvb * Sync with 1.3
90 1.1 rvb *
91 1.1 rvb * Revision 1.5.2.3 97/12/10 14:08:24 rvb
92 1.1 rvb * Fix O_ flags; check result in cfscall
93 1.1 rvb *
94 1.1 rvb * Revision 1.5.2.2 97/12/10 11:40:24 rvb
95 1.1 rvb * No more ody
96 1.1 rvb *
97 1.1 rvb * Revision 1.5.2.1 97/12/06 17:41:20 rvb
98 1.1 rvb * Sync with peters coda.h
99 1.1 rvb *
100 1.1 rvb * Revision 1.5 97/12/05 10:39:16 rvb
101 1.1 rvb * Read CHANGES
102 1.1 rvb *
103 1.1 rvb * Revision 1.4.18.9 97/12/05 08:58:07 rvb
104 1.1 rvb * peter found this one
105 1.1 rvb *
106 1.1 rvb * Revision 1.4.18.8 97/11/26 15:28:57 rvb
107 1.1 rvb * Cant make downcall pbuf == union cfs_downcalls yet
108 1.1 rvb *
109 1.1 rvb * Revision 1.4.18.7 97/11/25 09:40:49 rvb
110 1.1 rvb * Final cfs_venus.c w/o macros, but one locking bug
111 1.1 rvb *
112 1.1 rvb * Revision 1.4.18.6 97/11/20 11:46:41 rvb
113 1.1 rvb * Capture current cfs_venus
114 1.1 rvb *
115 1.1 rvb * Revision 1.4.18.5 97/11/18 10:27:15 rvb
116 1.1 rvb * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c
117 1.1 rvb * cfs_nb_foo and cfs_foo are joined
118 1.1 rvb *
119 1.1 rvb * Revision 1.4.18.4 97/11/13 22:02:59 rvb
120 1.1 rvb * pass2 cfs_NetBSD.h mt
121 1.1 rvb *
122 1.1 rvb * Revision 1.4.18.3 97/11/12 12:09:38 rvb
123 1.1 rvb * reorg pass1
124 1.1 rvb *
125 1.1 rvb * Revision 1.4.18.2 97/10/29 16:06:09 rvb
126 1.1 rvb * Kill DYING
127 1.1 rvb *
128 1.1 rvb * Revision 1.4.18.1 1997/10/28 23:10:15 rvb
129 1.1 rvb * >64Meg; venus can be killed!
130 1.1 rvb *
131 1.1 rvb * Revision 1.4 1996/12/12 22:10:58 bnoble
132 1.1 rvb * Fixed the "downcall invokes venus operation" deadlock in all known cases.
133 1.1 rvb * There may be more
134 1.1 rvb *
135 1.1 rvb * Revision 1.3 1996/11/13 04:14:20 bnoble
136 1.1 rvb * Merging BNOBLE_WORK_6_20_96 into main line
137 1.1 rvb *
138 1.1 rvb * Revision 1.2.8.1 1996/08/22 14:25:04 bnoble
139 1.1 rvb * Added a return code from vc_nb_close
140 1.1 rvb *
141 1.1 rvb * Revision 1.2 1996/01/02 16:56:58 bnoble
142 1.1 rvb * Added support for Coda MiniCache and raw inode calls (final commit)
143 1.1 rvb *
144 1.1 rvb * Revision 1.1.2.1 1995/12/20 01:57:24 bnoble
145 1.1 rvb * Added CFS-specific files
146 1.1 rvb *
147 1.1 rvb * Revision 1.1 1995/03/14 20:52:15 bnoble
148 1.1 rvb * Initial revision
149 1.1 rvb *
150 1.1 rvb */
151 1.1 rvb
152 1.1 rvb /* These routines are the device entry points for Venus. */
153 1.1 rvb
154 1.1 rvb extern int cfsnc_initialized; /* Set if cache has been initialized */
155 1.1 rvb
156 1.1 rvb #include <vcfs.h>
157 1.1 rvb #include <sys/param.h>
158 1.1 rvb #include <sys/systm.h>
159 1.1 rvb #include <sys/kernel.h>
160 1.1 rvb #include <sys/malloc.h>
161 1.1 rvb #include <sys/proc.h>
162 1.1 rvb #include <sys/mount.h>
163 1.1 rvb #include <sys/file.h>
164 1.1 rvb #include <sys/ioctl.h>
165 1.1 rvb #include <sys/poll.h>
166 1.1 rvb #include <sys/select.h>
167 1.1 rvb
168 1.1 rvb #include <cfs/coda.h>
169 1.1 rvb #include <cfs/cnode.h>
170 1.2 rvb #include <cfs/cfsnc.h>
171 1.2 rvb #include <cfs/cfsio.h>
172 1.1 rvb
173 1.2 rvb #define CTL_C
174 1.1 rvb
175 1.1 rvb int cfs_psdev_print_entry = 0;
176 1.1 rvb #define ENTRY if(cfs_psdev_print_entry) myprintf(("Entered %s\n",__FUNCTION__))
177 1.1 rvb
178 1.1 rvb void vcfsattach(int n);
179 1.1 rvb int vc_nb_open(dev_t dev, int flag, int mode, struct proc *p);
180 1.1 rvb int vc_nb_close (dev_t dev, int flag, int mode, struct proc *p);
181 1.1 rvb int vc_nb_read(dev_t dev, struct uio *uiop, int flag);
182 1.1 rvb int vc_nb_write(dev_t dev, struct uio *uiop, int flag);
183 1.1 rvb int vc_nb_ioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p);
184 1.1 rvb int vc_nb_poll(dev_t dev, int events, struct proc *p);
185 1.1 rvb
186 1.1 rvb struct vmsg {
187 1.1 rvb struct queue vm_chain;
188 1.1 rvb caddr_t vm_data;
189 1.1 rvb u_short vm_flags;
190 1.1 rvb u_short vm_inSize; /* Size is at most 5000 bytes */
191 1.1 rvb u_short vm_outSize;
192 1.1 rvb u_short vm_opcode; /* copied from data to save ptr lookup */
193 1.1 rvb int vm_unique;
194 1.1 rvb caddr_t vm_sleep; /* Not used by Mach. */
195 1.1 rvb };
196 1.1 rvb
197 1.1 rvb #define VM_READ 1
198 1.1 rvb #define VM_WRITE 2
199 1.1 rvb #define VM_INTR 4
200 1.1 rvb
201 1.1 rvb /* vcfsattach: do nothing */
202 1.1 rvb void
203 1.1 rvb vcfsattach(n)
204 1.1 rvb int n;
205 1.1 rvb {
206 1.1 rvb }
207 1.1 rvb
208 1.1 rvb /*
209 1.1 rvb * These functions are written for NetBSD.
210 1.1 rvb */
211 1.1 rvb int
212 1.1 rvb vc_nb_open(dev, flag, mode, p)
213 1.1 rvb dev_t dev;
214 1.1 rvb int flag;
215 1.1 rvb int mode;
216 1.1 rvb struct proc *p; /* NetBSD only */
217 1.1 rvb {
218 1.1 rvb register struct vcomm *vcp;
219 1.1 rvb
220 1.1 rvb ENTRY;
221 1.1 rvb
222 1.1 rvb if (minor(dev) >= NVCFS || minor(dev) < 0)
223 1.1 rvb return(ENXIO);
224 1.1 rvb
225 1.1 rvb if (!cfsnc_initialized)
226 1.1 rvb cfsnc_init();
227 1.1 rvb
228 1.1 rvb vcp = &cfs_mnttbl[minor(dev)].mi_vcomm;
229 1.1 rvb if (VC_OPEN(vcp))
230 1.1 rvb return(EBUSY);
231 1.1 rvb
232 1.1 rvb bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
233 1.1 rvb INIT_QUEUE(vcp->vc_requests);
234 1.1 rvb INIT_QUEUE(vcp->vc_replys);
235 1.1 rvb MARK_VC_OPEN(vcp);
236 1.1 rvb
237 1.1 rvb cfs_mnttbl[minor(dev)].mi_vfsp = NULL;
238 1.1 rvb cfs_mnttbl[minor(dev)].mi_rootvp = NULL;
239 1.1 rvb
240 1.1 rvb return(0);
241 1.1 rvb }
242 1.1 rvb
243 1.1 rvb int
244 1.1 rvb vc_nb_close (dev, flag, mode, p)
245 1.1 rvb dev_t dev;
246 1.1 rvb int flag;
247 1.1 rvb int mode;
248 1.1 rvb struct proc *p;
249 1.1 rvb {
250 1.1 rvb register struct vcomm *vcp;
251 1.1 rvb register struct vmsg *vmp;
252 1.1 rvb struct cfs_mntinfo *mi;
253 1.1 rvb int err;
254 1.1 rvb
255 1.1 rvb ENTRY;
256 1.1 rvb
257 1.1 rvb if (minor(dev) >= NVCFS || minor(dev) < 0)
258 1.1 rvb return(ENXIO);
259 1.1 rvb
260 1.1 rvb mi = &cfs_mnttbl[minor(dev)];
261 1.1 rvb vcp = &(mi->mi_vcomm);
262 1.1 rvb
263 1.1 rvb if (!VC_OPEN(vcp))
264 1.1 rvb panic("vcclose: not open");
265 1.1 rvb
266 1.1 rvb /* prevent future operations on this vfs from succeeding by auto-
267 1.1 rvb * unmounting any vfs mounted via this device. This frees user or
268 1.1 rvb * sysadm from having to remember where all mount points are located.
269 1.1 rvb * Put this before WAKEUPs to avoid queuing new messages between
270 1.1 rvb * the WAKEUP and the unmount (which can happen if we're unlucky)
271 1.1 rvb */
272 1.1 rvb if (mi->mi_rootvp) {
273 1.1 rvb /* Let unmount know this is for real */
274 1.1 rvb VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
275 1.1 rvb if (vfs_busy(mi->mi_vfsp, 0, 0))
276 1.1 rvb return (EBUSY);
277 1.1 rvb cfs_unmounting(mi->mi_vfsp);
278 1.1 rvb err = dounmount(mi->mi_vfsp, flag, p);
279 1.1 rvb if (err)
280 1.1 rvb myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
281 1.1 rvb err, minor(dev)));
282 1.1 rvb }
283 1.1 rvb
284 1.1 rvb /* Wakeup clients so they can return. */
285 1.1 rvb for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
286 1.1 rvb !EOQ(vmp, vcp->vc_requests);
287 1.1 rvb vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
288 1.1 rvb {
289 1.1 rvb /* Free signal request messages and don't wakeup cause
290 1.1 rvb no one is waiting. */
291 1.1 rvb if (vmp->vm_opcode == CFS_SIGNAL) {
292 1.1 rvb CFS_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
293 1.1 rvb CFS_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
294 1.1 rvb continue;
295 1.1 rvb }
296 1.1 rvb
297 1.1 rvb wakeup(&vmp->vm_sleep);
298 1.1 rvb }
299 1.1 rvb
300 1.1 rvb for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
301 1.1 rvb !EOQ(vmp, vcp->vc_replys);
302 1.1 rvb vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
303 1.1 rvb {
304 1.1 rvb wakeup(&vmp->vm_sleep);
305 1.1 rvb }
306 1.1 rvb
307 1.1 rvb MARK_VC_CLOSED(vcp);
308 1.1 rvb return 0;
309 1.1 rvb }
310 1.1 rvb
311 1.1 rvb int
312 1.1 rvb vc_nb_read(dev, uiop, flag)
313 1.1 rvb dev_t dev;
314 1.1 rvb struct uio *uiop;
315 1.1 rvb int flag;
316 1.1 rvb {
317 1.1 rvb register struct vcomm * vcp;
318 1.1 rvb register struct vmsg *vmp;
319 1.1 rvb int error = 0;
320 1.1 rvb
321 1.1 rvb ENTRY;
322 1.1 rvb
323 1.1 rvb if (minor(dev) >= NVCFS || minor(dev) < 0)
324 1.1 rvb return(ENXIO);
325 1.1 rvb
326 1.1 rvb vcp = &cfs_mnttbl[minor(dev)].mi_vcomm;
327 1.1 rvb /* Get message at head of request queue. */
328 1.1 rvb if (EMPTY(vcp->vc_requests))
329 1.1 rvb return(0); /* Nothing to read */
330 1.1 rvb
331 1.1 rvb vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
332 1.1 rvb
333 1.1 rvb /* Move the input args into userspace */
334 1.1 rvb uiop->uio_rw = UIO_READ;
335 1.1 rvb error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
336 1.1 rvb if (error) {
337 1.1 rvb myprintf(("vcread: error (%d) on uiomove\n", error));
338 1.1 rvb error = EINVAL;
339 1.1 rvb }
340 1.1 rvb
341 1.1 rvb #ifdef DIAGNOSTIC
342 1.1 rvb if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
343 1.1 rvb panic("vc_nb_read: bad chain");
344 1.1 rvb #endif
345 1.1 rvb
346 1.1 rvb REMQUE(vmp->vm_chain);
347 1.1 rvb
348 1.1 rvb /* If request was a signal, free up the message and don't
349 1.1 rvb enqueue it in the reply queue. */
350 1.1 rvb if (vmp->vm_opcode == CFS_SIGNAL) {
351 1.1 rvb if (cfsdebug)
352 1.1 rvb myprintf(("vcread: signal msg (%d, %d)\n",
353 1.1 rvb vmp->vm_opcode, vmp->vm_unique));
354 1.1 rvb CFS_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
355 1.1 rvb CFS_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
356 1.1 rvb return(error);
357 1.1 rvb }
358 1.1 rvb
359 1.1 rvb vmp->vm_flags |= VM_READ;
360 1.1 rvb INSQUE(vmp->vm_chain, vcp->vc_replys);
361 1.1 rvb
362 1.1 rvb return(error);
363 1.1 rvb }
364 1.1 rvb
365 1.1 rvb int
366 1.1 rvb vc_nb_write(dev, uiop, flag)
367 1.1 rvb dev_t dev;
368 1.1 rvb struct uio *uiop;
369 1.1 rvb int flag;
370 1.1 rvb {
371 1.1 rvb register struct vcomm * vcp;
372 1.1 rvb register struct vmsg *vmp;
373 1.1 rvb struct cfs_out_hdr *out;
374 1.1 rvb u_long seq;
375 1.1 rvb u_long opcode;
376 1.1 rvb int buf[2];
377 1.1 rvb int error = 0;
378 1.1 rvb
379 1.1 rvb ENTRY;
380 1.1 rvb
381 1.1 rvb if (minor(dev) >= NVCFS || minor(dev) < 0)
382 1.1 rvb return(ENXIO);
383 1.1 rvb
384 1.1 rvb vcp = &cfs_mnttbl[minor(dev)].mi_vcomm;
385 1.1 rvb
386 1.1 rvb /* Peek at the opcode, unique without transfering the data. */
387 1.1 rvb uiop->uio_rw = UIO_WRITE;
388 1.1 rvb error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
389 1.1 rvb if (error) {
390 1.1 rvb myprintf(("vcwrite: error (%d) on uiomove\n", error));
391 1.1 rvb return(EINVAL);
392 1.1 rvb }
393 1.1 rvb
394 1.1 rvb opcode = buf[0];
395 1.1 rvb seq = buf[1];
396 1.1 rvb
397 1.1 rvb if (cfsdebug)
398 1.1 rvb myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
399 1.1 rvb
400 1.1 rvb if (DOWNCALL(opcode)) {
401 1.1 rvb union outputArgs pbuf;
402 1.1 rvb
403 1.1 rvb /* get the rest of the data. */
404 1.1 rvb uiop->uio_rw = UIO_WRITE;
405 1.1 rvb error = uiomove((caddr_t)&pbuf.cfs_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
406 1.1 rvb if (error) {
407 1.1 rvb myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
408 1.1 rvb error, opcode, seq));
409 1.1 rvb return(EINVAL);
410 1.1 rvb }
411 1.1 rvb
412 1.1 rvb return handleDownCall(opcode, &pbuf);
413 1.1 rvb }
414 1.1 rvb
415 1.1 rvb /* Look for the message on the (waiting for) reply queue. */
416 1.1 rvb for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
417 1.1 rvb !EOQ(vmp, vcp->vc_replys);
418 1.1 rvb vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
419 1.1 rvb {
420 1.1 rvb if (vmp->vm_unique == seq) break;
421 1.1 rvb }
422 1.1 rvb
423 1.1 rvb if (EOQ(vmp, vcp->vc_replys)) {
424 1.1 rvb if (cfsdebug)
425 1.1 rvb myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
426 1.1 rvb
427 1.1 rvb return(ESRCH);
428 1.1 rvb }
429 1.1 rvb
430 1.1 rvb /* Remove the message from the reply queue */
431 1.1 rvb REMQUE(vmp->vm_chain);
432 1.1 rvb
433 1.1 rvb /* move data into response buffer. */
434 1.1 rvb out = (struct cfs_out_hdr *)vmp->vm_data;
435 1.1 rvb /* Don't need to copy opcode and uniquifier. */
436 1.1 rvb
437 1.1 rvb /* get the rest of the data. */
438 1.1 rvb if (vmp->vm_outSize < uiop->uio_resid) {
439 1.1 rvb myprintf(("vcwrite: more data than asked for (%d < %d)\n",
440 1.1 rvb vmp->vm_outSize, uiop->uio_resid));
441 1.1 rvb wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
442 1.1 rvb return(EINVAL);
443 1.1 rvb }
444 1.1 rvb
445 1.1 rvb buf[0] = uiop->uio_resid; /* Save this value. */
446 1.1 rvb uiop->uio_rw = UIO_WRITE;
447 1.1 rvb error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
448 1.1 rvb if (error) {
449 1.1 rvb myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
450 1.1 rvb error, opcode, seq));
451 1.1 rvb return(EINVAL);
452 1.1 rvb }
453 1.1 rvb
454 1.1 rvb /* I don't think these are used, but just in case. */
455 1.1 rvb /* XXX - aren't these two already correct? -bnoble */
456 1.1 rvb out->opcode = opcode;
457 1.1 rvb out->unique = seq;
458 1.1 rvb vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
459 1.1 rvb vmp->vm_flags |= VM_WRITE;
460 1.1 rvb wakeup(&vmp->vm_sleep);
461 1.1 rvb
462 1.1 rvb return(0);
463 1.1 rvb }
464 1.1 rvb
465 1.1 rvb int
466 1.1 rvb vc_nb_ioctl(dev, cmd, addr, flag, p)
467 1.1 rvb dev_t dev;
468 1.1 rvb int cmd;
469 1.1 rvb caddr_t addr;
470 1.1 rvb int flag;
471 1.1 rvb struct proc *p;
472 1.1 rvb {
473 1.1 rvb ENTRY;
474 1.1 rvb
475 1.1 rvb switch(cmd) {
476 1.1 rvb case CFSRESIZE: {
477 1.1 rvb struct cfs_resize *data = (struct cfs_resize *)addr;
478 1.1 rvb return(cfsnc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
479 1.1 rvb break;
480 1.1 rvb }
481 1.1 rvb case CFSSTATS:
482 1.1 rvb if (cfsnc_use) {
483 1.1 rvb cfsnc_gather_stats();
484 1.1 rvb return(0);
485 1.1 rvb } else {
486 1.1 rvb return(ENODEV);
487 1.1 rvb }
488 1.1 rvb break;
489 1.1 rvb case CFSPRINT:
490 1.1 rvb if (cfsnc_use) {
491 1.1 rvb print_cfsnc();
492 1.1 rvb return(0);
493 1.1 rvb } else {
494 1.1 rvb return(ENODEV);
495 1.1 rvb }
496 1.1 rvb break;
497 1.1 rvb default :
498 1.1 rvb return(EINVAL);
499 1.1 rvb break;
500 1.1 rvb }
501 1.1 rvb }
502 1.1 rvb
503 1.1 rvb int
504 1.1 rvb vc_nb_poll(dev, events, p)
505 1.1 rvb dev_t dev;
506 1.1 rvb int events;
507 1.1 rvb struct proc *p;
508 1.1 rvb {
509 1.1 rvb register struct vcomm *vcp;
510 1.1 rvb int event_msk = 0;
511 1.1 rvb
512 1.1 rvb ENTRY;
513 1.1 rvb
514 1.1 rvb if (minor(dev) >= NVCFS || minor(dev) < 0)
515 1.1 rvb return(ENXIO);
516 1.1 rvb
517 1.1 rvb vcp = &cfs_mnttbl[minor(dev)].mi_vcomm;
518 1.1 rvb
519 1.1 rvb event_msk = events & (POLLIN|POLLRDNORM);
520 1.1 rvb if (!event_msk)
521 1.1 rvb return(0);
522 1.1 rvb
523 1.1 rvb if (!EMPTY(vcp->vc_requests))
524 1.1 rvb return(events & (POLLIN|POLLRDNORM));
525 1.1 rvb
526 1.1 rvb selrecord(p, &(vcp->vc_selproc));
527 1.1 rvb
528 1.1 rvb return(0);
529 1.1 rvb }
530 1.1 rvb
531 1.1 rvb /*
532 1.1 rvb * Statistics
533 1.1 rvb */
534 1.1 rvb struct cfs_clstat cfs_clstat;
535 1.1 rvb
536 1.1 rvb /*
537 1.1 rvb * Key question: whether to sleep interuptably or uninteruptably when
538 1.1 rvb * waiting for Venus. The former seems better (cause you can ^C a
539 1.1 rvb * job), but then GNU-EMACS completion breaks. Use tsleep with no
540 1.1 rvb * timeout, and no longjmp happens. But, when sleeping
541 1.1 rvb * "uninterruptibly", we don't get told if it returns abnormally
542 1.1 rvb * (e.g. kill -9).
543 1.1 rvb */
544 1.1 rvb
545 1.1 rvb /* If you want this to be interruptible, set this to > PZERO */
546 1.1 rvb int cfscall_sleep = PZERO - 1;
547 1.1 rvb #ifdef CTL_C
548 1.1 rvb int cfs_pcatch = PCATCH;
549 1.1 rvb #else
550 1.1 rvb #endif
551 1.1 rvb
552 1.1 rvb int
553 1.1 rvb cfscall(mntinfo, inSize, outSize, buffer)
554 1.1 rvb struct cfs_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
555 1.1 rvb {
556 1.1 rvb struct vcomm *vcp;
557 1.1 rvb struct vmsg *vmp;
558 1.1 rvb int error;
559 1.1 rvb #ifdef CTL_C
560 1.1 rvb struct proc *p = curproc;
561 1.1 rvb unsigned int psig_omask = p->p_sigmask;
562 1.1 rvb int i;
563 1.1 rvb #endif
564 1.1 rvb if (mntinfo == NULL) {
565 1.1 rvb /* Unlikely, but could be a race condition with a dying warden */
566 1.1 rvb return ENODEV;
567 1.1 rvb }
568 1.1 rvb
569 1.1 rvb vcp = &(mntinfo->mi_vcomm);
570 1.1 rvb
571 1.1 rvb cfs_clstat.ncalls++;
572 1.1 rvb cfs_clstat.reqs[((struct cfs_in_hdr *)buffer)->opcode]++;
573 1.1 rvb
574 1.1 rvb if (!VC_OPEN(vcp))
575 1.1 rvb return(ENODEV);
576 1.1 rvb
577 1.1 rvb CFS_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
578 1.1 rvb /* Format the request message. */
579 1.1 rvb vmp->vm_data = buffer;
580 1.1 rvb vmp->vm_flags = 0;
581 1.1 rvb vmp->vm_inSize = inSize;
582 1.1 rvb vmp->vm_outSize
583 1.1 rvb = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
584 1.1 rvb vmp->vm_opcode = ((struct cfs_in_hdr *)buffer)->opcode;
585 1.1 rvb vmp->vm_unique = ++vcp->vc_seq;
586 1.1 rvb if (cfsdebug)
587 1.1 rvb myprintf(("Doing a call for %d.%d\n",
588 1.1 rvb vmp->vm_opcode, vmp->vm_unique));
589 1.1 rvb
590 1.1 rvb /* Fill in the common input args. */
591 1.1 rvb ((struct cfs_in_hdr *)buffer)->unique = vmp->vm_unique;
592 1.1 rvb
593 1.1 rvb /* Append msg to request queue and poke Venus. */
594 1.1 rvb INSQUE(vmp->vm_chain, vcp->vc_requests);
595 1.1 rvb selwakeup(&(vcp->vc_selproc));
596 1.1 rvb
597 1.1 rvb /* We can be interrupted while we wait for Venus to process
598 1.1 rvb * our request. If the interrupt occurs before Venus has read
599 1.1 rvb * the request, we dequeue and return. If it occurs after the
600 1.1 rvb * read but before the reply, we dequeue, send a signal
601 1.1 rvb * message, and return. If it occurs after the reply we ignore
602 1.1 rvb * it. In no case do we want to restart the syscall. If it
603 1.1 rvb * was interrupted by a venus shutdown (vcclose), return
604 1.1 rvb * ENODEV. */
605 1.1 rvb
606 1.1 rvb /* Ignore return, We have to check anyway */
607 1.1 rvb #ifdef CTL_C
608 1.1 rvb /* This is work in progress. Setting cfs_pcatch lets tsleep reawaken
609 1.1 rvb on a ^c or ^z. The problem is that emacs sets certain interrupts
610 1.1 rvb as SA_RESTART. This means that we should exit sleep handle the
611 1.1 rvb "signal" and then go to sleep again. Mostly this is done by letting
612 1.1 rvb the syscall complete and be restarted. We are not idempotent and
613 1.1 rvb can not do this. A better solution is necessary.
614 1.1 rvb */
615 1.1 rvb i = 0;
616 1.1 rvb do {
617 1.1 rvb error = tsleep(&vmp->vm_sleep, (cfscall_sleep|cfs_pcatch), "cfscall", hz*2);
618 1.1 rvb if (error == 0)
619 1.1 rvb break;
620 1.1 rvb else if (error == EWOULDBLOCK) {
621 1.1 rvb printf("cfscall: tsleep TIMEOUT %d sec\n", 2+2*i);
622 1.1 rvb } else if (p->p_siglist == sigmask(SIGIO)) {
623 1.1 rvb p->p_sigmask |= p->p_siglist;
624 1.1 rvb printf("cfscall: tsleep returns %d SIGIO, cnt %d\n", error, i);
625 1.1 rvb } else {
626 1.1 rvb printf("cfscall: tsleep returns %d, cnt %d\n", error, i);
627 1.1 rvb printf("cfscall: siglist = %x, sigmask = %x, mask %x\n",
628 1.1 rvb p->p_siglist, p->p_sigmask,
629 1.1 rvb p->p_siglist & ~p->p_sigmask);
630 1.1 rvb break;
631 1.1 rvb p->p_sigmask |= p->p_siglist;
632 1.1 rvb printf("cfscall: new mask, siglist = %x, sigmask = %x, mask %x\n",
633 1.1 rvb p->p_siglist, p->p_sigmask,
634 1.1 rvb p->p_siglist & ~p->p_sigmask);
635 1.1 rvb }
636 1.1 rvb } while (error && i++ < 128);
637 1.1 rvb p->p_sigmask = psig_omask;
638 1.1 rvb #else
639 1.1 rvb (void) tsleep(&vmp->vm_sleep, cfscall_sleep, "cfscall", 0);
640 1.1 rvb #endif
641 1.1 rvb if (VC_OPEN(vcp)) { /* Venus is still alive */
642 1.1 rvb /* Op went through, interrupt or not... */
643 1.1 rvb if (vmp->vm_flags & VM_WRITE) {
644 1.1 rvb error = 0;
645 1.1 rvb *outSize = vmp->vm_outSize;
646 1.1 rvb }
647 1.1 rvb
648 1.1 rvb else if (!(vmp->vm_flags & VM_READ)) {
649 1.1 rvb /* Interrupted before venus read it. */
650 1.1 rvb if (cfsdebug||1)
651 1.1 rvb myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
652 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
653 1.1 rvb REMQUE(vmp->vm_chain);
654 1.1 rvb error = EINTR;
655 1.1 rvb }
656 1.1 rvb
657 1.1 rvb else {
658 1.1 rvb /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
659 1.1 rvb upcall started */
660 1.1 rvb /* Interrupted after start of upcall, send venus a signal */
661 1.1 rvb struct cfs_in_hdr *dog;
662 1.1 rvb struct vmsg *svmp;
663 1.1 rvb
664 1.1 rvb if (cfsdebug||1)
665 1.1 rvb myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
666 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
667 1.1 rvb
668 1.1 rvb REMQUE(vmp->vm_chain);
669 1.1 rvb error = EINTR;
670 1.1 rvb
671 1.1 rvb CFS_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
672 1.1 rvb
673 1.1 rvb CFS_ALLOC((svmp->vm_data), char *, sizeof (struct cfs_in_hdr));
674 1.1 rvb dog = (struct cfs_in_hdr *)svmp->vm_data;
675 1.1 rvb
676 1.1 rvb svmp->vm_flags = 0;
677 1.1 rvb dog->opcode = svmp->vm_opcode = CFS_SIGNAL;
678 1.1 rvb dog->unique = svmp->vm_unique = vmp->vm_unique;
679 1.1 rvb svmp->vm_inSize = sizeof (struct cfs_in_hdr);
680 1.1 rvb /*??? rvb */ svmp->vm_outSize = sizeof (struct cfs_in_hdr);
681 1.1 rvb
682 1.1 rvb if (cfsdebug)
683 1.1 rvb myprintf(("cfscall: enqueing signal msg (%d, %d)\n",
684 1.1 rvb svmp->vm_opcode, svmp->vm_unique));
685 1.1 rvb
686 1.1 rvb /* insert at head of queue! */
687 1.1 rvb INSQUE(svmp->vm_chain, vcp->vc_requests);
688 1.1 rvb selwakeup(&(vcp->vc_selproc));
689 1.1 rvb }
690 1.1 rvb }
691 1.1 rvb
692 1.1 rvb else { /* If venus died (!VC_OPEN(vcp)) */
693 1.1 rvb if (cfsdebug)
694 1.1 rvb myprintf(("vcclose woke op %d.%d flags %d\n",
695 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
696 1.1 rvb
697 1.1 rvb error = ENODEV;
698 1.1 rvb }
699 1.1 rvb
700 1.1 rvb CFS_FREE(vmp, sizeof(struct vmsg));
701 1.1 rvb
702 1.1 rvb if (!error)
703 error = ((struct cfs_out_hdr *)buffer)->result;
704 return(error);
705 }
706