3 * Coda: an Experimental Distributed File System
6 * Copyright (c) 1987-1998 Carnegie Mellon University
9 * Permission to use, copy, modify and distribute this software and its
10 * documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation, and
14 * that credit is given to Carnegie Mellon University in all documents
15 * and publicity pertaining to direct or indirect use of this code or its
18 * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS,
19 * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS
20 * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON
21 * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
22 * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF
23 * ANY DERIVATIVE WORK.
25 * Carnegie Mellon encourages users of this software to return any
26 * improvements or extensions that they make, and to grant Carnegie
27 * Mellon the rights to redistribute these changes without encumbrance.
29 * @(#) src/sys/coda/coda_psdev.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
30 * $FreeBSD: src/sys/coda/coda_psdev.c,v 1.13 1999/09/29 15:03:46 marcel Exp $
31 * $DragonFly: src/sys/vfs/coda/Attic/coda_psdev.c,v 1.2 2003/06/17 04:28:19 dillon Exp $
36 * Mach Operating System
37 * Copyright (c) 1989 Carnegie-Mellon University
38 * All rights reserved. The CMU software License Agreement specifies
39 * the terms and conditions for use and redistribution.
43 * This code was written for the Coda file system at Carnegie Mellon
44 * University. Contributers include David Steere, James Kistler, and
45 * M. Satyanarayanan. */
48 * These routines define the psuedo device for communication between
49 * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
50 * but I moved them to make it easier to port the Minicache without
51 * porting coda. -- DCS 10/12/94
54 /* These routines are the device entry points for Venus. */
56 extern int coda_nc_initialized; /* Set if cache has been initialized */
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/kernel.h>
64 #include <sys/malloc.h>
65 #include <sys/mount.h>
67 #include <sys/ioccom.h>
71 #include <coda/coda.h>
72 #include <coda/cnode.h>
73 #include <coda/coda_namecache.h>
74 #include <coda/coda_io.h>
75 #include <coda/coda_psdev.h>
80 #include <sys/signalvar.h>
83 int coda_psdev_print_entry = 0;
85 int outstanding_upcalls = 0;
86 int coda_call_sleep = PZERO - 1;
88 int coda_pcatch = PCATCH;
92 #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__FUNCTION__))
94 void vcodaattach(int n);
97 struct queue vm_chain;
100 u_short vm_inSize; /* Size is at most 5000 bytes */
102 u_short vm_opcode; /* copied from data to save ptr lookup */
104 caddr_t vm_sleep; /* Not used by Mach. */
111 /* vcodaattach: do nothing */
119 vc_nb_open(dev, flag, mode, p)
123 struct proc *p; /* NetBSD only */
125 register struct vcomm *vcp;
129 if (minor(dev) >= NVCODA || minor(dev) < 0)
132 if (!coda_nc_initialized)
135 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
139 bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
140 INIT_QUEUE(vcp->vc_requests);
141 INIT_QUEUE(vcp->vc_replys);
144 coda_mnttbl[minor(dev)].mi_vfsp = NULL;
145 coda_mnttbl[minor(dev)].mi_rootvp = NULL;
151 vc_nb_close (dev, flag, mode, p)
157 register struct vcomm *vcp;
158 register struct vmsg *vmp, *nvmp = NULL;
159 struct coda_mntinfo *mi;
164 if (minor(dev) >= NVCODA || minor(dev) < 0)
167 mi = &coda_mnttbl[minor(dev)];
168 vcp = &(mi->mi_vcomm);
171 panic("vcclose: not open");
173 /* prevent future operations on this vfs from succeeding by auto-
174 * unmounting any vfs mounted via this device. This frees user or
175 * sysadm from having to remember where all mount points are located.
176 * Put this before WAKEUPs to avoid queuing new messages between
177 * the WAKEUP and the unmount (which can happen if we're unlucky)
179 if (!mi->mi_rootvp) {
180 /* just a simple open/close w no mount */
185 /* Let unmount know this is for real */
186 VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
187 coda_unmounting(mi->mi_vfsp);
189 outstanding_upcalls = 0;
190 /* Wakeup clients so they can return. */
191 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
192 !EOQ(vmp, vcp->vc_requests);
195 nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain);
196 /* Free signal request messages and don't wakeup cause
197 no one is waiting. */
198 if (vmp->vm_opcode == CODA_SIGNAL) {
199 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
200 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
203 outstanding_upcalls++;
204 wakeup(&vmp->vm_sleep);
207 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
208 !EOQ(vmp, vcp->vc_replys);
209 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
211 outstanding_upcalls++;
212 wakeup(&vmp->vm_sleep);
217 if (outstanding_upcalls) {
219 printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
220 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
221 printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
223 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
227 err = dounmount(mi->mi_vfsp, flag, p);
229 myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
235 vc_nb_read(dev, uiop, flag)
240 register struct vcomm * vcp;
241 register struct vmsg *vmp;
246 if (minor(dev) >= NVCODA || minor(dev) < 0)
249 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
250 /* Get message at head of request queue. */
251 if (EMPTY(vcp->vc_requests))
252 return(0); /* Nothing to read */
254 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
256 /* Move the input args into userspace */
257 uiop->uio_rw = UIO_READ;
258 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
260 myprintf(("vcread: error (%d) on uiomove\n", error));
264 #ifdef OLD_DIAGNOSTIC
265 if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
266 panic("vc_nb_read: bad chain");
269 REMQUE(vmp->vm_chain);
271 /* If request was a signal, free up the message and don't
272 enqueue it in the reply queue. */
273 if (vmp->vm_opcode == CODA_SIGNAL) {
275 myprintf(("vcread: signal msg (%d, %d)\n",
276 vmp->vm_opcode, vmp->vm_unique));
277 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
278 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
282 vmp->vm_flags |= VM_READ;
283 INSQUE(vmp->vm_chain, vcp->vc_replys);
289 vc_nb_write(dev, uiop, flag)
294 register struct vcomm * vcp;
295 register struct vmsg *vmp;
296 struct coda_out_hdr *out;
304 if (minor(dev) >= NVCODA || minor(dev) < 0)
307 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
309 /* Peek at the opcode, unique without transfering the data. */
310 uiop->uio_rw = UIO_WRITE;
311 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
313 myprintf(("vcwrite: error (%d) on uiomove\n", error));
321 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
323 if (DOWNCALL(opcode)) {
324 union outputArgs pbuf;
326 /* get the rest of the data. */
327 uiop->uio_rw = UIO_WRITE;
328 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
330 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
331 error, opcode, seq));
335 return handleDownCall(opcode, &pbuf);
338 /* Look for the message on the (waiting for) reply queue. */
339 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
340 !EOQ(vmp, vcp->vc_replys);
341 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
343 if (vmp->vm_unique == seq) break;
346 if (EOQ(vmp, vcp->vc_replys)) {
348 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
353 /* Remove the message from the reply queue */
354 REMQUE(vmp->vm_chain);
356 /* move data into response buffer. */
357 out = (struct coda_out_hdr *)vmp->vm_data;
358 /* Don't need to copy opcode and uniquifier. */
360 /* get the rest of the data. */
361 if (vmp->vm_outSize < uiop->uio_resid) {
362 myprintf(("vcwrite: more data than asked for (%d < %d)\n",
363 vmp->vm_outSize, uiop->uio_resid));
364 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
368 buf[0] = uiop->uio_resid; /* Save this value. */
369 uiop->uio_rw = UIO_WRITE;
370 error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
372 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
373 error, opcode, seq));
377 /* I don't think these are used, but just in case. */
378 /* XXX - aren't these two already correct? -bnoble */
379 out->opcode = opcode;
381 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
382 vmp->vm_flags |= VM_WRITE;
383 wakeup(&vmp->vm_sleep);
389 vc_nb_ioctl(dev, cmd, addr, flag, p)
400 struct coda_resize *data = (struct coda_resize *)addr;
401 return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
406 coda_nc_gather_stats();
420 case CIOC_KERNEL_VERSION:
421 switch (*(u_int *)addr) {
423 *(u_int *)addr = coda_kernel_version;
428 if (coda_kernel_version != *(u_int *)addr)
443 vc_nb_poll(dev, events, p)
448 register struct vcomm *vcp;
453 if (minor(dev) >= NVCODA || minor(dev) < 0)
456 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
458 event_msk = events & (POLLIN|POLLRDNORM);
462 if (!EMPTY(vcp->vc_requests))
463 return(events & (POLLIN|POLLRDNORM));
465 selrecord(p, &(vcp->vc_selproc));
473 struct coda_clstat coda_clstat;
476 * Key question: whether to sleep interuptably or uninteruptably when
477 * waiting for Venus. The former seems better (cause you can ^C a
478 * job), but then GNU-EMACS completion breaks. Use tsleep with no
479 * timeout, and no longjmp happens. But, when sleeping
480 * "uninterruptibly", we don't get told if it returns abnormally
485 coda_call(mntinfo, inSize, outSize, buffer)
486 struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
492 struct proc *p = curproc;
493 sigset_t psig_omask = p->p_sigmask;
497 if (mntinfo == NULL) {
498 /* Unlikely, but could be a race condition with a dying warden */
502 vcp = &(mntinfo->mi_vcomm);
504 coda_clstat.ncalls++;
505 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
510 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
511 /* Format the request message. */
512 vmp->vm_data = buffer;
514 vmp->vm_inSize = inSize;
516 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
517 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
518 vmp->vm_unique = ++vcp->vc_seq;
520 myprintf(("Doing a call for %d.%d\n",
521 vmp->vm_opcode, vmp->vm_unique));
523 /* Fill in the common input args. */
524 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
526 /* Append msg to request queue and poke Venus. */
527 INSQUE(vmp->vm_chain, vcp->vc_requests);
528 selwakeup(&(vcp->vc_selproc));
530 /* We can be interrupted while we wait for Venus to process
531 * our request. If the interrupt occurs before Venus has read
532 * the request, we dequeue and return. If it occurs after the
533 * read but before the reply, we dequeue, send a signal
534 * message, and return. If it occurs after the reply we ignore
535 * it. In no case do we want to restart the syscall. If it
536 * was interrupted by a venus shutdown (vcclose), return
539 /* Ignore return, We have to check anyway */
541 /* This is work in progress. Setting coda_pcatch lets tsleep reawaken
542 on a ^c or ^z. The problem is that emacs sets certain interrupts
543 as SA_RESTART. This means that we should exit sleep handle the
544 "signal" and then go to sleep again. Mostly this is done by letting
545 the syscall complete and be restarted. We are not idempotent and
546 can not do this. A better solution is necessary.
550 error = tsleep(&vmp->vm_sleep,
551 (coda_call_sleep|coda_pcatch), "coda_call",
555 else if (error == EWOULDBLOCK) {
557 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
561 SIGEMPTYSET(tempset);
562 SIGADDSET(tempset, SIGIO);
563 if (SIGSETEQ(p->p_siglist, tempset)) {
564 SIGADDSET(p->p_sigmask, SIGIO);
566 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n",
570 SIGDELSET(tempset, SIGIO);
571 SIGADDSET(tempset, SIGALRM);
572 if (SIGSETEQ(p->p_siglist, tempset)) {
573 SIGADDSET(p->p_sigmask, SIGALRM);
575 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n",
580 printf("coda_call: tsleep returns %d, cnt %d\n",
584 tempset = p->p_siglist;
585 SIGSETNAND(tempset, p->p_sigmask);
586 printf("coda_call: siglist = %p, sigmask = %p, mask %p\n",
587 p->p_siglist, p->p_sigmask,
590 SIGSETOR(p->p_sigmask, p->p_siglist);
591 tempset = p->p_siglist;
592 SIGSETNAND(tempset, p->p_sigmask);
593 printf("coda_call: new mask, siglist = %p, sigmask = %p, mask %p\n",
594 p->p_siglist, p->p_sigmask,
600 } while (error && i++ < 128 && VC_OPEN(vcp));
601 p->p_sigmask = psig_omask;
603 (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
605 if (VC_OPEN(vcp)) { /* Venus is still alive */
606 /* Op went through, interrupt or not... */
607 if (vmp->vm_flags & VM_WRITE) {
609 *outSize = vmp->vm_outSize;
612 else if (!(vmp->vm_flags & VM_READ)) {
613 /* Interrupted before venus read it. */
619 myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
620 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
621 REMQUE(vmp->vm_chain);
626 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
628 /* Interrupted after start of upcall, send venus a signal */
629 struct coda_in_hdr *dog;
637 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
638 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
640 REMQUE(vmp->vm_chain);
643 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
645 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
646 dog = (struct coda_in_hdr *)svmp->vm_data;
649 dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
650 dog->unique = svmp->vm_unique = vmp->vm_unique;
651 svmp->vm_inSize = sizeof (struct coda_in_hdr);
652 /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
655 myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
656 svmp->vm_opcode, svmp->vm_unique));
658 /* insert at head of queue! */
659 INSQUE(svmp->vm_chain, vcp->vc_requests);
660 selwakeup(&(vcp->vc_selproc));
664 else { /* If venus died (!VC_OPEN(vcp)) */
666 myprintf(("vcclose woke op %d.%d flags %d\n",
667 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
672 CODA_FREE(vmp, sizeof(struct vmsg));
674 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
675 wakeup(&outstanding_upcalls);
678 error = ((struct coda_out_hdr *)buffer)->result;