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 KASSERT(mnt, ("Coda: tried to open uninitialized cfs device"));
134 vcp = &mnt->mi_vcomm;
138 bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
139 INIT_QUEUE(vcp->vc_requests);
140 INIT_QUEUE(vcp->vc_replys);
144 mnt->mi_rootvp = NULL;
150 vc_nb_close (dev, flag, mode, td)
156 register struct vcomm *vcp;
157 register struct vmsg *vmp, *nvmp = NULL;
158 struct coda_mntinfo *mi;
163 mi = dev2coda_mntinfo(dev);
164 KASSERT(mi, ("Coda: closing unknown cfs device"));
167 KASSERT(VC_OPEN(vcp), ("Coda: closing unopened cfs device"));
169 /* prevent future operations on this vfs from succeeding by auto-
170 * unmounting any vfs mounted via this device. This frees user or
171 * sysadm from having to remember where all mount points are located.
172 * Put this before WAKEUPs to avoid queuing new messages between
173 * the WAKEUP and the unmount (which can happen if we're unlucky)
175 if (!mi->mi_rootvp) {
176 /* just a simple open/close w no mount */
181 /* Let unmount know this is for real */
182 VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
183 coda_unmounting(mi->mi_vfsp);
185 outstanding_upcalls = 0;
186 /* Wakeup clients so they can return. */
187 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
188 !EOQ(vmp, vcp->vc_requests);
191 nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain);
192 /* Free signal request messages and don't wakeup cause
193 no one is waiting. */
194 if (vmp->vm_opcode == CODA_SIGNAL) {
195 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
196 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
199 outstanding_upcalls++;
200 wakeup(&vmp->vm_sleep);
203 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
204 !EOQ(vmp, vcp->vc_replys);
205 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
207 outstanding_upcalls++;
208 wakeup(&vmp->vm_sleep);
213 if (outstanding_upcalls) {
215 printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
216 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
217 printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
219 (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
223 err = dounmount(mi->mi_vfsp, flag, td);
225 myprintf(("Error %d unmounting vfs in vcclose(%s)\n",
226 err, devtoname(dev)));
231 vc_nb_read(dev, uiop, flag)
236 register struct vcomm * vcp;
237 register struct vmsg *vmp;
242 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
243 /* Get message at head of request queue. */
244 if (EMPTY(vcp->vc_requests))
245 return(0); /* Nothing to read */
247 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
249 /* Move the input args into userspace */
250 uiop->uio_rw = UIO_READ;
251 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
253 myprintf(("vcread: error (%d) on uiomove\n", error));
257 #ifdef OLD_DIAGNOSTIC
258 if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
259 panic("vc_nb_read: bad chain");
262 REMQUE(vmp->vm_chain);
264 /* If request was a signal, free up the message and don't
265 enqueue it in the reply queue. */
266 if (vmp->vm_opcode == CODA_SIGNAL) {
268 myprintf(("vcread: signal msg (%d, %d)\n",
269 vmp->vm_opcode, vmp->vm_unique));
270 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
271 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
275 vmp->vm_flags |= VM_READ;
276 INSQUE(vmp->vm_chain, vcp->vc_replys);
282 vc_nb_write(dev, uiop, flag)
287 register struct vcomm * vcp;
288 register struct vmsg *vmp;
289 struct coda_out_hdr *out;
297 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
299 /* Peek at the opcode, unique without transfering the data. */
300 uiop->uio_rw = UIO_WRITE;
301 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
303 myprintf(("vcwrite: error (%d) on uiomove\n", error));
311 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
313 if (DOWNCALL(opcode)) {
314 union outputArgs pbuf;
316 /* get the rest of the data. */
317 uiop->uio_rw = UIO_WRITE;
318 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
320 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
321 error, opcode, seq));
325 return handleDownCall(opcode, &pbuf);
328 /* Look for the message on the (waiting for) reply queue. */
329 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
330 !EOQ(vmp, vcp->vc_replys);
331 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
333 if (vmp->vm_unique == seq) break;
336 if (EOQ(vmp, vcp->vc_replys)) {
338 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
343 /* Remove the message from the reply queue */
344 REMQUE(vmp->vm_chain);
346 /* move data into response buffer. */
347 out = (struct coda_out_hdr *)vmp->vm_data;
348 /* Don't need to copy opcode and uniquifier. */
350 /* get the rest of the data. */
351 if (vmp->vm_outSize < uiop->uio_resid) {
352 myprintf(("vcwrite: more data than asked for (%d < %d)\n",
353 vmp->vm_outSize, uiop->uio_resid));
354 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
358 buf[0] = uiop->uio_resid; /* Save this value. */
359 uiop->uio_rw = UIO_WRITE;
360 error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
362 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
363 error, opcode, seq));
367 /* I don't think these are used, but just in case. */
368 /* XXX - aren't these two already correct? -bnoble */
369 out->opcode = opcode;
371 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
372 vmp->vm_flags |= VM_WRITE;
373 wakeup(&vmp->vm_sleep);
379 vc_nb_ioctl(dev, cmd, addr, flag, td)
390 struct coda_resize *data = (struct coda_resize *)addr;
391 return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
396 coda_nc_gather_stats();
410 case CIOC_KERNEL_VERSION:
411 switch (*(u_int *)addr) {
413 *(u_int *)addr = coda_kernel_version;
418 if (coda_kernel_version != *(u_int *)addr)
433 vc_nb_poll(dev, events, td)
438 register struct vcomm *vcp;
443 vcp = &dev2coda_mntinfo(dev)->mi_vcomm;
445 event_msk = events & (POLLIN|POLLRDNORM);
449 if (!EMPTY(vcp->vc_requests))
450 return(events & (POLLIN|POLLRDNORM));
452 selrecord(td, &(vcp->vc_selproc));
460 struct coda_clstat coda_clstat;
463 * Key question: whether to sleep interuptably or uninteruptably when
464 * waiting for Venus. The former seems better (cause you can ^C a
465 * job), but then GNU-EMACS completion breaks. Use tsleep with no
466 * timeout, and no longjmp happens. But, when sleeping
467 * "uninterruptibly", we don't get told if it returns abnormally
472 coda_call(mntinfo, inSize, outSize, buffer)
473 struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
479 struct thread *td = curthread;
480 struct proc *p = td->td_proc;
485 if (mntinfo == NULL) {
486 /* Unlikely, but could be a race condition with a dying warden */
490 vcp = &(mntinfo->mi_vcomm);
492 coda_clstat.ncalls++;
493 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
498 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
499 /* Format the request message. */
500 vmp->vm_data = buffer;
502 vmp->vm_inSize = inSize;
504 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
505 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
506 vmp->vm_unique = ++vcp->vc_seq;
508 myprintf(("Doing a call for %d.%d\n",
509 vmp->vm_opcode, vmp->vm_unique));
511 /* Fill in the common input args. */
512 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
514 /* Append msg to request queue and poke Venus. */
515 INSQUE(vmp->vm_chain, vcp->vc_requests);
516 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep);
518 /* We can be interrupted while we wait for Venus to process
519 * our request. If the interrupt occurs before Venus has read
520 * the request, we dequeue and return. If it occurs after the
521 * read but before the reply, we dequeue, send a signal
522 * message, and return. If it occurs after the reply we ignore
523 * it. In no case do we want to restart the syscall. If it
524 * was interrupted by a venus shutdown (vcclose), return
527 /* Ignore return, We have to check anyway */
529 /* This is work in progress. Setting coda_pcatch lets tsleep reawaken
530 on a ^c or ^z. The problem is that emacs sets certain interrupts
531 as SA_RESTART. This means that we should exit sleep handle the
532 "signal" and then go to sleep again. Mostly this is done by letting
533 the syscall complete and be restarted. We are not idempotent and
534 can not do this. A better solution is necessary.
538 psig_omask = td->td_sigmask;
540 error = msleep(&vmp->vm_sleep, &p->p_mtx,
541 (coda_call_sleep|coda_pcatch), "coda_call",
545 else if (error == EWOULDBLOCK) {
547 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
551 SIGEMPTYSET(tempset);
552 SIGADDSET(tempset, SIGIO);
553 if (SIGSETEQ(td->td_siglist, tempset)) {
554 SIGADDSET(td->td_sigmask, SIGIO);
556 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n",
560 SIGDELSET(tempset, SIGIO);
561 SIGADDSET(tempset, SIGALRM);
562 if (SIGSETEQ(td->td_siglist, tempset)) {
563 SIGADDSET(td->td_sigmask, SIGALRM);
565 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n",
571 printf("coda_call: tsleep returns %d, cnt %d\n",
576 tempset = td->td_siglist;
577 SIGSETNAND(tempset, td->td_sigmask);
578 printf("coda_call: siglist = %p, sigmask = %p, mask %p\n",
579 td->td_siglist, td->td_sigmask,
582 SIGSETOR(td->td_sigmask, td->td_siglist);
583 tempset = td->td_siglist;
584 SIGSETNAND(tempset, td->td_sigmask);
585 printf("coda_call: new mask, siglist = %p, sigmask = %p, mask %p\n",
586 td->td_siglist, td->td_sigmask,
592 } while (error && i++ < 128 && VC_OPEN(vcp));
593 td->td_sigmask = psig_omask;
597 (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
599 if (VC_OPEN(vcp)) { /* Venus is still alive */
600 /* Op went through, interrupt or not... */
601 if (vmp->vm_flags & VM_WRITE) {
603 *outSize = vmp->vm_outSize;
606 else if (!(vmp->vm_flags & VM_READ)) {
607 /* Interrupted before venus read it. */
613 myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
614 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
615 REMQUE(vmp->vm_chain);
620 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
622 /* Interrupted after start of upcall, send venus a signal */
623 struct coda_in_hdr *dog;
631 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
632 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
634 REMQUE(vmp->vm_chain);
637 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
639 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
640 dog = (struct coda_in_hdr *)svmp->vm_data;
643 dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
644 dog->unique = svmp->vm_unique = vmp->vm_unique;
645 svmp->vm_inSize = sizeof (struct coda_in_hdr);
646 /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
649 myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
650 svmp->vm_opcode, svmp->vm_unique));
652 /* insert at head of queue! */
653 INSQUE(svmp->vm_chain, vcp->vc_requests);
654 selwakeuppri(&(vcp->vc_selproc), coda_call_sleep);
658 else { /* If venus died (!VC_OPEN(vcp)) */
660 myprintf(("vcclose woke op %d.%d flags %d\n",
661 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
666 CODA_FREE(vmp, sizeof(struct vmsg));
668 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
669 wakeup(&outstanding_upcalls);
672 error = ((struct coda_out_hdr *)buffer)->result;