Home | History | Annotate | Line # | Download | only in coda
coda_psdev.c revision 1.1
      1 /*
      2 
      3             Coda: an Experimental Distributed File System
      4                              Release 3.1
      5 
      6           Copyright (c) 1987-1998 Carnegie Mellon University
      7                          All Rights Reserved
      8 
      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
     16 derivatives.
     17 
     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.
     24 
     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.
     28 */
     29 
     30 /* $Header: /tank/opengrok/rsync2/NetBSD/src/sys/coda/coda_psdev.c,v 1.1 1998/08/29 21:26:45 rvb Exp $ */
     31 
     32 #define CTL_C
     33 
     34 /*
     35  * Mach Operating System
     36  * Copyright (c) 1989 Carnegie-Mellon University
     37  * All rights reserved.  The CMU software License Agreement specifies
     38  * the terms and conditions for use and redistribution.
     39  */
     40 
     41 /*
     42  * This code was written for the Coda file system at Carnegie Mellon
     43  * University.  Contributers include David Steere, James Kistler, and
     44  * M. Satyanarayanan.  */
     45 
     46 /* ************************************************** */
     47 /* These routines define the psuedo device for communication between
     48  * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
     49  * but I moved them to make it easier to port the Minicache without
     50  * porting coda. -- DCS 10/12/94
     51  */
     52 
     53 /*
     54  * Renamed to cfs_psdev: pseudo-device driver.
     55  */
     56 
     57 /*
     58  * HISTORY
     59  * $Log: coda_psdev.c,v $
     60  * Revision 1.1  1998/08/29 21:26:45  rvb
     61  * Initial revision
     62  *
     63  * Revision 1.9  1998/08/28 18:12:17  rvb
     64  * Now it also works on FreeBSD -current.  This code will be
     65  * committed to the FreeBSD -current and NetBSD -current
     66  * trees.  It will then be tailored to the particular platform
     67  * by flushing conditional code.
     68  *
     69  * Revision 1.8  1998/08/18 17:05:15  rvb
     70  * Don't use __RCSID now
     71  *
     72  * Revision 1.7  1998/08/18 16:31:41  rvb
     73  * Sync the code for NetBSD -current; test on 1.3 later
     74  *
     75  * Revision 1.8  1998/06/09 23:30:42  rvb
     76  * Try to allow ^C -- take 1
     77  *
     78  * Revision 1.5.2.8  98/01/23  11:21:04  rvb
     79  * Sync with 2.2.5
     80  *
     81  * Revision 1.5.2.7  98/01/22  22:22:21  rvb
     82  * sync 1.2 and 1.3
     83  *
     84  * Revision 1.5.2.6  98/01/22  13:11:24  rvb
     85  * Move makecfsnode ctlfid later so vfsp is known; work on ^c and ^z
     86  *
     87  * Revision 1.5.2.5  97/12/16  22:01:27  rvb
     88  * Oops add cfs_subr.h cfs_venus.h; sync with peter
     89  *
     90  * Revision 1.5.2.4  97/12/16  12:40:05  rvb
     91  * Sync with 1.3
     92  *
     93  * Revision 1.5.2.3  97/12/10  14:08:24  rvb
     94  * Fix O_ flags; check result in cfscall
     95  *
     96  * Revision 1.5.2.2  97/12/10  11:40:24  rvb
     97  * No more ody
     98  *
     99  * Revision 1.5.2.1  97/12/06  17:41:20  rvb
    100  * Sync with peters coda.h
    101  *
    102  * Revision 1.5  97/12/05  10:39:16  rvb
    103  * Read CHANGES
    104  *
    105  * Revision 1.4.18.9  97/12/05  08:58:07  rvb
    106  * peter found this one
    107  *
    108  * Revision 1.4.18.8  97/11/26  15:28:57  rvb
    109  * Cant make downcall pbuf == union cfs_downcalls yet
    110  *
    111  * Revision 1.4.18.7  97/11/25  09:40:49  rvb
    112  * Final cfs_venus.c w/o macros, but one locking bug
    113  *
    114  * Revision 1.4.18.6  97/11/20  11:46:41  rvb
    115  * Capture current cfs_venus
    116  *
    117  * Revision 1.4.18.5  97/11/18  10:27:15  rvb
    118  * cfs_nbsd.c is DEAD!!!; integrated into cfs_vf/vnops.c
    119  * cfs_nb_foo and cfs_foo are joined
    120  *
    121  * Revision 1.4.18.4  97/11/13  22:02:59  rvb
    122  * pass2 cfs_NetBSD.h mt
    123  *
    124  * Revision 1.4.18.3  97/11/12  12:09:38  rvb
    125  * reorg pass1
    126  *
    127  * Revision 1.4.18.2  97/10/29  16:06:09  rvb
    128  * Kill DYING
    129  *
    130  * Revision 1.4.18.1  1997/10/28 23:10:15  rvb
    131  * >64Meg; venus can be killed!
    132  *
    133  * Revision 1.4  1996/12/12 22:10:58  bnoble
    134  * Fixed the "downcall invokes venus operation" deadlock in all known cases.
    135  * There may be more
    136  *
    137  * Revision 1.3  1996/11/13 04:14:20  bnoble
    138  * Merging BNOBLE_WORK_6_20_96 into main line
    139  *
    140  * Revision 1.2.8.1  1996/08/22 14:25:04  bnoble
    141  * Added a return code from vc_nb_close
    142  *
    143  * Revision 1.2  1996/01/02 16:56:58  bnoble
    144  * Added support for Coda MiniCache and raw inode calls (final commit)
    145  *
    146  * Revision 1.1.2.1  1995/12/20 01:57:24  bnoble
    147  * Added CFS-specific files
    148  *
    149  * Revision 1.1  1995/03/14  20:52:15  bnoble
    150  * Initial revision
    151  *
    152  */
    153 
    154 /* These routines are the device entry points for Venus. */
    155 
    156 extern int cfsnc_initialized;    /* Set if cache has been initialized */
    157 
    158 #include <vcfs.h>
    159 #include <sys/param.h>
    160 #include <sys/systm.h>
    161 #include <sys/kernel.h>
    162 #include <sys/malloc.h>
    163 #include <sys/proc.h>
    164 #include <sys/mount.h>
    165 #include <sys/file.h>
    166 #ifdef	__FreeBSD_version
    167 #include <sys/ioccom.h>
    168 #else
    169 #include <sys/ioctl.h>
    170 #endif
    171 #ifdef	NetBSD1_3
    172 #include <sys/poll.h>
    173 #endif
    174 #ifdef	__FreeBSD_version
    175 #include <sys/poll.h>
    176 #else
    177 #include <sys/select.h>
    178 #endif
    179 
    180 #include <cfs/coda.h>
    181 #include <cfs/cnode.h>
    182 #include <cfs/cfsnc.h>
    183 #include <cfs/cfsio.h>
    184 
    185 int cfs_psdev_print_entry = 0;
    186 
    187 #ifdef __GNUC__
    188 #define ENTRY    \
    189     if(cfs_psdev_print_entry) myprintf(("Entered %s\n",__FUNCTION__))
    190 #else
    191 #define ENTRY
    192 #endif
    193 
    194 void vcfsattach(int n);
    195 int vc_nb_open(dev_t dev, int flag, int mode, struct proc *p);
    196 int vc_nb_close (dev_t dev, int flag, int mode, struct proc *p);
    197 int vc_nb_read(dev_t dev, struct uio *uiop, int flag);
    198 int vc_nb_write(dev_t dev, struct uio *uiop, int flag);
    199 int vc_nb_ioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p);
    200 #if	defined(NetBSD1_3) || defined(__FreeBSD_version)
    201 int vc_nb_poll(dev_t dev, int events, struct proc *p);
    202 #else
    203 int vc_nb_select(dev_t dev, int flag, struct proc *p);
    204 #endif
    205 
    206 struct vmsg {
    207     struct queue vm_chain;
    208     caddr_t	 vm_data;
    209     u_short	 vm_flags;
    210     u_short      vm_inSize;	/* Size is at most 5000 bytes */
    211     u_short	 vm_outSize;
    212     u_short	 vm_opcode; 	/* copied from data to save ptr lookup */
    213     int		 vm_unique;
    214     caddr_t	 vm_sleep;	/* Not used by Mach. */
    215 };
    216 
    217 #define	VM_READ	    1
    218 #define	VM_WRITE    2
    219 #define	VM_INTR	    4
    220 
    221 /* vcfsattach: do nothing */
    222 void
    223 vcfsattach(n)
    224     int n;
    225 {
    226 }
    227 
    228 /*
    229  * These functions are written for NetBSD.
    230  */
    231 int
    232 vc_nb_open(dev, flag, mode, p)
    233     dev_t        dev;
    234     int          flag;
    235     int          mode;
    236     struct proc *p;             /* NetBSD only */
    237 {
    238     register struct vcomm *vcp;
    239 
    240     ENTRY;
    241 
    242     if (minor(dev) >= NVCFS || minor(dev) < 0)
    243 	return(ENXIO);
    244 
    245     if (!cfsnc_initialized)
    246 	cfsnc_init();
    247 
    248     vcp = &cfs_mnttbl[minor(dev)].mi_vcomm;
    249     if (VC_OPEN(vcp))
    250 	return(EBUSY);
    251 
    252     bzero(&(vcp->vc_selproc), sizeof (struct selinfo));
    253     INIT_QUEUE(vcp->vc_requests);
    254     INIT_QUEUE(vcp->vc_replys);
    255     MARK_VC_OPEN(vcp);
    256 
    257     cfs_mnttbl[minor(dev)].mi_vfsp = NULL;
    258     cfs_mnttbl[minor(dev)].mi_rootvp = NULL;
    259 
    260     return(0);
    261 }
    262 
    263 int
    264 vc_nb_close (dev, flag, mode, p)
    265     dev_t        dev;
    266     int          flag;
    267     int          mode;
    268     struct proc *p;
    269 {
    270     register struct vcomm *vcp;
    271     register struct vmsg *vmp;
    272     struct cfs_mntinfo *mi;
    273     int                 err;
    274 
    275     ENTRY;
    276 
    277     if (minor(dev) >= NVCFS || minor(dev) < 0)
    278 	return(ENXIO);
    279 
    280     mi = &cfs_mnttbl[minor(dev)];
    281     vcp = &(mi->mi_vcomm);
    282 
    283     if (!VC_OPEN(vcp))
    284 	panic("vcclose: not open");
    285 
    286     /* prevent future operations on this vfs from succeeding by auto-
    287      * unmounting any vfs mounted via this device. This frees user or
    288      * sysadm from having to remember where all mount points are located.
    289      * Put this before WAKEUPs to avoid queuing new messages between
    290      * the WAKEUP and the unmount (which can happen if we're unlucky)
    291      */
    292     if (mi->mi_rootvp) {
    293 	/* Let unmount know this is for real */
    294 	VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
    295 #ifdef	NEW_LOCKMGR
    296 #ifdef	__FreeBSD_version
    297 	/* dounmount is different ... probably wrong ... */
    298 #else
    299 	if (vfs_busy(mi->mi_vfsp, 0, 0))
    300 	    return (EBUSY);
    301 #endif
    302 #endif
    303 	cfs_unmounting(mi->mi_vfsp);
    304 	err = dounmount(mi->mi_vfsp, flag, p);
    305 	if (err)
    306 	    myprintf(("Error %d unmounting vfs in vcclose(%d)\n",
    307 		      err, minor(dev)));
    308     }
    309 
    310     /* Wakeup clients so they can return. */
    311     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
    312 	 !EOQ(vmp, vcp->vc_requests);
    313 	 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
    314     {
    315 	/* Free signal request messages and don't wakeup cause
    316 	   no one is waiting. */
    317 	if (vmp->vm_opcode == CFS_SIGNAL) {
    318 	    CFS_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
    319 	    CFS_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
    320 	    continue;
    321 	}
    322 
    323 	wakeup(&vmp->vm_sleep);
    324     }
    325 
    326     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
    327 	 !EOQ(vmp, vcp->vc_replys);
    328 	 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
    329     {
    330 	wakeup(&vmp->vm_sleep);
    331     }
    332 
    333     MARK_VC_CLOSED(vcp);
    334     return 0;
    335 }
    336 
    337 int
    338 vc_nb_read(dev, uiop, flag)
    339     dev_t        dev;
    340     struct uio  *uiop;
    341     int          flag;
    342 {
    343     register struct vcomm *	vcp;
    344     register struct vmsg *vmp;
    345     int error = 0;
    346 
    347     ENTRY;
    348 
    349     if (minor(dev) >= NVCFS || minor(dev) < 0)
    350 	return(ENXIO);
    351 
    352     vcp = &cfs_mnttbl[minor(dev)].mi_vcomm;
    353     /* Get message at head of request queue. */
    354     if (EMPTY(vcp->vc_requests))
    355 	return(0);	/* Nothing to read */
    356 
    357     vmp = (struct vmsg *)GETNEXT(vcp->vc_requests);
    358 
    359     /* Move the input args into userspace */
    360     uiop->uio_rw = UIO_READ;
    361     error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
    362     if (error) {
    363 	myprintf(("vcread: error (%d) on uiomove\n", error));
    364 	error = EINVAL;
    365     }
    366 
    367 #ifdef DIAGNOSTIC
    368     if (vmp->vm_chain.forw == 0 || vmp->vm_chain.back == 0)
    369 	panic("vc_nb_read: bad chain");
    370 #endif
    371 
    372     REMQUE(vmp->vm_chain);
    373 
    374     /* If request was a signal, free up the message and don't
    375        enqueue it in the reply queue. */
    376     if (vmp->vm_opcode == CFS_SIGNAL) {
    377 	if (cfsdebug)
    378 	    myprintf(("vcread: signal msg (%d, %d)\n",
    379 		      vmp->vm_opcode, vmp->vm_unique));
    380 	CFS_FREE((caddr_t)vmp->vm_data, (u_int)VC_IN_NO_DATA);
    381 	CFS_FREE((caddr_t)vmp, (u_int)sizeof(struct vmsg));
    382 	return(error);
    383     }
    384 
    385     vmp->vm_flags |= VM_READ;
    386     INSQUE(vmp->vm_chain, vcp->vc_replys);
    387 
    388     return(error);
    389 }
    390 
    391 int
    392 vc_nb_write(dev, uiop, flag)
    393     dev_t        dev;
    394     struct uio  *uiop;
    395     int          flag;
    396 {
    397     register struct vcomm *	vcp;
    398     register struct vmsg *vmp;
    399     struct cfs_out_hdr *out;
    400     u_long seq;
    401     u_long opcode;
    402     int buf[2];
    403     int error = 0;
    404 
    405     ENTRY;
    406 
    407     if (minor(dev) >= NVCFS || minor(dev) < 0)
    408 	return(ENXIO);
    409 
    410     vcp = &cfs_mnttbl[minor(dev)].mi_vcomm;
    411 
    412     /* Peek at the opcode, unique without transfering the data. */
    413     uiop->uio_rw = UIO_WRITE;
    414     error = uiomove((caddr_t)buf, sizeof(int) * 2, uiop);
    415     if (error) {
    416 	myprintf(("vcwrite: error (%d) on uiomove\n", error));
    417 	return(EINVAL);
    418     }
    419 
    420     opcode = buf[0];
    421     seq = buf[1];
    422 
    423     if (cfsdebug)
    424 	myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
    425 
    426     if (DOWNCALL(opcode)) {
    427 	union outputArgs pbuf;
    428 
    429 	/* get the rest of the data. */
    430 	uiop->uio_rw = UIO_WRITE;
    431 	error = uiomove((caddr_t)&pbuf.cfs_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
    432 	if (error) {
    433 	    myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
    434 		      error, opcode, seq));
    435 	    return(EINVAL);
    436 	    }
    437 
    438 	return handleDownCall(opcode, &pbuf);
    439     }
    440 
    441     /* Look for the message on the (waiting for) reply queue. */
    442     for (vmp = (struct vmsg *)GETNEXT(vcp->vc_replys);
    443 	 !EOQ(vmp, vcp->vc_replys);
    444 	 vmp = (struct vmsg *)GETNEXT(vmp->vm_chain))
    445     {
    446 	if (vmp->vm_unique == seq) break;
    447     }
    448 
    449     if (EOQ(vmp, vcp->vc_replys)) {
    450 	if (cfsdebug)
    451 	    myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
    452 
    453 	return(ESRCH);
    454 	}
    455 
    456     /* Remove the message from the reply queue */
    457     REMQUE(vmp->vm_chain);
    458 
    459     /* move data into response buffer. */
    460     out = (struct cfs_out_hdr *)vmp->vm_data;
    461     /* Don't need to copy opcode and uniquifier. */
    462 
    463     /* get the rest of the data. */
    464     if (vmp->vm_outSize < uiop->uio_resid) {
    465 	myprintf(("vcwrite: more data than asked for (%d < %d)\n",
    466 		  vmp->vm_outSize, uiop->uio_resid));
    467 	wakeup(&vmp->vm_sleep); 	/* Notify caller of the error. */
    468 	return(EINVAL);
    469     }
    470 
    471     buf[0] = uiop->uio_resid; 	/* Save this value. */
    472     uiop->uio_rw = UIO_WRITE;
    473     error = uiomove((caddr_t) &out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
    474     if (error) {
    475 	myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
    476 		  error, opcode, seq));
    477 	return(EINVAL);
    478     }
    479 
    480     /* I don't think these are used, but just in case. */
    481     /* XXX - aren't these two already correct? -bnoble */
    482     out->opcode = opcode;
    483     out->unique = seq;
    484     vmp->vm_outSize	= buf[0];	/* Amount of data transferred? */
    485     vmp->vm_flags |= VM_WRITE;
    486     wakeup(&vmp->vm_sleep);
    487 
    488     return(0);
    489 }
    490 
    491 int
    492 vc_nb_ioctl(dev, cmd, addr, flag, p)
    493     dev_t         dev;
    494     int           cmd;
    495     caddr_t       addr;
    496     int           flag;
    497     struct proc  *p;
    498 {
    499     ENTRY;
    500 
    501     switch(cmd) {
    502     case CFSRESIZE: {
    503 	struct cfs_resize *data = (struct cfs_resize *)addr;
    504 	return(cfsnc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
    505 	break;
    506     }
    507     case CFSSTATS:
    508 	if (cfsnc_use) {
    509 	    cfsnc_gather_stats();
    510 	    return(0);
    511 	} else {
    512 	    return(ENODEV);
    513 	}
    514 	break;
    515     case CFSPRINT:
    516 	if (cfsnc_use) {
    517 	    print_cfsnc();
    518 	    return(0);
    519 	} else {
    520 	    return(ENODEV);
    521 	}
    522 	break;
    523     default :
    524 	return(EINVAL);
    525 	break;
    526     }
    527 }
    528 
    529 #if	defined(NetBSD1_3) || defined(__FreeBSD_version)
    530 int
    531 vc_nb_poll(dev, events, p)
    532     dev_t         dev;
    533     int           events;
    534     struct proc  *p;
    535 {
    536     register struct vcomm *vcp;
    537     int event_msk = 0;
    538 
    539     ENTRY;
    540 
    541     if (minor(dev) >= NVCFS || minor(dev) < 0)
    542 	return(ENXIO);
    543 
    544     vcp = &cfs_mnttbl[minor(dev)].mi_vcomm;
    545 
    546     event_msk = events & (POLLIN|POLLRDNORM);
    547     if (!event_msk)
    548 	return(0);
    549 
    550     if (!EMPTY(vcp->vc_requests))
    551 	return(events & (POLLIN|POLLRDNORM));
    552 
    553     selrecord(p, &(vcp->vc_selproc));
    554 
    555     return(0);
    556 }
    557 #else
    558 int
    559 vc_nb_select(dev, flag, p)
    560     dev_t         dev;
    561     int           flag;
    562     struct proc  *p;
    563 {
    564     register struct vcomm *vcp;
    565 
    566     ENTRY;
    567 
    568     if (minor(dev) >= NVCFS || minor(dev) < 0)
    569 	return(ENXIO);
    570 
    571     vcp = &cfs_mnttbl[minor(dev)].mi_vcomm;
    572 
    573     if (flag != FREAD)
    574 	return(0);
    575 
    576     if (!EMPTY(vcp->vc_requests))
    577 	return(1);
    578 
    579     selrecord(p, &(vcp->vc_selproc));
    580 
    581     return(0);
    582 }
    583 #endif
    584 
    585 /*
    586  * Statistics
    587  */
    588 struct cfs_clstat cfs_clstat;
    589 
    590 /*
    591  * Key question: whether to sleep interuptably or uninteruptably when
    592  * waiting for Venus.  The former seems better (cause you can ^C a
    593  * job), but then GNU-EMACS completion breaks. Use tsleep with no
    594  * timeout, and no longjmp happens. But, when sleeping
    595  * "uninterruptibly", we don't get told if it returns abnormally
    596  * (e.g. kill -9).
    597  */
    598 
    599 /* If you want this to be interruptible, set this to > PZERO */
    600 int cfscall_sleep = PZERO - 1;
    601 #ifdef	CTL_C
    602 int cfs_pcatch = PCATCH;
    603 #else
    604 #endif
    605 
    606 int
    607 cfscall(mntinfo, inSize, outSize, buffer)
    608      struct cfs_mntinfo *mntinfo; int inSize; int *outSize; caddr_t buffer;
    609 {
    610 	struct vcomm *vcp;
    611 	struct vmsg *vmp;
    612 	int error;
    613 #ifdef	CTL_C
    614 	struct proc *p = curproc;
    615 	unsigned int psig_omask = p->p_sigmask;
    616 	int i;
    617 #endif
    618 	if (mntinfo == NULL) {
    619 	    /* Unlikely, but could be a race condition with a dying warden */
    620 	    return ENODEV;
    621 	}
    622 
    623 	vcp = &(mntinfo->mi_vcomm);
    624 
    625 	cfs_clstat.ncalls++;
    626 	cfs_clstat.reqs[((struct cfs_in_hdr *)buffer)->opcode]++;
    627 
    628 	if (!VC_OPEN(vcp))
    629 	    return(ENODEV);
    630 
    631 	CFS_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
    632 	/* Format the request message. */
    633 	vmp->vm_data = buffer;
    634 	vmp->vm_flags = 0;
    635 	vmp->vm_inSize = inSize;
    636 	vmp->vm_outSize
    637 	    = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
    638 	vmp->vm_opcode = ((struct cfs_in_hdr *)buffer)->opcode;
    639 	vmp->vm_unique = ++vcp->vc_seq;
    640 	if (cfsdebug)
    641 	    myprintf(("Doing a call for %d.%d\n",
    642 		      vmp->vm_opcode, vmp->vm_unique));
    643 
    644 	/* Fill in the common input args. */
    645 	((struct cfs_in_hdr *)buffer)->unique = vmp->vm_unique;
    646 
    647 	/* Append msg to request queue and poke Venus. */
    648 	INSQUE(vmp->vm_chain, vcp->vc_requests);
    649 	selwakeup(&(vcp->vc_selproc));
    650 
    651 	/* We can be interrupted while we wait for Venus to process
    652 	 * our request.  If the interrupt occurs before Venus has read
    653 	 * the request, we dequeue and return. If it occurs after the
    654 	 * read but before the reply, we dequeue, send a signal
    655 	 * message, and return. If it occurs after the reply we ignore
    656 	 * it. In no case do we want to restart the syscall.  If it
    657 	 * was interrupted by a venus shutdown (vcclose), return
    658 	 * ENODEV.  */
    659 
    660 	/* Ignore return, We have to check anyway */
    661 #ifdef	CTL_C
    662 	/* This is work in progress.  Setting cfs_pcatch lets tsleep reawaken
    663 	   on a ^c or ^z.  The problem is that emacs sets certain interrupts
    664 	   as SA_RESTART.  This means that we should exit sleep handle the
    665 	   "signal" and then go to sleep again.  Mostly this is done by letting
    666 	   the syscall complete and be restarted.  We are not idempotent and
    667 	   can not do this.  A better solution is necessary.
    668 	 */
    669 	i = 0;
    670 	do {
    671 	    error = tsleep(&vmp->vm_sleep, (cfscall_sleep|cfs_pcatch), "cfscall", hz*2);
    672 	    if (error == 0)
    673 	    	break;
    674 	    else if (error == EWOULDBLOCK) {
    675 		    printf("cfscall: tsleep TIMEOUT %d sec\n", 2+2*i);
    676     	    } else if (p->p_siglist == sigmask(SIGIO)) {
    677 		    p->p_sigmask |= p->p_siglist;
    678 		    printf("cfscall: tsleep returns %d SIGIO, cnt %d\n", error, i);
    679 	    } else {
    680 		    printf("cfscall: tsleep returns %d, cnt %d\n", error, i);
    681 		    printf("cfscall: siglist = %x, sigmask = %x, mask %x\n",
    682 			    p->p_siglist, p->p_sigmask,
    683 			    p->p_siglist & ~p->p_sigmask);
    684 		    break;
    685 		    p->p_sigmask |= p->p_siglist;
    686 		    printf("cfscall: new mask, siglist = %x, sigmask = %x, mask %x\n",
    687 			    p->p_siglist, p->p_sigmask,
    688 			    p->p_siglist & ~p->p_sigmask);
    689 	    }
    690 	} while (error && i++ < 128);
    691 	p->p_sigmask = psig_omask;
    692 #else
    693 	(void) tsleep(&vmp->vm_sleep, cfscall_sleep, "cfscall", 0);
    694 #endif
    695 	if (VC_OPEN(vcp)) {	/* Venus is still alive */
    696  	/* Op went through, interrupt or not... */
    697 	    if (vmp->vm_flags & VM_WRITE) {
    698 		error = 0;
    699 		*outSize = vmp->vm_outSize;
    700 	    }
    701 
    702 	    else if (!(vmp->vm_flags & VM_READ)) {
    703 		/* Interrupted before venus read it. */
    704 		if (cfsdebug||1)
    705 		    myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
    706 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    707 		REMQUE(vmp->vm_chain);
    708 		error = EINTR;
    709 	    }
    710 
    711 	    else {
    712 		/* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
    713                    upcall started */
    714 		/* Interrupted after start of upcall, send venus a signal */
    715 		struct cfs_in_hdr *dog;
    716 		struct vmsg *svmp;
    717 
    718 		if (cfsdebug||1)
    719 		    myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
    720 			   vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    721 
    722 		REMQUE(vmp->vm_chain);
    723 		error = EINTR;
    724 
    725 		CFS_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
    726 
    727 		CFS_ALLOC((svmp->vm_data), char *, sizeof (struct cfs_in_hdr));
    728 		dog = (struct cfs_in_hdr *)svmp->vm_data;
    729 
    730 		svmp->vm_flags = 0;
    731 		dog->opcode = svmp->vm_opcode = CFS_SIGNAL;
    732 		dog->unique = svmp->vm_unique = vmp->vm_unique;
    733 		svmp->vm_inSize = sizeof (struct cfs_in_hdr);
    734 /*??? rvb */	svmp->vm_outSize = sizeof (struct cfs_in_hdr);
    735 
    736 		if (cfsdebug)
    737 		    myprintf(("cfscall: enqueing signal msg (%d, %d)\n",
    738 			   svmp->vm_opcode, svmp->vm_unique));
    739 
    740 		/* insert at head of queue! */
    741 		INSQUE(svmp->vm_chain, vcp->vc_requests);
    742 		selwakeup(&(vcp->vc_selproc));
    743 	    }
    744 	}
    745 
    746 	else {	/* If venus died (!VC_OPEN(vcp)) */
    747 	    if (cfsdebug)
    748 		myprintf(("vcclose woke op %d.%d flags %d\n",
    749 		       vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
    750 
    751 		error = ENODEV;
    752 	}
    753 
    754 	CFS_FREE(vmp, sizeof(struct vmsg));
    755 
    756 	if (!error)
    757 		error = ((struct cfs_out_hdr *)buffer)->result;
    758 	return(error);
    759 }
    760