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