coda_psdev.c revision 1.17.2.2 1 1.17.2.2 fvdl /* $NetBSD: coda_psdev.c,v 1.17.2.2 2001/09/26 15:28:07 fvdl 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.4 rvb * @(#) coda/coda_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 /* These routines are the device entry points for Venus. */
53 1.1 rvb
54 1.3 rvb extern int coda_nc_initialized; /* Set if cache has been initialized */
55 1.1 rvb
56 1.5 rvb #ifdef _LKM
57 1.5 rvb #define NVCODA 4
58 1.5 rvb #else
59 1.3 rvb #include <vcoda.h>
60 1.5 rvb #endif
61 1.5 rvb
62 1.1 rvb #include <sys/param.h>
63 1.1 rvb #include <sys/systm.h>
64 1.1 rvb #include <sys/kernel.h>
65 1.1 rvb #include <sys/malloc.h>
66 1.1 rvb #include <sys/proc.h>
67 1.1 rvb #include <sys/mount.h>
68 1.1 rvb #include <sys/file.h>
69 1.1 rvb #include <sys/ioctl.h>
70 1.1 rvb #include <sys/poll.h>
71 1.1 rvb #include <sys/select.h>
72 1.17.2.1 thorpej #include <sys/vnode.h>
73 1.17.2.1 thorpej
74 1.17.2.1 thorpej #include <miscfs/specfs/specdev.h>
75 1.1 rvb
76 1.16 thorpej #include <miscfs/syncfs/syncfs.h>
77 1.16 thorpej
78 1.4 rvb #include <coda/coda.h>
79 1.4 rvb #include <coda/cnode.h>
80 1.4 rvb #include <coda/coda_namecache.h>
81 1.4 rvb #include <coda/coda_io.h>
82 1.5 rvb #include <coda/coda_psdev.h>
83 1.1 rvb
84 1.2 rvb #define CTL_C
85 1.2 rvb
86 1.3 rvb int coda_psdev_print_entry = 0;
87 1.8 rvb static
88 1.8 rvb int outstanding_upcalls = 0;
89 1.8 rvb int coda_call_sleep = PZERO - 1;
90 1.8 rvb #ifdef CTL_C
91 1.8 rvb int coda_pcatch = PCATCH;
92 1.8 rvb #else
93 1.8 rvb #endif
94 1.3 rvb
95 1.3 rvb #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__FUNCTION__))
96 1.1 rvb
97 1.3 rvb void vcodaattach(int n);
98 1.1 rvb
99 1.1 rvb struct vmsg {
100 1.1 rvb struct queue vm_chain;
101 1.1 rvb caddr_t vm_data;
102 1.1 rvb u_short vm_flags;
103 1.1 rvb u_short vm_inSize; /* Size is at most 5000 bytes */
104 1.1 rvb u_short vm_outSize;
105 1.1 rvb u_short vm_opcode; /* copied from data to save ptr lookup */
106 1.1 rvb int vm_unique;
107 1.1 rvb caddr_t vm_sleep; /* Not used by Mach. */
108 1.1 rvb };
109 1.1 rvb
110 1.1 rvb #define VM_READ 1
111 1.1 rvb #define VM_WRITE 2
112 1.1 rvb #define VM_INTR 4
113 1.1 rvb
114 1.3 rvb /* vcodaattach: do nothing */
115 1.1 rvb void
116 1.3 rvb vcodaattach(n)
117 1.1 rvb int n;
118 1.1 rvb {
119 1.1 rvb }
120 1.1 rvb
121 1.1 rvb /*
122 1.1 rvb * These functions are written for NetBSD.
123 1.1 rvb */
124 1.1 rvb int
125 1.17.2.1 thorpej vc_nb_open(devvp, flag, mode, p)
126 1.17.2.1 thorpej struct vnode *devvp;
127 1.1 rvb int flag;
128 1.1 rvb int mode;
129 1.1 rvb struct proc *p; /* NetBSD only */
130 1.1 rvb {
131 1.13 augustss struct vcomm *vcp;
132 1.17.2.2 fvdl dev_t rdev;
133 1.17.2.2 fvdl int unit;
134 1.1 rvb
135 1.1 rvb ENTRY;
136 1.1 rvb
137 1.17.2.2 fvdl unit = minor(vdev_rdev(devvp));
138 1.17.2.2 fvdl
139 1.17.2.2 fvdl if (unit >= NVCODA || unit < 0)
140 1.1 rvb return(ENXIO);
141 1.1 rvb
142 1.3 rvb if (!coda_nc_initialized)
143 1.3 rvb coda_nc_init();
144 1.1 rvb
145 1.17.2.2 fvdl vcp = &coda_mnttbl[unit].mi_vcomm;
146 1.17.2.1 thorpej
147 1.17.2.2 fvdl vdev_setprivdata(devvp, &coda_mnttbl[unit]);
148 1.17.2.1 thorpej
149 1.1 rvb if (VC_OPEN(vcp))
150 1.1 rvb return(EBUSY);
151 1.1 rvb
152 1.17 thorpej memset(&(vcp->vc_selproc), 0, sizeof (struct selinfo));
153 1.1 rvb INIT_QUEUE(vcp->vc_requests);
154 1.1 rvb INIT_QUEUE(vcp->vc_replys);
155 1.1 rvb MARK_VC_OPEN(vcp);
156 1.1 rvb
157 1.17.2.2 fvdl coda_mnttbl[unit].mi_vfsp = NULL;
158 1.17.2.2 fvdl coda_mnttbl[unit].mi_rootvp = NULL;
159 1.1 rvb
160 1.1 rvb return(0);
161 1.1 rvb }
162 1.1 rvb
163 1.1 rvb int
164 1.17.2.2 fvdl vc_nb_close(devvp, flag, mode, p)
165 1.17.2.1 thorpej struct vnode *devvp;
166 1.1 rvb int flag;
167 1.1 rvb int mode;
168 1.1 rvb struct proc *p;
169 1.1 rvb {
170 1.13 augustss struct vcomm *vcp;
171 1.13 augustss struct vmsg *vmp, *nvmp = NULL;
172 1.3 rvb struct coda_mntinfo *mi;
173 1.17.2.2 fvdl int err;
174 1.17.2.2 fvdl dev_t rdev;
175 1.1 rvb
176 1.1 rvb ENTRY;
177 1.1 rvb
178 1.17.2.2 fvdl rdev = vdev_rdev(devvp);
179 1.17.2.2 fvdl mi = vdev_privdata(devvp);
180 1.17.2.2 fvdl if (err != 0)
181 1.17.2.2 fvdl return err;
182 1.1 rvb vcp = &(mi->mi_vcomm);
183 1.1 rvb
184 1.1 rvb if (!VC_OPEN(vcp))
185 1.1 rvb panic("vcclose: not open");
186 1.1 rvb
187 1.1 rvb /* prevent future operations on this vfs from succeeding by auto-
188 1.1 rvb * unmounting any vfs mounted via this device. This frees user or
189 1.1 rvb * sysadm from having to remember where all mount points are located.
190 1.1 rvb * Put this before WAKEUPs to avoid queuing new messages between
191 1.1 rvb * the WAKEUP and the unmount (which can happen if we're unlucky)
192 1.1 rvb */
193 1.8 rvb if (!mi->mi_rootvp) {
194 1.8 rvb /* just a simple open/close w no mount */
195 1.8 rvb MARK_VC_CLOSED(vcp);
196 1.8 rvb return 0;
197 1.1 rvb }
198 1.8 rvb
199 1.8 rvb /* Let unmount know this is for real */
200 1.16 thorpej /*
201 1.16 thorpej * XXX Freeze syncer. Must do this before locking the
202 1.16 thorpej * mount point. See dounmount for details().
203 1.16 thorpej */
204 1.16 thorpej lockmgr(&syncer_lock, LK_EXCLUSIVE, NULL);
205 1.8 rvb VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
206 1.16 thorpej if (vfs_busy(mi->mi_vfsp, 0, 0)) {
207 1.16 thorpej lockmgr(&syncer_lock, LK_RELEASE, NULL);
208 1.8 rvb return (EBUSY);
209 1.16 thorpej }
210 1.8 rvb coda_unmounting(mi->mi_vfsp);
211 1.1 rvb
212 1.1 rvb /* Wakeup clients so they can return. */
213 1.1 rvb for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
214 1.1 rvb !EOQ(vmp, vcp->vc_requests);
215 1.10 rvb vmp = nvmp)
216 1.1 rvb {
217 1.9 rvb nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain);
218 1.1 rvb /* Free signal request messages and don't wakeup cause
219 1.1 rvb no one is waiting. */
220 1.3 rvb if (vmp->vm_opcode == CODA_SIGNAL) {
221 1.3 rvb CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
222 1.3 rvb CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
223 1.1 rvb continue;
224 1.1 rvb }
225 1.8 rvb outstanding_upcalls++;
226 1.1 rvb wakeup(&vmp->vm_sleep);
227 1.1 rvb }
228 1.8 rvb
229 1.1 rvb for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
230 1.1 rvb !EOQ(vmp, vcp->vc_replys);
231 1.1 rvb vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
232 1.1 rvb {
233 1.8 rvb outstanding_upcalls++;
234 1.1 rvb wakeup(&vmp->vm_sleep);
235 1.1 rvb }
236 1.8 rvb
237 1.1 rvb MARK_VC_CLOSED(vcp);
238 1.8 rvb
239 1.8 rvb if (outstanding_upcalls) {
240 1.8 rvb #ifdef CODA_VERBOSE
241 1.8 rvb printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
242 1.8 rvb (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
243 1.8 rvb printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
244 1.8 rvb #else
245 1.8 rvb (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
246 1.8 rvb #endif
247 1.8 rvb }
248 1.8 rvb
249 1.8 rvb err = dounmount(mi->mi_vfsp, flag, p);
250 1.8 rvb if (err)
251 1.8 rvb myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
252 1.17.2.2 fvdl err, minor(rdev)));
253 1.1 rvb return 0;
254 1.1 rvb }
255 1.1 rvb
256 1.1 rvb int
257 1.17.2.1 thorpej vc_nb_read(devvp, uiop, flag)
258 1.17.2.1 thorpej struct vnode *devvp;
259 1.1 rvb struct uio *uiop;
260 1.1 rvb int flag;
261 1.1 rvb {
262 1.13 augustss struct vcomm * vcp;
263 1.13 augustss struct vmsg *vmp;
264 1.17.2.1 thorpej struct coda_mntinfo *mi;
265 1.17.2.2 fvdl int error;
266 1.1 rvb
267 1.1 rvb ENTRY;
268 1.1 rvb
269 1.17.2.2 fvdl mi = vdev_privdata(devvp);
270 1.17.2.1 thorpej vcp = &mi->mi_vcomm;
271 1.1 rvb /* Get message at head of request queue. */
272 1.1 rvb if (EMPTY(vcp->vc_requests))
273 1.1 rvb return(0); /* Nothing to read */
274 1.1 rvb
275 1.1 rvb vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
276 1.1 rvb
277 1.1 rvb /* Move the input args into userspace */
278 1.1 rvb uiop->uio_rw = UIO_READ;
279 1.1 rvb error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
280 1.1 rvb if (error) {
281 1.1 rvb myprintf(("vcread: error (%d) on uiomove\n", error));
282 1.1 rvb error = EINVAL;
283 1.1 rvb }
284 1.1 rvb
285 1.5 rvb #ifdef OLD_DIAGNOSTIC
286 1.1 rvb if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
287 1.1 rvb panic("vc_nb_read: bad chain");
288 1.1 rvb #endif
289 1.1 rvb
290 1.1 rvb REMQUE(vmp->vm_chain);
291 1.1 rvb
292 1.1 rvb /* If request was a signal, free up the message and don't
293 1.1 rvb enqueue it in the reply queue. */
294 1.3 rvb if (vmp->vm_opcode == CODA_SIGNAL) {
295 1.3 rvb if (codadebug)
296 1.1 rvb myprintf(("vcread: signal msg (%d, %d)\n",
297 1.1 rvb vmp->vm_opcode, vmp->vm_unique));
298 1.3 rvb CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
299 1.3 rvb CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
300 1.1 rvb return(error);
301 1.1 rvb }
302 1.1 rvb
303 1.1 rvb vmp->vm_flags |= VM_READ;
304 1.1 rvb INSQUE(vmp->vm_chain, vcp->vc_replys);
305 1.1 rvb
306 1.1 rvb return(error);
307 1.1 rvb }
308 1.1 rvb
309 1.1 rvb int
310 1.17.2.1 thorpej vc_nb_write(devvp, uiop, flag)
311 1.17.2.1 thorpej struct vnode *devvp;
312 1.1 rvb struct uio *uiop;
313 1.1 rvb int flag;
314 1.1 rvb {
315 1.13 augustss struct vcomm * vcp;
316 1.13 augustss struct vmsg *vmp;
317 1.17.2.1 thorpej struct coda_mntinfo *mi;
318 1.3 rvb struct coda_out_hdr *out;
319 1.1 rvb u_long seq;
320 1.1 rvb u_long opcode;
321 1.1 rvb int buf[2];
322 1.17.2.2 fvdl int error;
323 1.1 rvb
324 1.1 rvb ENTRY;
325 1.1 rvb
326 1.17.2.2 fvdl mi = vdev_privdata(devvp);
327 1.17.2.1 thorpej vcp = &mi->mi_vcomm;
328 1.1 rvb
329 1.1 rvb /* Peek at the opcode, unique without transfering the data. */
330 1.1 rvb uiop->uio_rw = UIO_WRITE;
331 1.1 rvb error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
332 1.1 rvb if (error) {
333 1.1 rvb myprintf(("vcwrite: error (%d) on uiomove\n", error));
334 1.1 rvb return(EINVAL);
335 1.1 rvb }
336 1.1 rvb
337 1.1 rvb opcode = buf[0];
338 1.1 rvb seq = buf[1];
339 1.1 rvb
340 1.3 rvb if (codadebug)
341 1.1 rvb myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
342 1.1 rvb
343 1.1 rvb if (DOWNCALL(opcode)) {
344 1.1 rvb union outputArgs pbuf;
345 1.1 rvb
346 1.1 rvb /* get the rest of the data. */
347 1.1 rvb uiop->uio_rw = UIO_WRITE;
348 1.3 rvb error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
349 1.1 rvb if (error) {
350 1.1 rvb myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
351 1.1 rvb error, opcode, seq));
352 1.1 rvb return(EINVAL);
353 1.1 rvb }
354 1.1 rvb
355 1.1 rvb return handleDownCall(opcode, &pbuf);
356 1.1 rvb }
357 1.1 rvb
358 1.1 rvb /* Look for the message on the (waiting for) reply queue. */
359 1.1 rvb for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
360 1.1 rvb !EOQ(vmp, vcp->vc_replys);
361 1.1 rvb vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
362 1.1 rvb {
363 1.1 rvb if (vmp->vm_unique == seq) break;
364 1.1 rvb }
365 1.1 rvb
366 1.1 rvb if (EOQ(vmp, vcp->vc_replys)) {
367 1.3 rvb if (codadebug)
368 1.1 rvb myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
369 1.1 rvb
370 1.1 rvb return(ESRCH);
371 1.1 rvb }
372 1.1 rvb
373 1.1 rvb /* Remove the message from the reply queue */
374 1.1 rvb REMQUE(vmp->vm_chain);
375 1.1 rvb
376 1.1 rvb /* move data into response buffer. */
377 1.3 rvb out = (struct coda_out_hdr *)vmp->vm_data;
378 1.1 rvb /* Don't need to copy opcode and uniquifier. */
379 1.1 rvb
380 1.1 rvb /* get the rest of the data. */
381 1.1 rvb if (vmp->vm_outSize < uiop->uio_resid) {
382 1.11 matt myprintf(("vcwrite: more data than asked for (%d < %lu)\n",
383 1.11 matt vmp->vm_outSize, (unsigned long) uiop->uio_resid));
384 1.1 rvb wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
385 1.1 rvb return(EINVAL);
386 1.1 rvb }
387 1.1 rvb
388 1.1 rvb buf[0] = uiop->uio_resid; /* Save this value. */
389 1.1 rvb uiop->uio_rw = UIO_WRITE;
390 1.1 rvb error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
391 1.1 rvb if (error) {
392 1.1 rvb myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
393 1.1 rvb error, opcode, seq));
394 1.1 rvb return(EINVAL);
395 1.1 rvb }
396 1.1 rvb
397 1.1 rvb /* I don't think these are used, but just in case. */
398 1.1 rvb /* XXX - aren't these two already correct? -bnoble */
399 1.1 rvb out->opcode = opcode;
400 1.1 rvb out->unique = seq;
401 1.1 rvb vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
402 1.1 rvb vmp->vm_flags |= VM_WRITE;
403 1.1 rvb wakeup(&vmp->vm_sleep);
404 1.1 rvb
405 1.1 rvb return(0);
406 1.1 rvb }
407 1.1 rvb
408 1.1 rvb int
409 1.17.2.1 thorpej vc_nb_ioctl(devvp, cmd, addr, flag, p)
410 1.17.2.1 thorpej struct vnode *devvp;
411 1.5 rvb u_long cmd;
412 1.1 rvb caddr_t addr;
413 1.1 rvb int flag;
414 1.1 rvb struct proc *p;
415 1.1 rvb {
416 1.1 rvb ENTRY;
417 1.1 rvb
418 1.1 rvb switch(cmd) {
419 1.3 rvb case CODARESIZE: {
420 1.3 rvb struct coda_resize *data = (struct coda_resize *)addr;
421 1.3 rvb return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
422 1.1 rvb break;
423 1.1 rvb }
424 1.3 rvb case CODASTATS:
425 1.3 rvb if (coda_nc_use) {
426 1.3 rvb coda_nc_gather_stats();
427 1.1 rvb return(0);
428 1.1 rvb } else {
429 1.1 rvb return(ENODEV);
430 1.1 rvb }
431 1.1 rvb break;
432 1.3 rvb case CODAPRINT:
433 1.3 rvb if (coda_nc_use) {
434 1.3 rvb print_coda_nc();
435 1.1 rvb return(0);
436 1.1 rvb } else {
437 1.1 rvb return(ENODEV);
438 1.1 rvb }
439 1.1 rvb break;
440 1.9 rvb case CIOC_KERNEL_VERSION:
441 1.9 rvb switch (*(u_int *)addr) {
442 1.9 rvb case 0:
443 1.9 rvb *(u_int *)addr = coda_kernel_version;
444 1.9 rvb return 0;
445 1.9 rvb break;
446 1.9 rvb case 1:
447 1.9 rvb case 2:
448 1.9 rvb if (coda_kernel_version != *(u_int *)addr)
449 1.9 rvb return ENOENT;
450 1.9 rvb else
451 1.9 rvb return 0;
452 1.9 rvb default:
453 1.9 rvb return ENOENT;
454 1.9 rvb }
455 1.9 rvb break;
456 1.1 rvb default :
457 1.1 rvb return(EINVAL);
458 1.1 rvb break;
459 1.1 rvb }
460 1.1 rvb }
461 1.1 rvb
462 1.1 rvb int
463 1.17.2.1 thorpej vc_nb_poll(devvp, events, p)
464 1.17.2.1 thorpej struct vnode *devvp;
465 1.1 rvb int events;
466 1.1 rvb struct proc *p;
467 1.1 rvb {
468 1.17.2.1 thorpej struct coda_mntinfo *mi;
469 1.13 augustss struct vcomm *vcp;
470 1.17.2.2 fvdl int event_msk;
471 1.1 rvb
472 1.1 rvb ENTRY;
473 1.17.2.1 thorpej
474 1.17.2.2 fvdl mi = vdev_privdata(devvp);
475 1.17.2.1 thorpej vcp = &mi->mi_vcomm;
476 1.1 rvb
477 1.1 rvb event_msk = events & (POLLIN|POLLRDNORM);
478 1.1 rvb if (!event_msk)
479 1.1 rvb return(0);
480 1.1 rvb
481 1.1 rvb if (!EMPTY(vcp->vc_requests))
482 1.1 rvb return(events & (POLLIN|POLLRDNORM));
483 1.1 rvb
484 1.1 rvb selrecord(p, &(vcp->vc_selproc));
485 1.1 rvb
486 1.1 rvb return(0);
487 1.1 rvb }
488 1.1 rvb
489 1.1 rvb /*
490 1.1 rvb * Statistics
491 1.1 rvb */
492 1.3 rvb struct coda_clstat coda_clstat;
493 1.1 rvb
494 1.1 rvb /*
495 1.1 rvb * Key question: whether to sleep interuptably or uninteruptably when
496 1.1 rvb * waiting for Venus. The former seems better (cause you can ^C a
497 1.1 rvb * job), but then GNU-EMACS completion breaks. Use tsleep with no
498 1.1 rvb * timeout, and no longjmp happens. But, when sleeping
499 1.1 rvb * "uninterruptibly", we don't get told if it returns abnormally
500 1.1 rvb * (e.g. kill -9).
501 1.1 rvb */
502 1.1 rvb
503 1.1 rvb int
504 1.3 rvb coda_call(mntinfo, inSize, outSize, buffer)
505 1.3 rvb struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
506 1.1 rvb {
507 1.1 rvb struct vcomm *vcp;
508 1.1 rvb struct vmsg *vmp;
509 1.1 rvb int error;
510 1.1 rvb #ifdef CTL_C
511 1.1 rvb struct proc *p = curproc;
512 1.4 rvb sigset_t psig_omask;
513 1.1 rvb int i;
514 1.14 jdolecek psig_omask = p->p_sigctx.ps_siglist; /* array assignment */
515 1.1 rvb #endif
516 1.1 rvb if (mntinfo == NULL) {
517 1.1 rvb /* Unlikely, but could be a race condition with a dying warden */
518 1.1 rvb return ENODEV;
519 1.1 rvb }
520 1.1 rvb
521 1.1 rvb vcp = &(mntinfo->mi_vcomm);
522 1.1 rvb
523 1.3 rvb coda_clstat.ncalls++;
524 1.3 rvb coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
525 1.1 rvb
526 1.1 rvb if (!VC_OPEN(vcp))
527 1.1 rvb return(ENODEV);
528 1.1 rvb
529 1.3 rvb CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
530 1.1 rvb /* Format the request message. */
531 1.1 rvb vmp->vm_data = buffer;
532 1.1 rvb vmp->vm_flags = 0;
533 1.1 rvb vmp->vm_inSize = inSize;
534 1.1 rvb vmp->vm_outSize
535 1.1 rvb = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
536 1.3 rvb vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
537 1.1 rvb vmp->vm_unique = ++vcp->vc_seq;
538 1.3 rvb if (codadebug)
539 1.1 rvb myprintf(("Doing a call for %d.%d\n",
540 1.1 rvb vmp->vm_opcode, vmp->vm_unique));
541 1.1 rvb
542 1.1 rvb /* Fill in the common input args. */
543 1.3 rvb ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
544 1.1 rvb
545 1.1 rvb /* Append msg to request queue and poke Venus. */
546 1.1 rvb INSQUE(vmp->vm_chain, vcp->vc_requests);
547 1.1 rvb selwakeup(&(vcp->vc_selproc));
548 1.1 rvb
549 1.1 rvb /* We can be interrupted while we wait for Venus to process
550 1.1 rvb * our request. If the interrupt occurs before Venus has read
551 1.1 rvb * the request, we dequeue and return. If it occurs after the
552 1.1 rvb * read but before the reply, we dequeue, send a signal
553 1.1 rvb * message, and return. If it occurs after the reply we ignore
554 1.1 rvb * it. In no case do we want to restart the syscall. If it
555 1.1 rvb * was interrupted by a venus shutdown (vcclose), return
556 1.1 rvb * ENODEV. */
557 1.1 rvb
558 1.1 rvb /* Ignore return, We have to check anyway */
559 1.1 rvb #ifdef CTL_C
560 1.3 rvb /* This is work in progress. Setting coda_pcatch lets tsleep reawaken
561 1.1 rvb on a ^c or ^z. The problem is that emacs sets certain interrupts
562 1.1 rvb as SA_RESTART. This means that we should exit sleep handle the
563 1.1 rvb "signal" and then go to sleep again. Mostly this is done by letting
564 1.1 rvb the syscall complete and be restarted. We are not idempotent and
565 1.1 rvb can not do this. A better solution is necessary.
566 1.1 rvb */
567 1.1 rvb i = 0;
568 1.1 rvb do {
569 1.3 rvb error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2);
570 1.1 rvb if (error == 0)
571 1.1 rvb break;
572 1.1 rvb else if (error == EWOULDBLOCK) {
573 1.7 rvb #ifdef CODA_VERBOSE
574 1.3 rvb printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
575 1.5 rvb #endif
576 1.14 jdolecek } else if (sigismember(&p->p_sigctx.ps_siglist, SIGIO)) {
577 1.14 jdolecek sigaddset(&p->p_sigctx.ps_sigmask, SIGIO);
578 1.7 rvb #ifdef CODA_VERBOSE
579 1.3 rvb printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i);
580 1.5 rvb #endif
581 1.14 jdolecek } else if (sigismember(&p->p_sigctx.ps_siglist, SIGALRM)) {
582 1.14 jdolecek sigaddset(&p->p_sigctx.ps_sigmask, SIGALRM);
583 1.8 rvb #ifdef CODA_VERBOSE
584 1.8 rvb printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i);
585 1.8 rvb #endif
586 1.1 rvb } else {
587 1.4 rvb sigset_t tmp;
588 1.14 jdolecek tmp = p->p_sigctx.ps_siglist; /* array assignment */
589 1.14 jdolecek sigminusset(&p->p_sigctx.ps_sigmask, &tmp);
590 1.4 rvb
591 1.7 rvb #ifdef CODA_VERBOSE
592 1.3 rvb printf("coda_call: tsleep returns %d, cnt %d\n", error, i);
593 1.4 rvb printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n",
594 1.14 jdolecek p->p_sigctx.ps_siglist.__bits[0], p->p_sigctx.ps_siglist.__bits[1],
595 1.14 jdolecek p->p_sigctx.ps_siglist.__bits[2], p->p_sigctx.ps_siglist.__bits[3],
596 1.14 jdolecek p->p_sigctx.ps_sigmask.__bits[0], p->p_sigctx.ps_sigmask.__bits[1],
597 1.14 jdolecek p->p_sigctx.ps_sigmask.__bits[2], p->p_sigctx.ps_sigmask.__bits[3],
598 1.4 rvb tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]);
599 1.5 rvb #endif
600 1.1 rvb break;
601 1.5 rvb #ifdef notyet
602 1.14 jdolecek sigminusset(&p->p_sigctx.ps_sigmask, &p->p_sigctx.ps_siglist);
603 1.4 rvb printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n",
604 1.15 jdolecek p->p_sigctx.ps_siglist.__bits[0], p->p_sigctx.ps_siglist.__bits[1],
605 1.15 jdolecek p->p_sigctx.ps_siglist.__bits[2], p->p_sigctx.ps_siglist.__bits[3],
606 1.15 jdolecek p->p_sigctx.ps_sigmask.__bits[0], p->p_sigctx.ps_sigmask.__bits[1],
607 1.15 jdolecek p->p_sigctx.ps_sigmask.__bits[2], p->p_sigctx.ps_sigmask.__bits[3]);
608 1.5 rvb #endif
609 1.1 rvb }
610 1.8 rvb } while (error && i++ < 128 && VC_OPEN(vcp));
611 1.14 jdolecek p->p_sigctx.ps_siglist = psig_omask; /* array assignment */
612 1.1 rvb #else
613 1.3 rvb (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
614 1.1 rvb #endif
615 1.1 rvb if (VC_OPEN(vcp)) { /* Venus is still alive */
616 1.1 rvb /* Op went through, interrupt or not... */
617 1.1 rvb if (vmp->vm_flags & VM_WRITE) {
618 1.1 rvb error = 0;
619 1.1 rvb *outSize = vmp->vm_outSize;
620 1.1 rvb }
621 1.1 rvb
622 1.1 rvb else if (!(vmp->vm_flags & VM_READ)) {
623 1.1 rvb /* Interrupted before venus read it. */
624 1.7 rvb #ifdef CODA_VERBOSE
625 1.7 rvb if (1)
626 1.7 rvb #else
627 1.5 rvb if (codadebug)
628 1.5 rvb #endif
629 1.1 rvb myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
630 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
631 1.1 rvb REMQUE(vmp->vm_chain);
632 1.1 rvb error = EINTR;
633 1.1 rvb }
634 1.1 rvb
635 1.1 rvb else {
636 1.1 rvb /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
637 1.1 rvb upcall started */
638 1.1 rvb /* Interrupted after start of upcall, send venus a signal */
639 1.3 rvb struct coda_in_hdr *dog;
640 1.1 rvb struct vmsg *svmp;
641 1.1 rvb
642 1.7 rvb #ifdef CODA_VERBOSE
643 1.7 rvb if (1)
644 1.7 rvb #else
645 1.5 rvb if (codadebug)
646 1.5 rvb #endif
647 1.1 rvb myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
648 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
649 1.1 rvb
650 1.1 rvb REMQUE(vmp->vm_chain);
651 1.1 rvb error = EINTR;
652 1.1 rvb
653 1.3 rvb CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
654 1.1 rvb
655 1.3 rvb CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
656 1.3 rvb dog = (struct coda_in_hdr *)svmp->vm_data;
657 1.1 rvb
658 1.1 rvb svmp->vm_flags = 0;
659 1.3 rvb dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
660 1.1 rvb dog->unique = svmp->vm_unique = vmp->vm_unique;
661 1.3 rvb svmp->vm_inSize = sizeof (struct coda_in_hdr);
662 1.3 rvb /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
663 1.1 rvb
664 1.3 rvb if (codadebug)
665 1.3 rvb myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
666 1.1 rvb svmp->vm_opcode, svmp->vm_unique));
667 1.1 rvb
668 1.1 rvb /* insert at head of queue! */
669 1.1 rvb INSQUE(svmp->vm_chain, vcp->vc_requests);
670 1.1 rvb selwakeup(&(vcp->vc_selproc));
671 1.1 rvb }
672 1.1 rvb }
673 1.1 rvb
674 1.1 rvb else { /* If venus died (!VC_OPEN(vcp)) */
675 1.3 rvb if (codadebug)
676 1.1 rvb myprintf(("vcclose woke op %d.%d flags %d\n",
677 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
678 1.1 rvb
679 1.1 rvb error = ENODEV;
680 1.1 rvb }
681 1.1 rvb
682 1.3 rvb CODA_FREE(vmp, sizeof(struct vmsg));
683 1.8 rvb
684 1.8 rvb if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
685 1.8 rvb wakeup(&outstanding_upcalls);
686 1.1 rvb
687 1.1 rvb if (!error)
688 1.3 rvb error = ((struct coda_out_hdr *)buffer)->result;
689 1.1 rvb return(error);
690 1.1 rvb }
691 1.4 rvb
692