NetBSD/sys/coda/coda_psdev.c

768 lines
19 KiB
C
Raw Normal View History

2013-10-18 00:54:24 +04:00
/* $NetBSD: coda_psdev.c,v 1.50 2013/10/17 20:54:24 christos Exp $ */
1998-08-30 01:26:45 +04:00
1998-09-08 21:12:46 +04:00
/*
2005-02-27 01:58:54 +03:00
*
1998-09-08 21:12:46 +04:00
* Coda: an Experimental Distributed File System
* Release 3.1
2005-02-27 01:58:54 +03:00
*
1998-09-08 21:12:46 +04:00
* Copyright (c) 1987-1998 Carnegie Mellon University
* All Rights Reserved
2005-02-27 01:58:54 +03:00
*
1998-09-08 21:12:46 +04:00
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation, and
* that credit is given to Carnegie Mellon University in all documents
* and publicity pertaining to direct or indirect use of this code or its
* derivatives.
2005-02-27 01:58:54 +03:00
*
1998-09-08 21:12:46 +04:00
* CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS,
* SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS
* FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON
* DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
* RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF
* ANY DERIVATIVE WORK.
2005-02-27 01:58:54 +03:00
*
1998-09-08 21:12:46 +04:00
* Carnegie Mellon encourages users of this software to return any
* improvements or extensions that they make, and to grant Carnegie
* Mellon the rights to redistribute these changes without encumbrance.
2005-02-27 01:58:54 +03:00
*
* @(#) coda/coda_psdev.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $
1998-09-08 21:12:46 +04:00
*/
1998-08-30 01:26:45 +04:00
2005-02-27 01:58:54 +03:00
/*
1998-08-30 01:26:45 +04:00
* Mach Operating System
* Copyright (c) 1989 Carnegie-Mellon University
* All rights reserved. The CMU software License Agreement specifies
* the terms and conditions for use and redistribution.
*/
/*
* This code was written for the Coda file system at Carnegie Mellon
* University. Contributers include David Steere, James Kistler, and
* M. Satyanarayanan. */
/* These routines define the pseudo device for communication between
2005-02-27 01:58:54 +03:00
* Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
* but I moved them to make it easier to port the Minicache without
1998-08-30 01:26:45 +04:00
* porting coda. -- DCS 10/12/94
*
* Following code depends on file-system CODA.
1998-08-30 01:26:45 +04:00
*/
/* These routines are the device entry points for Venus. */
2001-11-13 02:08:56 +03:00
#include <sys/cdefs.h>
2013-10-18 00:54:24 +04:00
__KERNEL_RCSID(0, "$NetBSD: coda_psdev.c,v 1.50 2013/10/17 20:54:24 christos Exp $");
2001-11-13 02:08:56 +03:00
extern int coda_nc_initialized; /* Set if cache has been initialized */
1998-08-30 01:26:45 +04:00
2008-12-30 15:56:12 +03:00
#ifndef _KERNEL_OPT
#define NVCODA 4
#else
#include <vcoda.h>
#endif
1998-08-30 01:26:45 +04:00
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/select.h>
#include <sys/conf.h>
#include <sys/atomic.h>
#include <sys/module.h>
1998-08-30 01:26:45 +04:00
#include <miscfs/syncfs/syncfs.h>
1998-09-15 06:02:55 +04:00
#include <coda/coda.h>
#include <coda/cnode.h>
#include <coda/coda_namecache.h>
#include <coda/coda_io.h>
1998-08-30 01:26:45 +04:00
1998-09-08 21:12:46 +04:00
#define CTL_C
1998-08-30 01:26:45 +04:00
int coda_psdev_print_entry = 0;
static
int outstanding_upcalls = 0;
int coda_call_sleep = PZERO - 1;
#ifdef CTL_C
int coda_pcatch = PCATCH;
#else
#endif
int coda_kernel_version = CODA_KERNEL_VERSION;
2001-11-23 20:42:48 +03:00
#define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__))
1998-08-30 01:26:45 +04:00
void vcodaattach(int n);
1998-08-30 01:26:45 +04:00
dev_type_open(vc_nb_open);
dev_type_close(vc_nb_close);
dev_type_read(vc_nb_read);
dev_type_write(vc_nb_write);
dev_type_ioctl(vc_nb_ioctl);
dev_type_poll(vc_nb_poll);
dev_type_kqfilter(vc_nb_kqfilter);
const struct cdevsw vcoda_cdevsw = {
vc_nb_open, vc_nb_close, vc_nb_read, vc_nb_write, vc_nb_ioctl,
2006-08-30 03:43:12 +04:00
nostop, notty, vc_nb_poll, nommap, vc_nb_kqfilter, D_OTHER,
};
1998-08-30 01:26:45 +04:00
struct vmsg {
TAILQ_ENTRY(vmsg) vm_chain;
void * vm_data;
1998-08-30 01:26:45 +04:00
u_short vm_flags;
u_short vm_inSize; /* Size is at most 5000 bytes */
u_short vm_outSize;
u_short vm_opcode; /* copied from data to save ptr lookup */
int vm_unique;
void * vm_sleep; /* Not used by Mach. */
1998-08-30 01:26:45 +04:00
};
struct coda_mntinfo coda_mnttbl[NVCODA];
1998-08-30 01:26:45 +04:00
#define VM_READ 1
#define VM_WRITE 2
#define VM_INTR 4
/* vcodaattach: do nothing */
1998-08-30 01:26:45 +04:00
void
vcodaattach(int n)
1998-08-30 01:26:45 +04:00
{
}
2005-02-27 01:58:54 +03:00
/*
1998-08-30 01:26:45 +04:00
* These functions are written for NetBSD.
*/
2005-02-27 01:58:54 +03:00
int
vc_nb_open(dev_t dev, int flag, int mode,
struct lwp *l)
1998-08-30 01:26:45 +04:00
{
2000-03-30 15:24:16 +04:00
struct vcomm *vcp;
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
ENTRY;
2009-01-11 05:45:45 +03:00
if (minor(dev) >= NVCODA)
1998-08-30 01:26:45 +04:00
return(ENXIO);
2005-02-27 01:58:54 +03:00
if (!coda_nc_initialized)
coda_nc_init();
2005-02-27 01:58:54 +03:00
vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
1998-08-30 01:26:45 +04:00
if (VC_OPEN(vcp))
return(EBUSY);
2005-02-27 01:58:54 +03:00
selinit(&vcp->vc_selproc);
TAILQ_INIT(&vcp->vc_requests);
TAILQ_INIT(&vcp->vc_replies);
1998-08-30 01:26:45 +04:00
MARK_VC_OPEN(vcp);
2005-02-27 01:58:54 +03:00
coda_mnttbl[minor(dev)].mi_vfsp = NULL;
coda_mnttbl[minor(dev)].mi_rootvp = NULL;
1998-08-30 01:26:45 +04:00
return(0);
}
2005-02-27 01:58:54 +03:00
int
vc_nb_close(dev_t dev, int flag, int mode, struct lwp *l)
1998-08-30 01:26:45 +04:00
{
2000-03-30 15:24:16 +04:00
struct vcomm *vcp;
struct vmsg *vmp;
struct coda_mntinfo *mi;
1998-08-30 01:26:45 +04:00
int err;
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
ENTRY;
2009-01-11 05:45:45 +03:00
if (minor(dev) >= NVCODA)
1998-08-30 01:26:45 +04:00
return(ENXIO);
mi = &coda_mnttbl[minor(dev)];
1998-08-30 01:26:45 +04:00
vcp = &(mi->mi_vcomm);
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
if (!VC_OPEN(vcp))
panic("vcclose: not open");
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* prevent future operations on this vfs from succeeding by auto-
* unmounting any vfs mounted via this device. This frees user or
* sysadm from having to remember where all mount points are located.
* Put this before WAKEUPs to avoid queuing new messages between
* the WAKEUP and the unmount (which can happen if we're unlucky)
*/
if (!mi->mi_rootvp) {
/* just a simple open/close w no mount */
MARK_VC_CLOSED(vcp);
return 0;
1998-08-30 01:26:45 +04:00
}
/* Let unmount know this is for real */
VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
coda_unmounting(mi->mi_vfsp);
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* Wakeup clients so they can return. */
while ((vmp = TAILQ_FIRST(&vcp->vc_requests)) != NULL) {
TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
1998-08-30 01:26:45 +04:00
/* Free signal request messages and don't wakeup cause
no one is waiting. */
if (vmp->vm_opcode == CODA_SIGNAL) {
2008-03-01 20:26:07 +03:00
CODA_FREE(vmp->vm_data, VC_IN_NO_DATA);
CODA_FREE(vmp, sizeof(struct vmsg));
1998-08-30 01:26:45 +04:00
continue;
}
2005-02-27 01:58:54 +03:00
outstanding_upcalls++;
1998-08-30 01:26:45 +04:00
wakeup(&vmp->vm_sleep);
}
while ((vmp = TAILQ_FIRST(&vcp->vc_replies)) != NULL) {
TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
2005-02-27 01:58:54 +03:00
outstanding_upcalls++;
1998-08-30 01:26:45 +04:00
wakeup(&vmp->vm_sleep);
}
1998-08-30 01:26:45 +04:00
MARK_VC_CLOSED(vcp);
if (outstanding_upcalls) {
#ifdef CODA_VERBOSE
printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
#else
(void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
#endif
}
2005-12-11 15:16:03 +03:00
err = dounmount(mi->mi_vfsp, flag, l);
if (err)
2009-01-11 05:45:45 +03:00
myprintf(("Error %d unmounting vfs in vcclose(%llu)\n",
err, (unsigned long long)minor(dev)));
seldestroy(&vcp->vc_selproc);
1998-08-30 01:26:45 +04:00
return 0;
}
2005-02-27 01:58:54 +03:00
int
vc_nb_read(dev_t dev, struct uio *uiop, int flag)
1998-08-30 01:26:45 +04:00
{
2000-03-30 15:24:16 +04:00
struct vcomm * vcp;
struct vmsg *vmp;
1998-08-30 01:26:45 +04:00
int error = 0;
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
ENTRY;
2009-01-11 05:45:45 +03:00
if (minor(dev) >= NVCODA)
1998-08-30 01:26:45 +04:00
return(ENXIO);
2005-02-27 01:58:54 +03:00
vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
1998-08-30 01:26:45 +04:00
/* Get message at head of request queue. */
vmp = TAILQ_FIRST(&vcp->vc_requests);
if (vmp == NULL)
1998-08-30 01:26:45 +04:00
return(0); /* Nothing to read */
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* Move the input args into userspace */
uiop->uio_rw = UIO_READ;
error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
if (error) {
myprintf(("vcread: error (%d) on uiomove\n", error));
error = EINVAL;
}
TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* If request was a signal, free up the message and don't
enqueue it in the reply queue. */
if (vmp->vm_opcode == CODA_SIGNAL) {
if (codadebug)
2005-02-27 01:58:54 +03:00
myprintf(("vcread: signal msg (%d, %d)\n",
1998-08-30 01:26:45 +04:00
vmp->vm_opcode, vmp->vm_unique));
2008-03-01 20:26:07 +03:00
CODA_FREE(vmp->vm_data, VC_IN_NO_DATA);
CODA_FREE(vmp, sizeof(struct vmsg));
1998-08-30 01:26:45 +04:00
return(error);
}
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
vmp->vm_flags |= VM_READ;
TAILQ_INSERT_TAIL(&vcp->vc_replies, vmp, vm_chain);
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
return(error);
}
int
vc_nb_write(dev_t dev, struct uio *uiop, int flag)
1998-08-30 01:26:45 +04:00
{
2000-03-30 15:24:16 +04:00
struct vcomm * vcp;
struct vmsg *vmp;
struct coda_out_hdr *out;
1998-08-30 01:26:45 +04:00
u_long seq;
u_long opcode;
int tbuf[2];
1998-08-30 01:26:45 +04:00
int error = 0;
ENTRY;
2009-01-11 05:45:45 +03:00
if (minor(dev) >= NVCODA)
1998-08-30 01:26:45 +04:00
return(ENXIO);
2005-02-27 01:58:54 +03:00
vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* Peek at the opcode, unique without transfering the data. */
uiop->uio_rw = UIO_WRITE;
2008-03-01 20:26:07 +03:00
error = uiomove(tbuf, sizeof(int) * 2, uiop);
1998-08-30 01:26:45 +04:00
if (error) {
myprintf(("vcwrite: error (%d) on uiomove\n", error));
return(EINVAL);
}
2005-02-27 01:58:54 +03:00
opcode = tbuf[0];
seq = tbuf[1];
2005-02-27 01:58:54 +03:00
if (codadebug)
1998-08-30 01:26:45 +04:00
myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
if (DOWNCALL(opcode)) {
union outputArgs pbuf;
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* get the rest of the data. */
uiop->uio_rw = UIO_WRITE;
2008-03-01 20:26:07 +03:00
error = uiomove(&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
1998-08-30 01:26:45 +04:00
if (error) {
2005-02-27 01:58:54 +03:00
myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
1998-08-30 01:26:45 +04:00
error, opcode, seq));
return(EINVAL);
}
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
return handleDownCall(opcode, &pbuf);
}
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* Look for the message on the (waiting for) reply queue. */
TAILQ_FOREACH(vmp, &vcp->vc_replies, vm_chain) {
1998-08-30 01:26:45 +04:00
if (vmp->vm_unique == seq) break;
}
2005-02-27 01:58:54 +03:00
if (vmp == NULL) {
if (codadebug)
1998-08-30 01:26:45 +04:00
myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
return(ESRCH);
}
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* Remove the message from the reply queue */
TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* move data into response buffer. */
out = (struct coda_out_hdr *)vmp->vm_data;
1998-08-30 01:26:45 +04:00
/* Don't need to copy opcode and uniquifier. */
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* get the rest of the data. */
if (vmp->vm_outSize < uiop->uio_resid) {
1999-09-18 09:31:42 +04:00
myprintf(("vcwrite: more data than asked for (%d < %lu)\n",
vmp->vm_outSize, (unsigned long) uiop->uio_resid));
1998-08-30 01:26:45 +04:00
wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
return(EINVAL);
2005-02-27 01:58:54 +03:00
}
tbuf[0] = uiop->uio_resid; /* Save this value. */
1998-08-30 01:26:45 +04:00
uiop->uio_rw = UIO_WRITE;
2008-03-01 20:26:07 +03:00
error = uiomove(&out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
1998-08-30 01:26:45 +04:00
if (error) {
2005-02-27 01:58:54 +03:00
myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
1998-08-30 01:26:45 +04:00
error, opcode, seq));
return(EINVAL);
}
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* I don't think these are used, but just in case. */
/* XXX - aren't these two already correct? -bnoble */
out->opcode = opcode;
out->unique = seq;
vmp->vm_outSize = tbuf[0]; /* Amount of data transferred? */
1998-08-30 01:26:45 +04:00
vmp->vm_flags |= VM_WRITE;
wakeup(&vmp->vm_sleep);
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
return(0);
}
int
vc_nb_ioctl(dev_t dev, u_long cmd, void *addr, int flag,
struct lwp *l)
1998-08-30 01:26:45 +04:00
{
ENTRY;
switch(cmd) {
case CODARESIZE: {
struct coda_resize *data = (struct coda_resize *)addr;
return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
1998-08-30 01:26:45 +04:00
break;
}
case CODASTATS:
if (coda_nc_use) {
coda_nc_gather_stats();
1998-08-30 01:26:45 +04:00
return(0);
} else {
return(ENODEV);
}
break;
case CODAPRINT:
if (coda_nc_use) {
print_coda_nc();
1998-08-30 01:26:45 +04:00
return(0);
} else {
return(ENODEV);
}
break;
case CIOC_KERNEL_VERSION:
switch (*(u_int *)addr) {
case 0:
*(u_int *)addr = coda_kernel_version;
return 0;
break;
case 1:
case 2:
if (coda_kernel_version != *(u_int *)addr)
return ENOENT;
else
return 0;
default:
return ENOENT;
}
break;
1998-08-30 01:26:45 +04:00
default :
return(EINVAL);
break;
}
}
int
2005-12-11 15:16:03 +03:00
vc_nb_poll(dev_t dev, int events, struct lwp *l)
1998-08-30 01:26:45 +04:00
{
2000-03-30 15:24:16 +04:00
struct vcomm *vcp;
1998-08-30 01:26:45 +04:00
int event_msk = 0;
ENTRY;
2005-02-27 01:58:54 +03:00
2009-01-11 05:45:45 +03:00
if (minor(dev) >= NVCODA)
1998-08-30 01:26:45 +04:00
return(ENXIO);
2005-02-27 01:58:54 +03:00
vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
event_msk = events & (POLLIN|POLLRDNORM);
if (!event_msk)
return(0);
2005-02-27 01:58:54 +03:00
if (!TAILQ_EMPTY(&vcp->vc_requests))
1998-08-30 01:26:45 +04:00
return(events & (POLLIN|POLLRDNORM));
2005-12-11 15:16:03 +03:00
selrecord(l, &(vcp->vc_selproc));
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
return(0);
}
static void
filt_vc_nb_detach(struct knote *kn)
{
struct vcomm *vcp = kn->kn_hook;
2002-11-26 21:45:22 +03:00
SLIST_REMOVE(&vcp->vc_selproc.sel_klist, kn, knote, kn_selnext);
}
static int
filt_vc_nb_read(struct knote *kn, long hint)
{
2005-02-27 01:58:54 +03:00
struct vcomm *vcp = kn->kn_hook;
struct vmsg *vmp;
vmp = TAILQ_FIRST(&vcp->vc_requests);
if (vmp == NULL)
return (0);
kn->kn_data = vmp->vm_inSize;
return (1);
}
static const struct filterops vc_nb_read_filtops =
{ 1, NULL, filt_vc_nb_detach, filt_vc_nb_read };
int
vc_nb_kqfilter(dev_t dev, struct knote *kn)
{
struct vcomm *vcp;
struct klist *klist;
ENTRY;
2005-02-27 01:58:54 +03:00
2009-01-11 05:45:45 +03:00
if (minor(dev) >= NVCODA)
return(ENXIO);
2005-02-27 01:58:54 +03:00
vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
switch (kn->kn_filter) {
case EVFILT_READ:
2002-11-26 21:45:22 +03:00
klist = &vcp->vc_selproc.sel_klist;
kn->kn_fop = &vc_nb_read_filtops;
break;
default:
return (EINVAL);
}
kn->kn_hook = vcp;
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
return (0);
}
1998-08-30 01:26:45 +04:00
/*
* Statistics
*/
struct coda_clstat coda_clstat;
1998-08-30 01:26:45 +04:00
2005-02-27 01:58:54 +03:00
/*
2003-01-06 16:04:54 +03:00
* Key question: whether to sleep interruptably or uninterruptably when
1998-08-30 01:26:45 +04:00
* waiting for Venus. The former seems better (cause you can ^C a
* job), but then GNU-EMACS completion breaks. Use tsleep with no
* timeout, and no longjmp happens. But, when sleeping
* "uninterruptibly", we don't get told if it returns abnormally
2005-02-27 01:58:54 +03:00
* (e.g. kill -9).
1998-08-30 01:26:45 +04:00
*/
int
2005-08-31 02:27:16 +04:00
coda_call(struct coda_mntinfo *mntinfo, int inSize, int *outSize,
void *buffer)
1998-08-30 01:26:45 +04:00
{
struct vcomm *vcp;
struct vmsg *vmp;
int error;
#ifdef CTL_C
2005-12-11 15:16:03 +03:00
struct lwp *l = curlwp;
struct proc *p = l->l_proc;
1998-09-15 06:02:55 +04:00
sigset_t psig_omask;
1998-08-30 01:26:45 +04:00
int i;
2007-02-10 00:55:00 +03:00
psig_omask = l->l_sigmask; /* XXXSA */
1998-08-30 01:26:45 +04:00
#endif
if (mntinfo == NULL) {
/* Unlikely, but could be a race condition with a dying warden */
return ENODEV;
}
vcp = &(mntinfo->mi_vcomm);
2005-02-27 01:58:54 +03:00
coda_clstat.ncalls++;
coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
1998-08-30 01:26:45 +04:00
if (!VC_OPEN(vcp))
return(ENODEV);
CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
1998-08-30 01:26:45 +04:00
/* Format the request message. */
vmp->vm_data = buffer;
vmp->vm_flags = 0;
vmp->vm_inSize = inSize;
2005-02-27 01:58:54 +03:00
vmp->vm_outSize
1998-08-30 01:26:45 +04:00
= *outSize ? *outSize : inSize; /* |buffer| >= inSize */
vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
1998-08-30 01:26:45 +04:00
vmp->vm_unique = ++vcp->vc_seq;
if (codadebug)
2005-02-27 01:58:54 +03:00
myprintf(("Doing a call for %d.%d\n",
1998-08-30 01:26:45 +04:00
vmp->vm_opcode, vmp->vm_unique));
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
/* Fill in the common input args. */
((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
1998-08-30 01:26:45 +04:00
/* Append msg to request queue and poke Venus. */
TAILQ_INSERT_TAIL(&vcp->vc_requests, vmp, vm_chain);
selnotify(&(vcp->vc_selproc), 0, 0);
1998-08-30 01:26:45 +04:00
/* We can be interrupted while we wait for Venus to process
* our request. If the interrupt occurs before Venus has read
* the request, we dequeue and return. If it occurs after the
* read but before the reply, we dequeue, send a signal
* message, and return. If it occurs after the reply we ignore
* it. In no case do we want to restart the syscall. If it
* was interrupted by a venus shutdown (vcclose), return
* ENODEV. */
/* Ignore return, We have to check anyway */
#ifdef CTL_C
/* This is work in progress. Setting coda_pcatch lets tsleep reawaken
1998-08-30 01:26:45 +04:00
on a ^c or ^z. The problem is that emacs sets certain interrupts
as SA_RESTART. This means that we should exit sleep handle the
"signal" and then go to sleep again. Mostly this is done by letting
2005-02-27 01:58:54 +03:00
the syscall complete and be restarted. We are not idempotent and
1998-08-30 01:26:45 +04:00
can not do this. A better solution is necessary.
*/
i = 0;
do {
error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2);
1998-08-30 01:26:45 +04:00
if (error == 0)
break;
mutex_enter(p->p_lock);
2007-02-10 00:55:00 +03:00
if (error == EWOULDBLOCK) {
#ifdef CODA_VERBOSE
printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
#endif
2007-02-10 00:55:00 +03:00
} else if (sigispending(l, SIGIO)) {
sigaddset(&l->l_sigmask, SIGIO);
#ifdef CODA_VERBOSE
printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i);
#endif
2007-02-10 00:55:00 +03:00
} else if (sigispending(l, SIGALRM)) {
sigaddset(&l->l_sigmask, SIGALRM);
#ifdef CODA_VERBOSE
printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i);
#endif
1998-08-30 01:26:45 +04:00
} else {
1998-09-15 06:02:55 +04:00
sigset_t tmp;
2007-02-10 00:55:00 +03:00
tmp = p->p_sigpend.sp_set; /* array assignment */
sigminusset(&l->l_sigmask, &tmp);
1998-09-15 06:02:55 +04:00
#ifdef CODA_VERBOSE
printf("coda_call: tsleep returns %d, cnt %d\n", error, i);
1998-09-15 06:02:55 +04:00
printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n",
2007-02-10 00:55:00 +03:00
p->p_sigpend.sp_set.__bits[0], p->p_sigpend.sp_set.__bits[1],
p->p_sigpend.sp_set.__bits[2], p->p_sigpend.sp_set.__bits[3],
l->l_sigmask.__bits[0], l->l_sigmask.__bits[1],
l->l_sigmask.__bits[2], l->l_sigmask.__bits[3],
1998-09-15 06:02:55 +04:00
tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]);
#endif
mutex_exit(p->p_lock);
1998-08-30 01:26:45 +04:00
break;
#ifdef notyet
2007-02-10 00:55:00 +03:00
sigminusset(&l->l_sigmask, &p->p_sigpend.sp_set);
2005-02-27 01:58:54 +03:00
printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n",
2007-02-10 00:55:00 +03:00
p->p_sigpend.sp_set.__bits[0], p->p_sigpend.sp_set.__bits[1],
p->p_sigpend.sp_set.__bits[2], p->p_sigpend.sp_set.__bits[3],
l->l_sigmask.__bits[0], l->l_sigmask.__bits[1],
l->l_sigmask.__bits[2], l->l_sigmask.__bits[3]);
#endif
1998-08-30 01:26:45 +04:00
}
mutex_exit(p->p_lock);
} while (error && i++ < 128 && VC_OPEN(vcp));
2007-02-10 00:55:00 +03:00
l->l_sigmask = psig_omask; /* XXXSA */
1998-08-30 01:26:45 +04:00
#else
(void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
1998-08-30 01:26:45 +04:00
#endif
if (VC_OPEN(vcp)) { /* Venus is still alive */
/* Op went through, interrupt or not... */
if (vmp->vm_flags & VM_WRITE) {
error = 0;
*outSize = vmp->vm_outSize;
}
2005-02-27 01:58:54 +03:00
else if (!(vmp->vm_flags & VM_READ)) {
1998-08-30 01:26:45 +04:00
/* Interrupted before venus read it. */
#ifdef CODA_VERBOSE
if (1)
#else
if (codadebug)
#endif
1998-08-30 01:26:45 +04:00
myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
1998-08-30 01:26:45 +04:00
error = EINTR;
}
2005-02-27 01:58:54 +03:00
else {
1998-08-30 01:26:45 +04:00
/* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
upcall started */
/* Interrupted after start of upcall, send venus a signal */
struct coda_in_hdr *dog;
1998-08-30 01:26:45 +04:00
struct vmsg *svmp;
2005-02-27 01:58:54 +03:00
#ifdef CODA_VERBOSE
if (1)
#else
if (codadebug)
#endif
1998-08-30 01:26:45 +04:00
myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
2005-02-27 01:58:54 +03:00
TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
1998-08-30 01:26:45 +04:00
error = EINTR;
2005-02-27 01:58:54 +03:00
CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
1998-08-30 01:26:45 +04:00
CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
dog = (struct coda_in_hdr *)svmp->vm_data;
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
svmp->vm_flags = 0;
dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
1998-08-30 01:26:45 +04:00
dog->unique = svmp->vm_unique = vmp->vm_unique;
svmp->vm_inSize = sizeof (struct coda_in_hdr);
/*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
2005-02-27 01:58:54 +03:00
if (codadebug)
myprintf(("coda_call: enqueing signal msg (%d, %d)\n",
1998-08-30 01:26:45 +04:00
svmp->vm_opcode, svmp->vm_unique));
2005-02-27 01:58:54 +03:00
/* insert at head of queue */
TAILQ_INSERT_HEAD(&vcp->vc_requests, svmp, vm_chain);
selnotify(&(vcp->vc_selproc), 0, 0);
1998-08-30 01:26:45 +04:00
}
}
else { /* If venus died (!VC_OPEN(vcp)) */
if (codadebug)
1998-08-30 01:26:45 +04:00
myprintf(("vcclose woke op %d.%d flags %d\n",
vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
2005-02-27 01:58:54 +03:00
1998-08-30 01:26:45 +04:00
error = ENODEV;
}
CODA_FREE(vmp, sizeof(struct vmsg));
1998-08-30 01:26:45 +04:00
if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
wakeup(&outstanding_upcalls);
1998-08-30 01:26:45 +04:00
if (!error)
error = ((struct coda_out_hdr *)buffer)->result;
1998-08-30 01:26:45 +04:00
return(error);
}
1998-09-15 06:02:55 +04:00
MODULE(MODULE_CLASS_DRIVER, vcoda, NULL);
static int
vcoda_modcmd(modcmd_t cmd, void *arg)
{
2013-10-18 00:54:24 +04:00
int error = 0;
switch (cmd) {
case MODULE_CMD_INIT:
#ifdef _MODULE
2013-10-18 00:54:24 +04:00
int cmajor, dmajor;
vcodaattach(NVCODA);
2013-10-18 00:54:24 +04:00
dmajor = cmajor = -1;
return devsw_attach("vcoda", NULL, &dmajor,
&vcoda_cdevsw, &cmajor);
#endif
break;
case MODULE_CMD_FINI:
#ifdef _MODULE
{
for (size_t i = 0; i < NVCODA; i++) {
struct vcomm *vcp = &coda_mnttbl[i].mi_vcomm;
if (VC_OPEN(vcp))
return EBUSY;
}
return devsw_detach(NULL, &vcoda_cdevsw);
}
#endif
break;
case MODULE_CMD_STAT:
return ENOTTY;
default:
return ENOTTY;
}
return error;
}