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