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