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