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