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