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