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.3 2003/06/23 17:55:26 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_t dev, int flag, int mode, d_thread_t *td)
121 register struct vcomm *vcp;
125 if (minor(dev) >= NVCODA || minor(dev) < 0)
128 if (!coda_nc_initialized)
131 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
135 bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
136 INIT_QUEUE(vcp->vc_requests);
137 INIT_QUEUE(vcp->vc_replys);
140 coda_mnttbl[minor(dev)].mi_vfsp = NULL;
141 coda_mnttbl[minor(dev)].mi_rootvp = NULL;
147 vc_nb_close (dev_t dev, int flag, int mode, d_thread_t *td)
150 struct vmsg *vmp, *nvmp = NULL;
151 struct coda_mntinfo *mi;
160 if (minor(dev) >= NVCODA || minor(dev) < 0)
163 mi = &coda_mnttbl[minor(dev)];
164 vcp = &(mi->mi_vcomm);
167 panic("vcclose: not open");
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, p);
225 myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
231 vc_nb_read(dev, uiop, flag)
236 register struct vcomm * vcp;
237 register struct vmsg *vmp;
242 if (minor(dev) >= NVCODA || minor(dev) < 0)
245 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
246 /* Get message at head of request queue. */
247 if (EMPTY(vcp->vc_requests))
248 return(0); /* Nothing to read */
250 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
252 /* Move the input args into userspace */
253 uiop->uio_rw = UIO_READ;
254 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
256 myprintf(("vcread: error (%d) on uiomove\n", error));
260 #ifdef OLD_DIAGNOSTIC
261 if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
262 panic("vc_nb_read: bad chain");
265 REMQUE(vmp->vm_chain);
267 /* If request was a signal, free up the message and don't
268 enqueue it in the reply queue. */
269 if (vmp->vm_opcode == CODA_SIGNAL) {
271 myprintf(("vcread: signal msg (%d, %d)\n",
272 vmp->vm_opcode, vmp->vm_unique));
273 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
274 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
278 vmp->vm_flags |= VM_READ;
279 INSQUE(vmp->vm_chain, vcp->vc_replys);
285 vc_nb_write(dev, uiop, flag)
290 register struct vcomm * vcp;
291 register struct vmsg *vmp;
292 struct coda_out_hdr *out;
300 if (minor(dev) >= NVCODA || minor(dev) < 0)
303 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
305 /* Peek at the opcode, unique without transfering the data. */
306 uiop->uio_rw = UIO_WRITE;
307 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
309 myprintf(("vcwrite: error (%d) on uiomove\n", error));
317 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
319 if (DOWNCALL(opcode)) {
320 union outputArgs pbuf;
322 /* get the rest of the data. */
323 uiop->uio_rw = UIO_WRITE;
324 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
326 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
327 error, opcode, seq));
331 return handleDownCall(opcode, &pbuf);
334 /* Look for the message on the (waiting for) reply queue. */
335 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
336 !EOQ(vmp, vcp->vc_replys);
337 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
339 if (vmp->vm_unique == seq) break;
342 if (EOQ(vmp, vcp->vc_replys)) {
344 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
349 /* Remove the message from the reply queue */
350 REMQUE(vmp->vm_chain);
352 /* move data into response buffer. */
353 out = (struct coda_out_hdr *)vmp->vm_data;
354 /* Don't need to copy opcode and uniquifier. */
356 /* get the rest of the data. */
357 if (vmp->vm_outSize < uiop->uio_resid) {
358 myprintf(("vcwrite: more data than asked for (%d < %d)\n",
359 vmp->vm_outSize, uiop->uio_resid));
360 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
364 buf[0] = uiop->uio_resid; /* Save this value. */
365 uiop->uio_rw = UIO_WRITE;
366 error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
368 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
369 error, opcode, seq));
373 /* I don't think these are used, but just in case. */
374 /* XXX - aren't these two already correct? -bnoble */
375 out->opcode = opcode;
377 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
378 vmp->vm_flags |= VM_WRITE;
379 wakeup(&vmp->vm_sleep);
385 vc_nb_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td)
391 struct coda_resize *data = (struct coda_resize *)addr;
392 return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
397 coda_nc_gather_stats();
411 case CIOC_KERNEL_VERSION:
412 switch (*(u_int *)addr) {
414 *(u_int *)addr = coda_kernel_version;
419 if (coda_kernel_version != *(u_int *)addr)
434 vc_nb_poll(dev_t dev, int events, d_thread_t *td)
436 register struct vcomm *vcp;
441 if (minor(dev) >= NVCODA || minor(dev) < 0)
444 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
446 event_msk = events & (POLLIN|POLLRDNORM);
450 if (!EMPTY(vcp->vc_requests))
451 return(events & (POLLIN|POLLRDNORM));
453 selrecord(td, &(vcp->vc_selproc));
461 struct coda_clstat coda_clstat;
464 * Key question: whether to sleep interuptably or uninteruptably when
465 * waiting for Venus. The former seems better (cause you can ^C a
466 * job), but then GNU-EMACS completion breaks. Use tsleep with no
467 * timeout, and no longjmp happens. But, when sleeping
468 * "uninterruptibly", we don't get told if it returns abnormally
473 coda_call(mntinfo, inSize, outSize, buffer)
474 struct coda_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
480 struct proc *p = curproc;
481 sigset_t psig_omask = p->p_sigmask;
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 selwakeup(&(vcp->vc_selproc));
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 error = tsleep(&vmp->vm_sleep,
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(p->p_siglist, tempset)) {
552 SIGADDSET(p->p_sigmask, SIGIO);
554 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n",
558 SIGDELSET(tempset, SIGIO);
559 SIGADDSET(tempset, SIGALRM);
560 if (SIGSETEQ(p->p_siglist, tempset)) {
561 SIGADDSET(p->p_sigmask, SIGALRM);
563 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n",
568 printf("coda_call: tsleep returns %d, cnt %d\n",
572 tempset = p->p_siglist;
573 SIGSETNAND(tempset, p->p_sigmask);
574 printf("coda_call: siglist = %p, sigmask = %p, mask %p\n",
575 p->p_siglist, p->p_sigmask,
578 SIGSETOR(p->p_sigmask, p->p_siglist);
579 tempset = p->p_siglist;
580 SIGSETNAND(tempset, p->p_sigmask);
581 printf("coda_call: new mask, siglist = %p, sigmask = %p, mask %p\n",
582 p->p_siglist, p->p_sigmask,
588 } while (error && i++ < 128 && VC_OPEN(vcp));
589 p->p_sigmask = psig_omask;
591 (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
593 if (VC_OPEN(vcp)) { /* Venus is still alive */
594 /* Op went through, interrupt or not... */
595 if (vmp->vm_flags & VM_WRITE) {
597 *outSize = vmp->vm_outSize;
600 else if (!(vmp->vm_flags & VM_READ)) {
601 /* Interrupted before venus read it. */
607 myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
608 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
609 REMQUE(vmp->vm_chain);
614 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
616 /* Interrupted after start of upcall, send venus a signal */
617 struct coda_in_hdr *dog;
625 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
626 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
628 REMQUE(vmp->vm_chain);
631 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
633 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
634 dog = (struct coda_in_hdr *)svmp->vm_data;
637 dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
638 dog->unique = svmp->vm_unique = vmp->vm_unique;
639 svmp->vm_inSize = sizeof (struct coda_in_hdr);
640 /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
643 myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
644 svmp->vm_opcode, svmp->vm_unique));
646 /* insert at head of queue! */
647 INSQUE(svmp->vm_chain, vcp->vc_requests);
648 selwakeup(&(vcp->vc_selproc));
652 else { /* If venus died (!VC_OPEN(vcp)) */
654 myprintf(("vcclose woke op %d.%d flags %d\n",
655 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
660 CODA_FREE(vmp, sizeof(struct vmsg));
662 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
663 wakeup(&outstanding_upcalls);
666 error = ((struct coda_out_hdr *)buffer)->result;