2 * Coda: an Experimental Distributed File System
5 * Copyright (c) 1987-1998 Carnegie Mellon University
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation, and
13 * that credit is given to Carnegie Mellon University in all documents
14 * and publicity pertaining to direct or indirect use of this code or its
17 * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS,
18 * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS
19 * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON
20 * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
21 * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF
22 * ANY DERIVATIVE WORK.
24 * Carnegie Mellon encourages users of this software to return any
25 * improvements or extensions that they make, and to grant Carnegie
26 * Mellon the rights to redistribute these changes without encumbrance.
28 * @(#) src/sys/coda/coda_psdev.c,v 1.1.1.1 1998/08/29 21:14:52 rvb Exp $
31 * Mach Operating System
32 * Copyright (c) 1989 Carnegie-Mellon University
33 * All rights reserved. The CMU software License Agreement specifies
34 * the terms and conditions for use and redistribution.
38 * This code was written for the Coda filesystem at Carnegie Mellon
39 * University. Contributers include David Steere, James Kistler, and
40 * M. Satyanarayanan. */
43 * These routines define the psuedo device for communication between
44 * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
45 * but I moved them to make it easier to port the Minicache without
46 * porting coda. -- DCS 10/12/94
49 /* These routines are the device entry points for Venus. */
51 #include <sys/cdefs.h>
52 __FBSDID("$FreeBSD$");
55 extern int coda_nc_initialized; /* Set if cache has been initialized */
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/ioccom.h>
60 #include <sys/kernel.h>
62 #include <sys/malloc.h>
63 #include <sys/file.h> /* must come after sys/malloc.h */
64 #include <sys/mount.h>
65 #include <sys/mutex.h>
69 #include <coda/coda.h>
70 #include <coda/cnode.h>
71 #include <coda/coda_namecache.h>
72 #include <coda/coda_io.h>
73 #include <coda/coda_psdev.h>
78 #include <sys/signalvar.h>
81 int coda_psdev_print_entry = 0;
83 int outstanding_upcalls = 0;
84 int coda_call_sleep = PZERO - 1;
86 int coda_pcatch = PCATCH;
90 #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__))
92 void vcodaattach(int n);
95 struct queue vm_chain;
98 u_short vm_inSize; /* Size is at most 5000 bytes */
100 u_short vm_opcode; /* copied from data to save ptr lookup */
102 caddr_t vm_sleep; /* Not used by Mach. */
109 /* vcodaattach: do nothing */
117 vc_nb_open(dev, flag, mode, td)
121 struct thread *td; /* NetBSD only */
124 struct coda_mntinfo *mnt;
128 if (!coda_nc_initialized)
131 mnt = dev2coda_mntinfo(dev);
132 vcp = &mnt->mi_vcomm;
136 bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
137 INIT_QUEUE(vcp->vc_requests);
138 INIT_QUEUE(vcp->vc_replys);
142 mnt->mi_rootvp = NULL;
148 vc_nb_close (dev, flag, mode, td)
154 register struct vcomm *vcp;
155 register struct vmsg *vmp, *nvmp = NULL;
156 struct coda_mntinfo *mi;
161 mi = dev2coda_mntinfo(dev);
162 vcp = &(mi->mi_vcomm);
165 panic("vcclose: not open");
167 /* prevent future operations on this vfs from succeeding by auto-
168 * unmounting any vfs mounted via this device. This frees user or
169 * sysadm from having to remember where all mount points are located.
170 * Put this before WAKEUPs to avoid queuing new messages between
171 * the WAKEUP and the unmount (which can happen if we're unlucky)
173 if (!mi->mi_rootvp) {
174 /* just a simple open/close w no mount */
179 /* Let unmount know this is for real */
180 VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
181 coda_unmounting(mi->mi_vfsp);
183 outstanding_upcalls = 0;
184 /* Wakeup clients so they can return. */
185 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
186 !EOQ(vmp, vcp->vc_requests);
189 nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain);
190 /* Free signal request messages and don't wakeup cause
191 no one is waiting. */
192 if (vmp->vm_opcode == CODA_SIGNAL) {
193 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
194 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
197 outstanding_upcalls++;
198 wakeup(&vmp->vm_sleep);
201 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
202 !EOQ(vmp, vcp->vc_replys);
203 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
205 outstanding_upcalls++;
206 wakeup(&vmp->vm_sleep);
211 if (outstanding_upcalls) {
213 printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
214 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
215 printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
217 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
221 err = dounmount(mi->mi_vfsp, flag, td);
223 myprintf(("Error %d unmounting vfs in vcclose(%s)\n",
224 err, devtoname(dev)));
229 vc_nb_read(dev, uiop, flag)
234 register struct vcomm * vcp;
235 register struct vmsg *vmp;
240 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
241 /* Get message at head of request queue. */
242 if (EMPTY(vcp->vc_requests))
243 return(0); /* Nothing to read */
245 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
247 /* Move the input args into userspace */
248 uiop->uio_rw = UIO_READ;
249 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
251 myprintf(("vcread: error (%d) on uiomove\n", error));
255 #ifdef OLD_DIAGNOSTIC
256 if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
257 panic("vc_nb_read: bad chain");
260 REMQUE(vmp->vm_chain);
262 /* If request was a signal, free up the message and don't
263 enqueue it in the reply queue. */
264 if (vmp->vm_opcode == CODA_SIGNAL) {
266 myprintf(("vcread: signal msg (%d, %d)\n",
267 vmp->vm_opcode, vmp->vm_unique));
268 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
269 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
273 vmp->vm_flags |= VM_READ;
274 INSQUE(vmp->vm_chain, vcp->vc_replys);
280 vc_nb_write(dev, uiop, flag)
285 register struct vcomm * vcp;
286 register struct vmsg *vmp;
287 struct coda_out_hdr *out;
295 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
297 /* Peek at the opcode, unique without transfering the data. */
298 uiop->uio_rw = UIO_WRITE;
299 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
301 myprintf(("vcwrite: error (%d) on uiomove\n", error));
309 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
311 if (DOWNCALL(opcode)) {
312 union outputArgs pbuf;
314 /* get the rest of the data. */
315 uiop->uio_rw = UIO_WRITE;
316 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
318 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
319 error, opcode, seq));
323 return handleDownCall(opcode, &pbuf);
326 /* Look for the message on the (waiting for) reply queue. */
327 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
328 !EOQ(vmp, vcp->vc_replys);
329 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
331 if (vmp->vm_unique == seq) break;
334 if (EOQ(vmp, vcp->vc_replys)) {
336 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
341 /* Remove the message from the reply queue */
342 REMQUE(vmp->vm_chain);
344 /* move data into response buffer. */
345 out = (struct coda_out_hdr *)vmp->vm_data;
346 /* Don't need to copy opcode and uniquifier. */
348 /* get the rest of the data. */
349 if (vmp->vm_outSize < uiop->uio_resid) {
350 myprintf(("vcwrite: more data than asked for (%d < %d)\n",
351 vmp->vm_outSize, uiop->uio_resid));
352 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
356 buf[0] = uiop->uio_resid; /* Save this value. */
357 uiop->uio_rw = UIO_WRITE;
358 error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
360 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
361 error, opcode, seq));
365 /* I don't think these are used, but just in case. */
366 /* XXX - aren't these two already correct? -bnoble */
367 out->opcode = opcode;
369 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
370 vmp->vm_flags |= VM_WRITE;
371 wakeup(&vmp->vm_sleep);
377 vc_nb_ioctl(dev, cmd, addr, flag, td)
388 struct coda_resize *data = (struct coda_resize *)addr;
389 return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
394 coda_nc_gather_stats();
408 case CIOC_KERNEL_VERSION:
409 switch (*(u_int *)addr) {
411 *(u_int *)addr = coda_kernel_version;
416 if (coda_kernel_version != *(u_int *)addr)
431 vc_nb_poll(dev, events, td)
436 register struct vcomm *vcp;
441 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
443 event_msk = events & (POLLIN|POLLRDNORM);
447 if (!EMPTY(vcp->vc_requests))
448 return(events & (POLLIN|POLLRDNORM));
450 selrecord(td, &(vcp->vc_selproc));
458 struct coda_clstat coda_clstat;
461 * Key question: whether to sleep interuptably or uninteruptably when
462 * waiting for Venus. The former seems better (cause you can ^C a
463 * job), but then GNU-EMACS completion breaks. Use tsleep with no
464 * timeout, and no longjmp happens. But, when sleeping
465 * "uninterruptibly", we don't get told if it returns abnormally
470 coda_call(mntinfo, inSize, outSize, buffer)
471 struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
477 struct thread *td = curthread;
478 struct proc *p = td->td_proc;
483 if (mntinfo == NULL) {
484 /* Unlikely, but could be a race condition with a dying warden */
488 vcp = &(mntinfo->mi_vcomm);
490 coda_clstat.ncalls++;
491 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
496 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
497 /* Format the request message. */
498 vmp->vm_data = buffer;
500 vmp->vm_inSize = inSize;
502 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
503 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
504 vmp->vm_unique = ++vcp->vc_seq;
506 myprintf(("Doing a call for %d.%d\n",
507 vmp->vm_opcode, vmp->vm_unique));
509 /* Fill in the common input args. */
510 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
512 /* Append msg to request queue and poke Venus. */
513 INSQUE(vmp->vm_chain, vcp->vc_requests);
514 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep);
516 /* We can be interrupted while we wait for Venus to process
517 * our request. If the interrupt occurs before Venus has read
518 * the request, we dequeue and return. If it occurs after the
519 * read but before the reply, we dequeue, send a signal
520 * message, and return. If it occurs after the reply we ignore
521 * it. In no case do we want to restart the syscall. If it
522 * was interrupted by a venus shutdown (vcclose), return
525 /* Ignore return, We have to check anyway */
527 /* This is work in progress. Setting coda_pcatch lets tsleep reawaken
528 on a ^c or ^z. The problem is that emacs sets certain interrupts
529 as SA_RESTART. This means that we should exit sleep handle the
530 "signal" and then go to sleep again. Mostly this is done by letting
531 the syscall complete and be restarted. We are not idempotent and
532 can not do this. A better solution is necessary.
536 psig_omask = td->td_sigmask;
538 error = msleep(&vmp->vm_sleep, &p->p_mtx,
539 (coda_call_sleep|coda_pcatch), "coda_call",
543 else if (error == EWOULDBLOCK) {
545 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
549 SIGEMPTYSET(tempset);
550 SIGADDSET(tempset, SIGIO);
551 if (SIGSETEQ(td->td_siglist, tempset)) {
552 SIGADDSET(td->td_sigmask, SIGIO);
554 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n",
558 SIGDELSET(tempset, SIGIO);
559 SIGADDSET(tempset, SIGALRM);
560 if (SIGSETEQ(td->td_siglist, tempset)) {
561 SIGADDSET(td->td_sigmask, SIGALRM);
563 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n",
569 printf("coda_call: tsleep returns %d, cnt %d\n",
574 tempset = td->td_siglist;
575 SIGSETNAND(tempset, td->td_sigmask);
576 printf("coda_call: siglist = %p, sigmask = %p, mask %p\n",
577 td->td_siglist, td->td_sigmask,
580 SIGSETOR(td->td_sigmask, td->td_siglist);
581 tempset = td->td_siglist;
582 SIGSETNAND(tempset, td->td_sigmask);
583 printf("coda_call: new mask, siglist = %p, sigmask = %p, mask %p\n",
584 td->td_siglist, td->td_sigmask,
590 } while (error && i++ < 128 && VC_OPEN(vcp));
591 td->td_sigmask = psig_omask;
595 (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
597 if (VC_OPEN(vcp)) { /* Venus is still alive */
598 /* Op went through, interrupt or not... */
599 if (vmp->vm_flags & VM_WRITE) {
601 *outSize = vmp->vm_outSize;
604 else if (!(vmp->vm_flags & VM_READ)) {
605 /* Interrupted before venus read it. */
611 myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
612 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
613 REMQUE(vmp->vm_chain);
618 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
620 /* Interrupted after start of upcall, send venus a signal */
621 struct coda_in_hdr *dog;
629 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
630 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
632 REMQUE(vmp->vm_chain);
635 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
637 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
638 dog = (struct coda_in_hdr *)svmp->vm_data;
641 dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
642 dog->unique = svmp->vm_unique = vmp->vm_unique;
643 svmp->vm_inSize = sizeof (struct coda_in_hdr);
644 /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
647 myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
648 svmp->vm_opcode, svmp->vm_unique));
650 /* insert at head of queue! */
651 INSQUE(svmp->vm_chain, vcp->vc_requests);
652 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep);
656 else { /* If venus died (!VC_OPEN(vcp)) */
658 myprintf(("vcclose woke op %d.%d flags %d\n",
659 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
664 CODA_FREE(vmp, sizeof(struct vmsg));
666 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
667 wakeup(&outstanding_upcalls);
670 error = ((struct coda_out_hdr *)buffer)->result;