coda_psdev.c revision 1.26.12.1 1 1.26.12.1 yamt /* $NetBSD: coda_psdev.c,v 1.26.12.1 2005/03/19 08:33:28 yamt Exp $ */
2 1.2 rvb
3 1.1 rvb /*
4 1.26.12.1 yamt *
5 1.2 rvb * Coda: an Experimental Distributed File System
6 1.2 rvb * Release 3.1
7 1.26.12.1 yamt *
8 1.2 rvb * Copyright (c) 1987-1998 Carnegie Mellon University
9 1.2 rvb * All Rights Reserved
10 1.26.12.1 yamt *
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.26.12.1 yamt *
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.26.12.1 yamt *
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.26.12.1 yamt *
31 1.26.12.1 yamt * @(#) 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.26.12.1 yamt /*
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.26.12.1 yamt * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
48 1.26.12.1 yamt * 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.26.12.1 yamt __KERNEL_RCSID(0, "$NetBSD: coda_psdev.c,v 1.26.12.1 2005/03/19 08:33:28 yamt 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.21 jdolecek nostop, notty, vc_nb_poll, nommap, vc_nb_kqfilter,
112 1.20 gehenna };
113 1.1 rvb
114 1.1 rvb struct vmsg {
115 1.1 rvb struct queue vm_chain;
116 1.1 rvb caddr_t 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.1 rvb caddr_t 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.3 rvb vcodaattach(n)
132 1.1 rvb int n;
133 1.1 rvb {
134 1.1 rvb }
135 1.1 rvb
136 1.26.12.1 yamt /*
137 1.1 rvb * These functions are written for NetBSD.
138 1.1 rvb */
139 1.26.12.1 yamt int
140 1.26.12.1 yamt vc_nb_open(dev, flag, mode, p)
141 1.26.12.1 yamt dev_t dev;
142 1.26.12.1 yamt int flag;
143 1.26.12.1 yamt int mode;
144 1.26 fvdl struct proc *p; /* NetBSD only */
145 1.1 rvb {
146 1.13 augustss struct vcomm *vcp;
147 1.26.12.1 yamt
148 1.1 rvb ENTRY;
149 1.1 rvb
150 1.3 rvb if (minor(dev) >= NVCODA || minor(dev) < 0)
151 1.1 rvb return(ENXIO);
152 1.26.12.1 yamt
153 1.3 rvb if (!coda_nc_initialized)
154 1.3 rvb coda_nc_init();
155 1.26.12.1 yamt
156 1.3 rvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
157 1.1 rvb if (VC_OPEN(vcp))
158 1.1 rvb return(EBUSY);
159 1.26.12.1 yamt
160 1.17 thorpej memset(&(vcp->vc_selproc), 0, sizeof (struct selinfo));
161 1.1 rvb INIT_QUEUE(vcp->vc_requests);
162 1.1 rvb INIT_QUEUE(vcp->vc_replys);
163 1.1 rvb MARK_VC_OPEN(vcp);
164 1.26.12.1 yamt
165 1.3 rvb coda_mnttbl[minor(dev)].mi_vfsp = NULL;
166 1.3 rvb coda_mnttbl[minor(dev)].mi_rootvp = NULL;
167 1.1 rvb
168 1.1 rvb return(0);
169 1.1 rvb }
170 1.1 rvb
171 1.26.12.1 yamt int
172 1.26.12.1 yamt vc_nb_close (dev, flag, mode, p)
173 1.26.12.1 yamt dev_t dev;
174 1.26.12.1 yamt int flag;
175 1.26.12.1 yamt int mode;
176 1.26 fvdl struct proc *p;
177 1.1 rvb {
178 1.13 augustss struct vcomm *vcp;
179 1.13 augustss struct vmsg *vmp, *nvmp = NULL;
180 1.3 rvb struct coda_mntinfo *mi;
181 1.1 rvb int err;
182 1.26.12.1 yamt
183 1.1 rvb ENTRY;
184 1.1 rvb
185 1.3 rvb if (minor(dev) >= NVCODA || minor(dev) < 0)
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.26.12.1 yamt
191 1.1 rvb if (!VC_OPEN(vcp))
192 1.1 rvb panic("vcclose: not open");
193 1.26.12.1 yamt
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.16 thorpej /*
208 1.16 thorpej * XXX Freeze syncer. Must do this before locking the
209 1.16 thorpej * mount point. See dounmount for details().
210 1.16 thorpej */
211 1.16 thorpej lockmgr(&syncer_lock, LK_EXCLUSIVE, NULL);
212 1.8 rvb VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
213 1.16 thorpej if (vfs_busy(mi->mi_vfsp, 0, 0)) {
214 1.16 thorpej lockmgr(&syncer_lock, LK_RELEASE, NULL);
215 1.8 rvb return (EBUSY);
216 1.16 thorpej }
217 1.8 rvb coda_unmounting(mi->mi_vfsp);
218 1.26.12.1 yamt
219 1.1 rvb /* Wakeup clients so they can return. */
220 1.1 rvb for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
221 1.1 rvb !EOQ(vmp, vcp->vc_requests);
222 1.10 rvb vmp = nvmp)
223 1.26.12.1 yamt {
224 1.9 rvb nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain);
225 1.1 rvb /* Free signal request messages and don't wakeup cause
226 1.1 rvb no one is waiting. */
227 1.3 rvb if (vmp->vm_opcode == CODA_SIGNAL) {
228 1.3 rvb CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
229 1.3 rvb CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
230 1.1 rvb continue;
231 1.1 rvb }
232 1.26.12.1 yamt outstanding_upcalls++;
233 1.1 rvb wakeup(&vmp->vm_sleep);
234 1.1 rvb }
235 1.8 rvb
236 1.1 rvb for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
237 1.1 rvb !EOQ(vmp, vcp->vc_replys);
238 1.1 rvb vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
239 1.1 rvb {
240 1.26.12.1 yamt outstanding_upcalls++;
241 1.1 rvb wakeup(&vmp->vm_sleep);
242 1.1 rvb }
243 1.8 rvb
244 1.1 rvb MARK_VC_CLOSED(vcp);
245 1.8 rvb
246 1.8 rvb if (outstanding_upcalls) {
247 1.8 rvb #ifdef CODA_VERBOSE
248 1.8 rvb printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
249 1.8 rvb (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
250 1.8 rvb printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
251 1.8 rvb #else
252 1.8 rvb (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
253 1.8 rvb #endif
254 1.8 rvb }
255 1.8 rvb
256 1.26 fvdl err = dounmount(mi->mi_vfsp, flag, p);
257 1.8 rvb if (err)
258 1.26.12.1 yamt myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
259 1.8 rvb err, minor(dev)));
260 1.1 rvb return 0;
261 1.1 rvb }
262 1.1 rvb
263 1.26.12.1 yamt int
264 1.26.12.1 yamt vc_nb_read(dev, uiop, flag)
265 1.26.12.1 yamt dev_t dev;
266 1.26.12.1 yamt struct uio *uiop;
267 1.1 rvb int flag;
268 1.1 rvb {
269 1.13 augustss struct vcomm * vcp;
270 1.13 augustss struct vmsg *vmp;
271 1.1 rvb int error = 0;
272 1.26.12.1 yamt
273 1.1 rvb ENTRY;
274 1.1 rvb
275 1.3 rvb if (minor(dev) >= NVCODA || minor(dev) < 0)
276 1.1 rvb return(ENXIO);
277 1.26.12.1 yamt
278 1.3 rvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
279 1.1 rvb /* Get message at head of request queue. */
280 1.1 rvb if (EMPTY(vcp->vc_requests))
281 1.1 rvb return(0); /* Nothing to read */
282 1.26.12.1 yamt
283 1.1 rvb vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
284 1.26.12.1 yamt
285 1.1 rvb /* Move the input args into userspace */
286 1.1 rvb uiop->uio_rw = UIO_READ;
287 1.1 rvb error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
288 1.1 rvb if (error) {
289 1.1 rvb myprintf(("vcread: error (%d) on uiomove\n", error));
290 1.1 rvb error = EINVAL;
291 1.1 rvb }
292 1.1 rvb
293 1.26.12.1 yamt #ifdef OLD_DIAGNOSTIC
294 1.1 rvb if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
295 1.1 rvb panic("vc_nb_read: bad chain");
296 1.1 rvb #endif
297 1.1 rvb
298 1.1 rvb REMQUE(vmp->vm_chain);
299 1.26.12.1 yamt
300 1.1 rvb /* If request was a signal, free up the message and don't
301 1.1 rvb enqueue it in the reply queue. */
302 1.3 rvb if (vmp->vm_opcode == CODA_SIGNAL) {
303 1.3 rvb if (codadebug)
304 1.26.12.1 yamt myprintf(("vcread: signal msg (%d, %d)\n",
305 1.1 rvb vmp->vm_opcode, vmp->vm_unique));
306 1.3 rvb CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
307 1.3 rvb CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
308 1.1 rvb return(error);
309 1.1 rvb }
310 1.26.12.1 yamt
311 1.1 rvb vmp->vm_flags |= VM_READ;
312 1.1 rvb INSQUE(vmp->vm_chain, vcp->vc_replys);
313 1.26.12.1 yamt
314 1.1 rvb return(error);
315 1.1 rvb }
316 1.1 rvb
317 1.1 rvb int
318 1.26.12.1 yamt vc_nb_write(dev, uiop, flag)
319 1.26.12.1 yamt dev_t dev;
320 1.26.12.1 yamt struct uio *uiop;
321 1.1 rvb int flag;
322 1.1 rvb {
323 1.13 augustss struct vcomm * vcp;
324 1.13 augustss struct vmsg *vmp;
325 1.3 rvb struct coda_out_hdr *out;
326 1.1 rvb u_long seq;
327 1.1 rvb u_long opcode;
328 1.1 rvb int buf[2];
329 1.1 rvb int error = 0;
330 1.1 rvb
331 1.1 rvb ENTRY;
332 1.1 rvb
333 1.3 rvb if (minor(dev) >= NVCODA || minor(dev) < 0)
334 1.1 rvb return(ENXIO);
335 1.26.12.1 yamt
336 1.3 rvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
337 1.26.12.1 yamt
338 1.1 rvb /* Peek at the opcode, unique without transfering the data. */
339 1.1 rvb uiop->uio_rw = UIO_WRITE;
340 1.1 rvb error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
341 1.1 rvb if (error) {
342 1.1 rvb myprintf(("vcwrite: error (%d) on uiomove\n", error));
343 1.1 rvb return(EINVAL);
344 1.1 rvb }
345 1.26.12.1 yamt
346 1.1 rvb opcode = buf[0];
347 1.1 rvb seq = buf[1];
348 1.26.12.1 yamt
349 1.3 rvb if (codadebug)
350 1.1 rvb myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
351 1.26.12.1 yamt
352 1.1 rvb if (DOWNCALL(opcode)) {
353 1.1 rvb union outputArgs pbuf;
354 1.26.12.1 yamt
355 1.1 rvb /* get the rest of the data. */
356 1.1 rvb uiop->uio_rw = UIO_WRITE;
357 1.3 rvb error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
358 1.1 rvb if (error) {
359 1.26.12.1 yamt myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
360 1.1 rvb error, opcode, seq));
361 1.1 rvb return(EINVAL);
362 1.1 rvb }
363 1.26.12.1 yamt
364 1.1 rvb return handleDownCall(opcode, &pbuf);
365 1.1 rvb }
366 1.26.12.1 yamt
367 1.1 rvb /* Look for the message on the (waiting for) reply queue. */
368 1.1 rvb for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
369 1.1 rvb !EOQ(vmp, vcp->vc_replys);
370 1.1 rvb vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
371 1.1 rvb {
372 1.1 rvb if (vmp->vm_unique == seq) break;
373 1.1 rvb }
374 1.26.12.1 yamt
375 1.1 rvb if (EOQ(vmp, vcp->vc_replys)) {
376 1.3 rvb if (codadebug)
377 1.1 rvb myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
378 1.26.12.1 yamt
379 1.1 rvb return(ESRCH);
380 1.1 rvb }
381 1.26.12.1 yamt
382 1.1 rvb /* Remove the message from the reply queue */
383 1.1 rvb REMQUE(vmp->vm_chain);
384 1.26.12.1 yamt
385 1.1 rvb /* move data into response buffer. */
386 1.3 rvb out = (struct coda_out_hdr *)vmp->vm_data;
387 1.1 rvb /* Don't need to copy opcode and uniquifier. */
388 1.26.12.1 yamt
389 1.1 rvb /* get the rest of the data. */
390 1.1 rvb if (vmp->vm_outSize < uiop->uio_resid) {
391 1.11 matt myprintf(("vcwrite: more data than asked for (%d < %lu)\n",
392 1.11 matt vmp->vm_outSize, (unsigned long) uiop->uio_resid));
393 1.1 rvb wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
394 1.1 rvb return(EINVAL);
395 1.26.12.1 yamt }
396 1.26.12.1 yamt
397 1.1 rvb buf[0] = uiop->uio_resid; /* Save this value. */
398 1.1 rvb uiop->uio_rw = UIO_WRITE;
399 1.1 rvb error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
400 1.1 rvb if (error) {
401 1.26.12.1 yamt myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
402 1.1 rvb error, opcode, seq));
403 1.1 rvb return(EINVAL);
404 1.1 rvb }
405 1.26.12.1 yamt
406 1.1 rvb /* I don't think these are used, but just in case. */
407 1.1 rvb /* XXX - aren't these two already correct? -bnoble */
408 1.1 rvb out->opcode = opcode;
409 1.1 rvb out->unique = seq;
410 1.1 rvb vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
411 1.1 rvb vmp->vm_flags |= VM_WRITE;
412 1.1 rvb wakeup(&vmp->vm_sleep);
413 1.26.12.1 yamt
414 1.1 rvb return(0);
415 1.1 rvb }
416 1.1 rvb
417 1.1 rvb int
418 1.26.12.1 yamt vc_nb_ioctl(dev, cmd, addr, flag, p)
419 1.26.12.1 yamt dev_t dev;
420 1.26.12.1 yamt u_long cmd;
421 1.26.12.1 yamt caddr_t addr;
422 1.26.12.1 yamt int flag;
423 1.26 fvdl struct proc *p;
424 1.1 rvb {
425 1.1 rvb ENTRY;
426 1.1 rvb
427 1.1 rvb switch(cmd) {
428 1.3 rvb case CODARESIZE: {
429 1.3 rvb struct coda_resize *data = (struct coda_resize *)addr;
430 1.3 rvb return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
431 1.1 rvb break;
432 1.1 rvb }
433 1.3 rvb case CODASTATS:
434 1.3 rvb if (coda_nc_use) {
435 1.3 rvb coda_nc_gather_stats();
436 1.1 rvb return(0);
437 1.1 rvb } else {
438 1.1 rvb return(ENODEV);
439 1.1 rvb }
440 1.1 rvb break;
441 1.3 rvb case CODAPRINT:
442 1.3 rvb if (coda_nc_use) {
443 1.3 rvb print_coda_nc();
444 1.1 rvb return(0);
445 1.1 rvb } else {
446 1.1 rvb return(ENODEV);
447 1.1 rvb }
448 1.1 rvb break;
449 1.9 rvb case CIOC_KERNEL_VERSION:
450 1.9 rvb switch (*(u_int *)addr) {
451 1.9 rvb case 0:
452 1.9 rvb *(u_int *)addr = coda_kernel_version;
453 1.9 rvb return 0;
454 1.9 rvb break;
455 1.9 rvb case 1:
456 1.9 rvb case 2:
457 1.9 rvb if (coda_kernel_version != *(u_int *)addr)
458 1.9 rvb return ENOENT;
459 1.9 rvb else
460 1.9 rvb return 0;
461 1.9 rvb default:
462 1.9 rvb return ENOENT;
463 1.9 rvb }
464 1.9 rvb break;
465 1.1 rvb default :
466 1.1 rvb return(EINVAL);
467 1.1 rvb break;
468 1.1 rvb }
469 1.1 rvb }
470 1.1 rvb
471 1.1 rvb int
472 1.26.12.1 yamt vc_nb_poll(dev, events, p)
473 1.26.12.1 yamt dev_t dev;
474 1.26.12.1 yamt int events;
475 1.26 fvdl struct proc *p;
476 1.1 rvb {
477 1.13 augustss struct vcomm *vcp;
478 1.1 rvb int event_msk = 0;
479 1.1 rvb
480 1.1 rvb ENTRY;
481 1.26.12.1 yamt
482 1.3 rvb if (minor(dev) >= NVCODA || minor(dev) < 0)
483 1.1 rvb return(ENXIO);
484 1.26.12.1 yamt
485 1.3 rvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
486 1.26.12.1 yamt
487 1.1 rvb event_msk = events & (POLLIN|POLLRDNORM);
488 1.1 rvb if (!event_msk)
489 1.1 rvb return(0);
490 1.26.12.1 yamt
491 1.1 rvb if (!EMPTY(vcp->vc_requests))
492 1.1 rvb return(events & (POLLIN|POLLRDNORM));
493 1.1 rvb
494 1.26 fvdl selrecord(p, &(vcp->vc_selproc));
495 1.26.12.1 yamt
496 1.1 rvb return(0);
497 1.1 rvb }
498 1.1 rvb
499 1.21 jdolecek static void
500 1.21 jdolecek filt_vc_nb_detach(struct knote *kn)
501 1.21 jdolecek {
502 1.21 jdolecek struct vcomm *vcp = kn->kn_hook;
503 1.21 jdolecek
504 1.22 christos SLIST_REMOVE(&vcp->vc_selproc.sel_klist, kn, knote, kn_selnext);
505 1.21 jdolecek }
506 1.21 jdolecek
507 1.21 jdolecek static int
508 1.21 jdolecek filt_vc_nb_read(struct knote *kn, long hint)
509 1.21 jdolecek {
510 1.26.12.1 yamt struct vcomm *vcp = kn->kn_hook;
511 1.21 jdolecek struct vmsg *vmp;
512 1.21 jdolecek
513 1.21 jdolecek if (EMPTY(vcp->vc_requests))
514 1.21 jdolecek return (0);
515 1.21 jdolecek
516 1.21 jdolecek vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
517 1.21 jdolecek
518 1.21 jdolecek kn->kn_data = vmp->vm_inSize;
519 1.21 jdolecek return (1);
520 1.21 jdolecek }
521 1.21 jdolecek
522 1.21 jdolecek static const struct filterops vc_nb_read_filtops =
523 1.21 jdolecek { 1, NULL, filt_vc_nb_detach, filt_vc_nb_read };
524 1.21 jdolecek
525 1.21 jdolecek int
526 1.21 jdolecek vc_nb_kqfilter(dev_t dev, struct knote *kn)
527 1.21 jdolecek {
528 1.21 jdolecek struct vcomm *vcp;
529 1.21 jdolecek struct klist *klist;
530 1.21 jdolecek
531 1.21 jdolecek ENTRY;
532 1.26.12.1 yamt
533 1.21 jdolecek if (minor(dev) >= NVCODA || minor(dev) < 0)
534 1.21 jdolecek return(ENXIO);
535 1.26.12.1 yamt
536 1.21 jdolecek vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
537 1.21 jdolecek
538 1.21 jdolecek switch (kn->kn_filter) {
539 1.21 jdolecek case EVFILT_READ:
540 1.22 christos klist = &vcp->vc_selproc.sel_klist;
541 1.21 jdolecek kn->kn_fop = &vc_nb_read_filtops;
542 1.21 jdolecek break;
543 1.21 jdolecek
544 1.21 jdolecek default:
545 1.21 jdolecek return (1);
546 1.21 jdolecek }
547 1.21 jdolecek
548 1.21 jdolecek kn->kn_hook = vcp;
549 1.21 jdolecek
550 1.21 jdolecek SLIST_INSERT_HEAD(klist, kn, kn_selnext);
551 1.21 jdolecek
552 1.21 jdolecek return (0);
553 1.21 jdolecek }
554 1.21 jdolecek
555 1.1 rvb /*
556 1.1 rvb * Statistics
557 1.1 rvb */
558 1.3 rvb struct coda_clstat coda_clstat;
559 1.1 rvb
560 1.26.12.1 yamt /*
561 1.23 wiz * Key question: whether to sleep interruptably or uninterruptably when
562 1.1 rvb * waiting for Venus. The former seems better (cause you can ^C a
563 1.1 rvb * job), but then GNU-EMACS completion breaks. Use tsleep with no
564 1.1 rvb * timeout, and no longjmp happens. But, when sleeping
565 1.1 rvb * "uninterruptibly", we don't get told if it returns abnormally
566 1.26.12.1 yamt * (e.g. kill -9).
567 1.1 rvb */
568 1.1 rvb
569 1.1 rvb int
570 1.26.12.1 yamt coda_call(mntinfo, inSize, outSize, buffer)
571 1.3 rvb struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
572 1.1 rvb {
573 1.1 rvb struct vcomm *vcp;
574 1.1 rvb struct vmsg *vmp;
575 1.1 rvb int error;
576 1.1 rvb #ifdef CTL_C
577 1.26 fvdl struct proc *p = curproc;
578 1.4 rvb sigset_t psig_omask;
579 1.1 rvb int i;
580 1.26 fvdl psig_omask = p->p_sigctx.ps_siglist; /* array assignment */
581 1.1 rvb #endif
582 1.1 rvb if (mntinfo == NULL) {
583 1.1 rvb /* Unlikely, but could be a race condition with a dying warden */
584 1.1 rvb return ENODEV;
585 1.1 rvb }
586 1.1 rvb
587 1.1 rvb vcp = &(mntinfo->mi_vcomm);
588 1.26.12.1 yamt
589 1.3 rvb coda_clstat.ncalls++;
590 1.3 rvb coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
591 1.1 rvb
592 1.1 rvb if (!VC_OPEN(vcp))
593 1.1 rvb return(ENODEV);
594 1.1 rvb
595 1.3 rvb CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
596 1.1 rvb /* Format the request message. */
597 1.1 rvb vmp->vm_data = buffer;
598 1.1 rvb vmp->vm_flags = 0;
599 1.1 rvb vmp->vm_inSize = inSize;
600 1.26.12.1 yamt vmp->vm_outSize
601 1.1 rvb = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
602 1.3 rvb vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
603 1.1 rvb vmp->vm_unique = ++vcp->vc_seq;
604 1.3 rvb if (codadebug)
605 1.26.12.1 yamt myprintf(("Doing a call for %d.%d\n",
606 1.1 rvb vmp->vm_opcode, vmp->vm_unique));
607 1.26.12.1 yamt
608 1.1 rvb /* Fill in the common input args. */
609 1.3 rvb ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
610 1.1 rvb
611 1.1 rvb /* Append msg to request queue and poke Venus. */
612 1.1 rvb INSQUE(vmp->vm_chain, vcp->vc_requests);
613 1.21 jdolecek selnotify(&(vcp->vc_selproc), 0);
614 1.1 rvb
615 1.1 rvb /* We can be interrupted while we wait for Venus to process
616 1.1 rvb * our request. If the interrupt occurs before Venus has read
617 1.1 rvb * the request, we dequeue and return. If it occurs after the
618 1.1 rvb * read but before the reply, we dequeue, send a signal
619 1.1 rvb * message, and return. If it occurs after the reply we ignore
620 1.1 rvb * it. In no case do we want to restart the syscall. If it
621 1.1 rvb * was interrupted by a venus shutdown (vcclose), return
622 1.1 rvb * ENODEV. */
623 1.1 rvb
624 1.1 rvb /* Ignore return, We have to check anyway */
625 1.1 rvb #ifdef CTL_C
626 1.3 rvb /* This is work in progress. Setting coda_pcatch lets tsleep reawaken
627 1.1 rvb on a ^c or ^z. The problem is that emacs sets certain interrupts
628 1.1 rvb as SA_RESTART. This means that we should exit sleep handle the
629 1.1 rvb "signal" and then go to sleep again. Mostly this is done by letting
630 1.26.12.1 yamt the syscall complete and be restarted. We are not idempotent and
631 1.1 rvb can not do this. A better solution is necessary.
632 1.1 rvb */
633 1.1 rvb i = 0;
634 1.1 rvb do {
635 1.3 rvb error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2);
636 1.1 rvb if (error == 0)
637 1.1 rvb break;
638 1.1 rvb else if (error == EWOULDBLOCK) {
639 1.7 rvb #ifdef CODA_VERBOSE
640 1.3 rvb printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
641 1.5 rvb #endif
642 1.14 jdolecek } else if (sigismember(&p->p_sigctx.ps_siglist, SIGIO)) {
643 1.14 jdolecek sigaddset(&p->p_sigctx.ps_sigmask, SIGIO);
644 1.7 rvb #ifdef CODA_VERBOSE
645 1.3 rvb printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i);
646 1.5 rvb #endif
647 1.14 jdolecek } else if (sigismember(&p->p_sigctx.ps_siglist, SIGALRM)) {
648 1.14 jdolecek sigaddset(&p->p_sigctx.ps_sigmask, SIGALRM);
649 1.8 rvb #ifdef CODA_VERBOSE
650 1.8 rvb printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i);
651 1.8 rvb #endif
652 1.1 rvb } else {
653 1.4 rvb sigset_t tmp;
654 1.14 jdolecek tmp = p->p_sigctx.ps_siglist; /* array assignment */
655 1.14 jdolecek sigminusset(&p->p_sigctx.ps_sigmask, &tmp);
656 1.4 rvb
657 1.7 rvb #ifdef CODA_VERBOSE
658 1.3 rvb printf("coda_call: tsleep returns %d, cnt %d\n", error, i);
659 1.4 rvb printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n",
660 1.14 jdolecek p->p_sigctx.ps_siglist.__bits[0], p->p_sigctx.ps_siglist.__bits[1],
661 1.14 jdolecek p->p_sigctx.ps_siglist.__bits[2], p->p_sigctx.ps_siglist.__bits[3],
662 1.14 jdolecek p->p_sigctx.ps_sigmask.__bits[0], p->p_sigctx.ps_sigmask.__bits[1],
663 1.14 jdolecek p->p_sigctx.ps_sigmask.__bits[2], p->p_sigctx.ps_sigmask.__bits[3],
664 1.4 rvb tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]);
665 1.5 rvb #endif
666 1.1 rvb break;
667 1.5 rvb #ifdef notyet
668 1.14 jdolecek sigminusset(&p->p_sigctx.ps_sigmask, &p->p_sigctx.ps_siglist);
669 1.26.12.1 yamt printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n",
670 1.15 jdolecek p->p_sigctx.ps_siglist.__bits[0], p->p_sigctx.ps_siglist.__bits[1],
671 1.15 jdolecek p->p_sigctx.ps_siglist.__bits[2], p->p_sigctx.ps_siglist.__bits[3],
672 1.15 jdolecek p->p_sigctx.ps_sigmask.__bits[0], p->p_sigctx.ps_sigmask.__bits[1],
673 1.15 jdolecek p->p_sigctx.ps_sigmask.__bits[2], p->p_sigctx.ps_sigmask.__bits[3]);
674 1.5 rvb #endif
675 1.1 rvb }
676 1.8 rvb } while (error && i++ < 128 && VC_OPEN(vcp));
677 1.14 jdolecek p->p_sigctx.ps_siglist = psig_omask; /* array assignment */
678 1.1 rvb #else
679 1.3 rvb (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
680 1.1 rvb #endif
681 1.1 rvb if (VC_OPEN(vcp)) { /* Venus is still alive */
682 1.1 rvb /* Op went through, interrupt or not... */
683 1.1 rvb if (vmp->vm_flags & VM_WRITE) {
684 1.1 rvb error = 0;
685 1.1 rvb *outSize = vmp->vm_outSize;
686 1.1 rvb }
687 1.1 rvb
688 1.26.12.1 yamt else if (!(vmp->vm_flags & VM_READ)) {
689 1.1 rvb /* Interrupted before venus read it. */
690 1.7 rvb #ifdef CODA_VERBOSE
691 1.7 rvb if (1)
692 1.7 rvb #else
693 1.5 rvb if (codadebug)
694 1.5 rvb #endif
695 1.1 rvb myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
696 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
697 1.1 rvb REMQUE(vmp->vm_chain);
698 1.1 rvb error = EINTR;
699 1.1 rvb }
700 1.26.12.1 yamt
701 1.26.12.1 yamt else {
702 1.1 rvb /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
703 1.1 rvb upcall started */
704 1.1 rvb /* Interrupted after start of upcall, send venus a signal */
705 1.3 rvb struct coda_in_hdr *dog;
706 1.1 rvb struct vmsg *svmp;
707 1.26.12.1 yamt
708 1.7 rvb #ifdef CODA_VERBOSE
709 1.7 rvb if (1)
710 1.7 rvb #else
711 1.5 rvb if (codadebug)
712 1.5 rvb #endif
713 1.1 rvb myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
714 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
715 1.26.12.1 yamt
716 1.1 rvb REMQUE(vmp->vm_chain);
717 1.1 rvb error = EINTR;
718 1.26.12.1 yamt
719 1.3 rvb CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
720 1.1 rvb
721 1.3 rvb CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
722 1.3 rvb dog = (struct coda_in_hdr *)svmp->vm_data;
723 1.26.12.1 yamt
724 1.1 rvb svmp->vm_flags = 0;
725 1.3 rvb dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
726 1.1 rvb dog->unique = svmp->vm_unique = vmp->vm_unique;
727 1.3 rvb svmp->vm_inSize = sizeof (struct coda_in_hdr);
728 1.3 rvb /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
729 1.26.12.1 yamt
730 1.3 rvb if (codadebug)
731 1.3 rvb myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
732 1.1 rvb svmp->vm_opcode, svmp->vm_unique));
733 1.26.12.1 yamt
734 1.1 rvb /* insert at head of queue! */
735 1.1 rvb INSQUE(svmp->vm_chain, vcp->vc_requests);
736 1.21 jdolecek selnotify(&(vcp->vc_selproc), 0);
737 1.1 rvb }
738 1.1 rvb }
739 1.1 rvb
740 1.1 rvb else { /* If venus died (!VC_OPEN(vcp)) */
741 1.3 rvb if (codadebug)
742 1.1 rvb myprintf(("vcclose woke op %d.%d flags %d\n",
743 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
744 1.26.12.1 yamt
745 1.1 rvb error = ENODEV;
746 1.1 rvb }
747 1.1 rvb
748 1.3 rvb CODA_FREE(vmp, sizeof(struct vmsg));
749 1.8 rvb
750 1.8 rvb if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
751 1.8 rvb wakeup(&outstanding_upcalls);
752 1.1 rvb
753 1.1 rvb if (!error)
754 1.3 rvb error = ((struct coda_out_hdr *)buffer)->result;
755 1.1 rvb return(error);
756 1.1 rvb }
757 1.4 rvb
758