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.12 2006/07/28 02:17:41 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 */
58 #include "use_vcoda.h"
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/device.h>
64 #include <sys/kernel.h>
66 #include <sys/malloc.h>
67 #include <sys/mount.h>
69 #include <sys/ioccom.h>
74 #include "coda_namecache.h"
76 #include "coda_psdev.h"
81 #include <sys/signalvar.h>
84 int coda_psdev_print_entry = 0;
86 int outstanding_upcalls = 0;
88 int coda_pcatch = PCATCH;
92 #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__))
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 */
118 vc_nb_open(struct dev_open_args *ap)
120 dev_t dev = ap->a_head.a_dev;
126 if (minor(dev) >= NVCODA || minor(dev) < 0)
129 if (!coda_nc_initialized)
132 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
136 bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
137 INIT_QUEUE(vcp->vc_requests);
138 INIT_QUEUE(vcp->vc_replys);
141 coda_mnttbl[minor(dev)].mi_vfsp = NULL;
142 coda_mnttbl[minor(dev)].mi_rootvp = NULL;
148 vc_nb_close (struct dev_close_args *ap)
150 dev_t dev = ap->a_head.a_dev;
152 struct vmsg *vmp, *nvmp = NULL;
153 struct coda_mntinfo *mi;
158 if (minor(dev) >= NVCODA || minor(dev) < 0)
161 mi = &coda_mnttbl[minor(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 tsleep(&outstanding_upcalls, 0, "coda_umount", 0);
215 printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
217 tsleep(&outstanding_upcalls, 0, "coda_umount", 0);
221 err = dounmount(mi->mi_vfsp, ap->a_fflag);
223 myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
229 vc_nb_read(struct dev_read_args *ap)
231 dev_t dev = ap->a_head.a_dev;
238 if (minor(dev) >= NVCODA || minor(dev) < 0)
241 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
242 /* Get message at head of request queue. */
243 if (EMPTY(vcp->vc_requests))
244 return(0); /* Nothing to read */
246 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
248 /* Move the input args into userspace */
249 error = uiomove(vmp->vm_data, vmp->vm_inSize, ap->a_uio);
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(struct dev_write_args *ap)
282 dev_t dev = ap->a_head.a_dev;
283 struct uio *uiop = ap->a_uio;
287 struct coda_out_hdr *out;
295 if (minor(dev) >= NVCODA || minor(dev) < 0)
298 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
300 /* Peek at the opcode, unique without transfering the data. */
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 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
319 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
320 error, opcode, seq));
324 return handleDownCall(opcode, &pbuf);
327 /* Look for the message on the (waiting for) reply queue. */
328 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
329 !EOQ(vmp, vcp->vc_replys);
330 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
332 if (vmp->vm_unique == seq) break;
335 if (EOQ(vmp, vcp->vc_replys)) {
337 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
342 /* Remove the message from the reply queue */
343 REMQUE(vmp->vm_chain);
345 /* move data into response buffer. */
346 out = (struct coda_out_hdr *)vmp->vm_data;
347 /* Don't need to copy opcode and uniquifier. */
349 /* get the rest of the data. */
350 if (vmp->vm_outSize < uiop->uio_resid) {
351 myprintf(("vcwrite: more data than asked for (%d < %d)\n",
352 vmp->vm_outSize, uiop->uio_resid));
353 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
357 buf[0] = uiop->uio_resid; /* Save this value. */
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(struct dev_ioctl_args *ap)
383 struct coda_resize *data = (struct coda_resize *)ap->a_data;
384 return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
389 coda_nc_gather_stats();
403 case CIOC_KERNEL_VERSION:
404 switch (*(u_int *)ap->a_data) {
406 *(u_int *)ap->a_data = coda_kernel_version;
411 if (coda_kernel_version != *(u_int *)ap->a_data)
426 vc_nb_poll(struct dev_poll_args *ap)
428 dev_t dev = ap->a_head.a_dev;
434 if (minor(dev) >= NVCODA || minor(dev) < 0)
437 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
439 event_msk = ap->a_events & (POLLIN|POLLRDNORM);
441 if (!EMPTY(vcp->vc_requests)) {
442 ap->a_events &= (POLLIN|POLLRDNORM);
445 selrecord(curthread, &(vcp->vc_selproc));
454 struct coda_clstat coda_clstat;
457 * Key question: whether to sleep interuptably or uninteruptably when
458 * waiting for Venus. The former seems better (cause you can ^C a
459 * job), but then GNU-EMACS completion breaks. Use tsleep with no
460 * timeout, and no longjmp happens. But, when sleeping
461 * "uninterruptibly", we don't get told if it returns abnormally
466 coda_call(struct coda_mntinfo *mntinfo, int inSize, int *outSize,
473 struct proc *p = curproc;
474 sigset_t psig_omask = p->p_sigmask;
478 if (mntinfo == NULL) {
479 /* Unlikely, but could be a race condition with a dying warden */
483 vcp = &(mntinfo->mi_vcomm);
485 coda_clstat.ncalls++;
486 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
491 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
492 /* Format the request message. */
493 vmp->vm_data = buffer;
495 vmp->vm_inSize = inSize;
497 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
498 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
499 vmp->vm_unique = ++vcp->vc_seq;
501 myprintf(("Doing a call for %d.%d\n",
502 vmp->vm_opcode, vmp->vm_unique));
504 /* Fill in the common input args. */
505 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
507 /* Append msg to request queue and poke Venus. */
508 INSQUE(vmp->vm_chain, vcp->vc_requests);
509 selwakeup(&(vcp->vc_selproc));
511 /* We can be interrupted while we wait for Venus to process
512 * our request. If the interrupt occurs before Venus has read
513 * the request, we dequeue and return. If it occurs after the
514 * read but before the reply, we dequeue, send a signal
515 * message, and return. If it occurs after the reply we ignore
516 * it. In no case do we want to restart the syscall. If it
517 * was interrupted by a venus shutdown (vcclose), return
520 /* Ignore return, We have to check anyway */
522 /* This is work in progress. Setting coda_pcatch lets tsleep reawaken
523 on a ^c or ^z. The problem is that emacs sets certain interrupts
524 as SA_RESTART. This means that we should exit sleep handle the
525 "signal" and then go to sleep again. Mostly this is done by letting
526 the syscall complete and be restarted. We are not idempotent and
527 can not do this. A better solution is necessary.
531 error = tsleep(&vmp->vm_sleep, coda_pcatch, "coda_call", hz*2);
534 else if (error == EWOULDBLOCK) {
536 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
540 SIGEMPTYSET(tempset);
541 SIGADDSET(tempset, SIGIO);
542 if (SIGSETEQ(p->p_siglist, tempset)) {
543 SIGADDSET(p->p_sigmask, SIGIO);
545 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n",
549 SIGDELSET(tempset, SIGIO);
550 SIGADDSET(tempset, SIGALRM);
551 if (SIGSETEQ(p->p_siglist, tempset)) {
552 SIGADDSET(p->p_sigmask, SIGALRM);
554 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n",
559 printf("coda_call: tsleep returns %d, cnt %d\n",
563 tempset = p->p_siglist;
564 SIGSETNAND(tempset, p->p_sigmask);
565 printf("coda_call: siglist = %p, sigmask = %p, mask %p\n",
566 p->p_siglist, p->p_sigmask,
569 SIGSETOR(p->p_sigmask, p->p_siglist);
570 tempset = p->p_siglist;
571 SIGSETNAND(tempset, p->p_sigmask);
572 printf("coda_call: new mask, siglist = %p, sigmask = %p, mask %p\n",
573 p->p_siglist, p->p_sigmask,
579 } while (error && i++ < 128 && VC_OPEN(vcp));
580 p->p_sigmask = psig_omask;
582 tsleep(&vmp->vm_sleep, 0, "coda_call", 0);
584 if (VC_OPEN(vcp)) { /* Venus is still alive */
585 /* Op went through, interrupt or not... */
586 if (vmp->vm_flags & VM_WRITE) {
588 *outSize = vmp->vm_outSize;
591 else if (!(vmp->vm_flags & VM_READ)) {
592 /* Interrupted before venus read it. */
598 myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
599 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
600 REMQUE(vmp->vm_chain);
605 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
607 /* Interrupted after start of upcall, send venus a signal */
608 struct coda_in_hdr *dog;
616 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
617 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
619 REMQUE(vmp->vm_chain);
622 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
624 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
625 dog = (struct coda_in_hdr *)svmp->vm_data;
628 dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
629 dog->unique = svmp->vm_unique = vmp->vm_unique;
630 svmp->vm_inSize = sizeof (struct coda_in_hdr);
631 /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
634 myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
635 svmp->vm_opcode, svmp->vm_unique));
637 /* insert at head of queue! */
638 INSQUE(svmp->vm_chain, vcp->vc_requests);
639 selwakeup(&(vcp->vc_selproc));
643 else { /* If venus died (!VC_OPEN(vcp)) */
645 myprintf(("vcclose woke op %d.%d flags %d\n",
646 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
651 CODA_FREE(vmp, sizeof(struct vmsg));
653 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
654 wakeup(&outstanding_upcalls);
657 error = ((struct coda_out_hdr *)buffer)->result;