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.10 2006/01/13 21:09:27 swildner 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/kernel.h>
64 #include <sys/malloc.h>
65 #include <sys/mount.h>
67 #include <sys/ioccom.h>
73 #include "coda_namecache.h"
75 #include "coda_psdev.h"
80 #include <sys/signalvar.h>
83 int coda_psdev_print_entry = 0;
85 int outstanding_upcalls = 0;
87 int coda_pcatch = PCATCH;
91 #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__))
93 void vcodaattach(int n);
96 struct queue vm_chain;
99 u_short vm_inSize; /* Size is at most 5000 bytes */
101 u_short vm_opcode; /* copied from data to save ptr lookup */
103 caddr_t vm_sleep; /* Not used by Mach. */
110 /* vcodaattach: do nothing */
117 vc_nb_open(dev_t dev, int flag, int mode, d_thread_t *td)
123 if (minor(dev) >= NVCODA || minor(dev) < 0)
126 if (!coda_nc_initialized)
129 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
133 bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
134 INIT_QUEUE(vcp->vc_requests);
135 INIT_QUEUE(vcp->vc_replys);
138 coda_mnttbl[minor(dev)].mi_vfsp = NULL;
139 coda_mnttbl[minor(dev)].mi_rootvp = NULL;
145 vc_nb_close (dev_t dev, int flag, int mode, d_thread_t *td)
148 struct vmsg *vmp, *nvmp = NULL;
149 struct coda_mntinfo *mi;
154 if (minor(dev) >= NVCODA || minor(dev) < 0)
157 mi = &coda_mnttbl[minor(dev)];
158 vcp = &(mi->mi_vcomm);
161 panic("vcclose: not open");
163 /* prevent future operations on this vfs from succeeding by auto-
164 * unmounting any vfs mounted via this device. This frees user or
165 * sysadm from having to remember where all mount points are located.
166 * Put this before WAKEUPs to avoid queuing new messages between
167 * the WAKEUP and the unmount (which can happen if we're unlucky)
169 if (!mi->mi_rootvp) {
170 /* just a simple open/close w no mount */
175 /* Let unmount know this is for real */
176 VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
177 coda_unmounting(mi->mi_vfsp);
179 outstanding_upcalls = 0;
180 /* Wakeup clients so they can return. */
181 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
182 !EOQ(vmp, vcp->vc_requests);
185 nvmp = (struct vmsg *)GETNEXT(vmp->vm_chain);
186 /* Free signal request messages and don't wakeup cause
187 no one is waiting. */
188 if (vmp->vm_opcode == CODA_SIGNAL) {
189 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
190 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
193 outstanding_upcalls++;
194 wakeup(&vmp->vm_sleep);
197 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
198 !EOQ(vmp, vcp->vc_replys);
199 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
201 outstanding_upcalls++;
202 wakeup(&vmp->vm_sleep);
207 if (outstanding_upcalls) {
209 printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
210 tsleep(&outstanding_upcalls, 0, "coda_umount", 0);
211 printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
213 tsleep(&outstanding_upcalls, 0, "coda_umount", 0);
217 err = dounmount(mi->mi_vfsp, flag, td);
219 myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
225 vc_nb_read(dev_t dev, struct uio *uiop, int flag)
233 if (minor(dev) >= NVCODA || minor(dev) < 0)
236 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
237 /* Get message at head of request queue. */
238 if (EMPTY(vcp->vc_requests))
239 return(0); /* Nothing to read */
241 vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
243 /* Move the input args into userspace */
244 uiop->uio_rw = UIO_READ;
245 error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
247 myprintf(("vcread: error (%d) on uiomove\n", error));
251 #ifdef OLD_DIAGNOSTIC
252 if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
253 panic("vc_nb_read: bad chain");
256 REMQUE(vmp->vm_chain);
258 /* If request was a signal, free up the message and don't
259 enqueue it in the reply queue. */
260 if (vmp->vm_opcode == CODA_SIGNAL) {
262 myprintf(("vcread: signal msg (%d, %d)\n",
263 vmp->vm_opcode, vmp->vm_unique));
264 CODA_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
265 CODA_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
269 vmp->vm_flags |= VM_READ;
270 INSQUE(vmp->vm_chain, vcp->vc_replys);
276 vc_nb_write(dev_t dev, struct uio *uiop, int flag)
280 struct coda_out_hdr *out;
288 if (minor(dev) >= NVCODA || minor(dev) < 0)
291 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
293 /* Peek at the opcode, unique without transfering the data. */
294 uiop->uio_rw = UIO_WRITE;
295 error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
297 myprintf(("vcwrite: error (%d) on uiomove\n", error));
305 myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
307 if (DOWNCALL(opcode)) {
308 union outputArgs pbuf;
310 /* get the rest of the data. */
311 uiop->uio_rw = UIO_WRITE;
312 error = uiomove((caddr_t)&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
314 myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
315 error, opcode, seq));
319 return handleDownCall(opcode, &pbuf);
322 /* Look for the message on the (waiting for) reply queue. */
323 for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
324 !EOQ(vmp, vcp->vc_replys);
325 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
327 if (vmp->vm_unique == seq) break;
330 if (EOQ(vmp, vcp->vc_replys)) {
332 myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
337 /* Remove the message from the reply queue */
338 REMQUE(vmp->vm_chain);
340 /* move data into response buffer. */
341 out = (struct coda_out_hdr *)vmp->vm_data;
342 /* Don't need to copy opcode and uniquifier. */
344 /* get the rest of the data. */
345 if (vmp->vm_outSize < uiop->uio_resid) {
346 myprintf(("vcwrite: more data than asked for (%d < %d)\n",
347 vmp->vm_outSize, uiop->uio_resid));
348 wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
352 buf[0] = uiop->uio_resid; /* Save this value. */
353 uiop->uio_rw = UIO_WRITE;
354 error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
356 myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
357 error, opcode, seq));
361 /* I don't think these are used, but just in case. */
362 /* XXX - aren't these two already correct? -bnoble */
363 out->opcode = opcode;
365 vmp->vm_outSize = buf[0]; /* Amount of data transferred? */
366 vmp->vm_flags |= VM_WRITE;
367 wakeup(&vmp->vm_sleep);
373 vc_nb_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td)
379 struct coda_resize *data = (struct coda_resize *)addr;
380 return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
385 coda_nc_gather_stats();
399 case CIOC_KERNEL_VERSION:
400 switch (*(u_int *)addr) {
402 *(u_int *)addr = coda_kernel_version;
407 if (coda_kernel_version != *(u_int *)addr)
422 vc_nb_poll(dev_t dev, int events, d_thread_t *td)
429 if (minor(dev) >= NVCODA || minor(dev) < 0)
432 vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
434 event_msk = events & (POLLIN|POLLRDNORM);
438 if (!EMPTY(vcp->vc_requests))
439 return(events & (POLLIN|POLLRDNORM));
441 selrecord(td, &(vcp->vc_selproc));
449 struct coda_clstat coda_clstat;
452 * Key question: whether to sleep interuptably or uninteruptably when
453 * waiting for Venus. The former seems better (cause you can ^C a
454 * job), but then GNU-EMACS completion breaks. Use tsleep with no
455 * timeout, and no longjmp happens. But, when sleeping
456 * "uninterruptibly", we don't get told if it returns abnormally
461 coda_call(struct coda_mntinfo *mntinfo, int inSize, int *outSize,
468 struct proc *p = curproc;
469 sigset_t psig_omask = p->p_sigmask;
473 if (mntinfo == NULL) {
474 /* Unlikely, but could be a race condition with a dying warden */
478 vcp = &(mntinfo->mi_vcomm);
480 coda_clstat.ncalls++;
481 coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
486 CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
487 /* Format the request message. */
488 vmp->vm_data = buffer;
490 vmp->vm_inSize = inSize;
492 = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
493 vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
494 vmp->vm_unique = ++vcp->vc_seq;
496 myprintf(("Doing a call for %d.%d\n",
497 vmp->vm_opcode, vmp->vm_unique));
499 /* Fill in the common input args. */
500 ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
502 /* Append msg to request queue and poke Venus. */
503 INSQUE(vmp->vm_chain, vcp->vc_requests);
504 selwakeup(&(vcp->vc_selproc));
506 /* We can be interrupted while we wait for Venus to process
507 * our request. If the interrupt occurs before Venus has read
508 * the request, we dequeue and return. If it occurs after the
509 * read but before the reply, we dequeue, send a signal
510 * message, and return. If it occurs after the reply we ignore
511 * it. In no case do we want to restart the syscall. If it
512 * was interrupted by a venus shutdown (vcclose), return
515 /* Ignore return, We have to check anyway */
517 /* This is work in progress. Setting coda_pcatch lets tsleep reawaken
518 on a ^c or ^z. The problem is that emacs sets certain interrupts
519 as SA_RESTART. This means that we should exit sleep handle the
520 "signal" and then go to sleep again. Mostly this is done by letting
521 the syscall complete and be restarted. We are not idempotent and
522 can not do this. A better solution is necessary.
526 error = tsleep(&vmp->vm_sleep, coda_pcatch, "coda_call", hz*2);
529 else if (error == EWOULDBLOCK) {
531 printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
535 SIGEMPTYSET(tempset);
536 SIGADDSET(tempset, SIGIO);
537 if (SIGSETEQ(p->p_siglist, tempset)) {
538 SIGADDSET(p->p_sigmask, SIGIO);
540 printf("coda_call: tsleep returns %d SIGIO, cnt %d\n",
544 SIGDELSET(tempset, SIGIO);
545 SIGADDSET(tempset, SIGALRM);
546 if (SIGSETEQ(p->p_siglist, tempset)) {
547 SIGADDSET(p->p_sigmask, SIGALRM);
549 printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n",
554 printf("coda_call: tsleep returns %d, cnt %d\n",
558 tempset = p->p_siglist;
559 SIGSETNAND(tempset, p->p_sigmask);
560 printf("coda_call: siglist = %p, sigmask = %p, mask %p\n",
561 p->p_siglist, p->p_sigmask,
564 SIGSETOR(p->p_sigmask, p->p_siglist);
565 tempset = p->p_siglist;
566 SIGSETNAND(tempset, p->p_sigmask);
567 printf("coda_call: new mask, siglist = %p, sigmask = %p, mask %p\n",
568 p->p_siglist, p->p_sigmask,
574 } while (error && i++ < 128 && VC_OPEN(vcp));
575 p->p_sigmask = psig_omask;
577 tsleep(&vmp->vm_sleep, 0, "coda_call", 0);
579 if (VC_OPEN(vcp)) { /* Venus is still alive */
580 /* Op went through, interrupt or not... */
581 if (vmp->vm_flags & VM_WRITE) {
583 *outSize = vmp->vm_outSize;
586 else if (!(vmp->vm_flags & VM_READ)) {
587 /* Interrupted before venus read it. */
593 myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
594 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
595 REMQUE(vmp->vm_chain);
600 /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
602 /* Interrupted after start of upcall, send venus a signal */
603 struct coda_in_hdr *dog;
611 myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
612 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
614 REMQUE(vmp->vm_chain);
617 CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
619 CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
620 dog = (struct coda_in_hdr *)svmp->vm_data;
623 dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
624 dog->unique = svmp->vm_unique = vmp->vm_unique;
625 svmp->vm_inSize = sizeof (struct coda_in_hdr);
626 /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
629 myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
630 svmp->vm_opcode, svmp->vm_unique));
632 /* insert at head of queue! */
633 INSQUE(svmp->vm_chain, vcp->vc_requests);
634 selwakeup(&(vcp->vc_selproc));
638 else { /* If venus died (!VC_OPEN(vcp)) */
640 myprintf(("vcclose woke op %d.%d flags %d\n",
641 vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
646 CODA_FREE(vmp, sizeof(struct vmsg));
648 if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
649 wakeup(&outstanding_upcalls);
652 error = ((struct coda_out_hdr *)buffer)->result;