1*4ea2e44bSthorpej /* $NetBSD: coda_psdev.c,v 1.65 2024/05/17 23:57:46 thorpej Exp $ */
2a00eb709Srvb
32eec68d7Srvb /*
4a00eb709Srvb *
5a00eb709Srvb * Coda: an Experimental Distributed File System
6a00eb709Srvb * Release 3.1
7a00eb709Srvb *
8a00eb709Srvb * Copyright (c) 1987-1998 Carnegie Mellon University
9a00eb709Srvb * All Rights Reserved
10a00eb709Srvb *
11a00eb709Srvb * Permission to use, copy, modify and distribute this software and its
12a00eb709Srvb * documentation is hereby granted, provided that both the copyright
13a00eb709Srvb * notice and this permission notice appear in all copies of the
14a00eb709Srvb * software, derivative works or modified versions, and any portions
15a00eb709Srvb * thereof, and that both notices appear in supporting documentation, and
16a00eb709Srvb * that credit is given to Carnegie Mellon University in all documents
17a00eb709Srvb * and publicity pertaining to direct or indirect use of this code or its
18a00eb709Srvb * derivatives.
19a00eb709Srvb *
20a00eb709Srvb * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS,
21a00eb709Srvb * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS
22a00eb709Srvb * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON
23a00eb709Srvb * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
24a00eb709Srvb * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF
25a00eb709Srvb * ANY DERIVATIVE WORK.
26a00eb709Srvb *
27a00eb709Srvb * Carnegie Mellon encourages users of this software to return any
28a00eb709Srvb * improvements or extensions that they make, and to grant Carnegie
29a00eb709Srvb * Mellon the rights to redistribute these changes without encumbrance.
30a00eb709Srvb *
319187d280Srvb * @(#) coda/coda_psdev.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $
322eec68d7Srvb */
332eec68d7Srvb
342eec68d7Srvb /*
352eec68d7Srvb * Mach Operating System
362eec68d7Srvb * Copyright (c) 1989 Carnegie-Mellon University
372eec68d7Srvb * All rights reserved. The CMU software License Agreement specifies
382eec68d7Srvb * the terms and conditions for use and redistribution.
392eec68d7Srvb */
402eec68d7Srvb
412eec68d7Srvb /*
422eec68d7Srvb * This code was written for the Coda file system at Carnegie Mellon
432eec68d7Srvb * University. Contributers include David Steere, James Kistler, and
442eec68d7Srvb * M. Satyanarayanan. */
452eec68d7Srvb
4696125fbeSjdolecek /* These routines define the pseudo device for communication between
472eec68d7Srvb * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c,
482eec68d7Srvb * but I moved them to make it easier to port the Minicache without
492eec68d7Srvb * porting coda. -- DCS 10/12/94
5096125fbeSjdolecek *
5196125fbeSjdolecek * Following code depends on file-system CODA.
522eec68d7Srvb */
532eec68d7Srvb
542eec68d7Srvb /* These routines are the device entry points for Venus. */
552eec68d7Srvb
56a13b5687Slukem #include <sys/cdefs.h>
57*4ea2e44bSthorpej __KERNEL_RCSID(0, "$NetBSD: coda_psdev.c,v 1.65 2024/05/17 23:57:46 thorpej Exp $");
58a13b5687Slukem
590aa47cd0Srvb extern int coda_nc_initialized; /* Set if cache has been initialized */
602eec68d7Srvb
612eec68d7Srvb #include <sys/param.h>
622eec68d7Srvb #include <sys/systm.h>
632eec68d7Srvb #include <sys/kernel.h>
642eec68d7Srvb #include <sys/proc.h>
652eec68d7Srvb #include <sys/mount.h>
662eec68d7Srvb #include <sys/file.h>
672eec68d7Srvb #include <sys/ioctl.h>
682eec68d7Srvb #include <sys/poll.h>
692eec68d7Srvb #include <sys/select.h>
7077a6b82bSgehenna #include <sys/conf.h>
7142d06267Sad #include <sys/atomic.h>
72704aca39Schristos #include <sys/module.h>
732eec68d7Srvb
749187d280Srvb #include <coda/coda.h>
759187d280Srvb #include <coda/cnode.h>
769187d280Srvb #include <coda/coda_namecache.h>
779187d280Srvb #include <coda/coda_io.h>
782eec68d7Srvb
79e7ae23fdSchristos #include "ioconf.h"
80e7ae23fdSchristos
81a00eb709Srvb #define CTL_C
822eec68d7Srvb
830aa47cd0Srvb int coda_psdev_print_entry = 0;
84e7f0c598Srvb static
85e7f0c598Srvb int outstanding_upcalls = 0;
86e7f0c598Srvb int coda_call_sleep = PZERO - 1;
87e7f0c598Srvb #ifdef CTL_C
88e7f0c598Srvb int coda_pcatch = PCATCH;
89e7f0c598Srvb #else
90e7f0c598Srvb #endif
912eec68d7Srvb
92704aca39Schristos int coda_kernel_version = CODA_KERNEL_VERSION;
93704aca39Schristos
940b5814f1Sperry #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__))
950aa47cd0Srvb
9677a6b82bSgehenna dev_type_open(vc_nb_open);
9777a6b82bSgehenna dev_type_close(vc_nb_close);
9877a6b82bSgehenna dev_type_read(vc_nb_read);
9977a6b82bSgehenna dev_type_write(vc_nb_write);
10077a6b82bSgehenna dev_type_ioctl(vc_nb_ioctl);
10177a6b82bSgehenna dev_type_poll(vc_nb_poll);
102e0cc03a0Sjdolecek dev_type_kqfilter(vc_nb_kqfilter);
10377a6b82bSgehenna
10477a6b82bSgehenna const struct cdevsw vcoda_cdevsw = {
105a68f9396Sdholland .d_open = vc_nb_open,
106a68f9396Sdholland .d_close = vc_nb_close,
107a68f9396Sdholland .d_read = vc_nb_read,
108a68f9396Sdholland .d_write = vc_nb_write,
109a68f9396Sdholland .d_ioctl = vc_nb_ioctl,
110a68f9396Sdholland .d_stop = nostop,
111a68f9396Sdholland .d_tty = notty,
112a68f9396Sdholland .d_poll = vc_nb_poll,
113a68f9396Sdholland .d_mmap = nommap,
114a68f9396Sdholland .d_kqfilter = vc_nb_kqfilter,
115f9228f42Sdholland .d_discard = nodiscard,
116a68f9396Sdholland .d_flag = D_OTHER,
11777a6b82bSgehenna };
11877a6b82bSgehenna
1192eec68d7Srvb struct vmsg {
12072ac0bccSplunky TAILQ_ENTRY(vmsg) vm_chain;
12153524e44Schristos void * vm_data;
1222eec68d7Srvb u_short vm_flags;
1232eec68d7Srvb u_short vm_inSize; /* Size is at most 5000 bytes */
1242eec68d7Srvb u_short vm_outSize;
1252eec68d7Srvb u_short vm_opcode; /* copied from data to save ptr lookup */
1262eec68d7Srvb int vm_unique;
12753524e44Schristos void * vm_sleep; /* Not used by Mach. */
1282eec68d7Srvb };
1292eec68d7Srvb
130704aca39Schristos struct coda_mntinfo coda_mnttbl[NVCODA];
131704aca39Schristos
1322eec68d7Srvb #define VM_READ 1
1332eec68d7Srvb #define VM_WRITE 2
1342eec68d7Srvb #define VM_INTR 4
1352eec68d7Srvb
1360aa47cd0Srvb /* vcodaattach: do nothing */
1372eec68d7Srvb void
vcodaattach(int n)138168cd830Schristos vcodaattach(int n)
1392eec68d7Srvb {
1402eec68d7Srvb }
1412eec68d7Srvb
1422eec68d7Srvb /*
1432eec68d7Srvb * These functions are written for NetBSD.
1442eec68d7Srvb */
1452eec68d7Srvb int
vc_nb_open(dev_t dev,int flag,int mode,struct lwp * l)146168cd830Schristos vc_nb_open(dev_t dev, int flag, int mode,
147168cd830Schristos struct lwp *l)
1482eec68d7Srvb {
149a82aeb55Saugustss struct vcomm *vcp;
1502eec68d7Srvb
1512eec68d7Srvb ENTRY;
1522eec68d7Srvb
153461a86f9Schristos if (minor(dev) >= NVCODA)
1542eec68d7Srvb return(ENXIO);
1552eec68d7Srvb
1560aa47cd0Srvb if (!coda_nc_initialized)
1570aa47cd0Srvb coda_nc_init();
1582eec68d7Srvb
1590aa47cd0Srvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
1602eec68d7Srvb if (VC_OPEN(vcp))
1612eec68d7Srvb return(EBUSY);
1622eec68d7Srvb
163c6186facSrmind selinit(&vcp->vc_selproc);
16472ac0bccSplunky TAILQ_INIT(&vcp->vc_requests);
16572ac0bccSplunky TAILQ_INIT(&vcp->vc_replies);
1662eec68d7Srvb MARK_VC_OPEN(vcp);
1672eec68d7Srvb
1680aa47cd0Srvb coda_mnttbl[minor(dev)].mi_vfsp = NULL;
1690aa47cd0Srvb coda_mnttbl[minor(dev)].mi_rootvp = NULL;
1702eec68d7Srvb
1712eec68d7Srvb return(0);
1722eec68d7Srvb }
1732eec68d7Srvb
1742eec68d7Srvb int
vc_nb_close(dev_t dev,int flag,int mode,struct lwp * l)175168cd830Schristos vc_nb_close(dev_t dev, int flag, int mode, struct lwp *l)
1762eec68d7Srvb {
177a82aeb55Saugustss struct vcomm *vcp;
17872ac0bccSplunky struct vmsg *vmp;
1790aa47cd0Srvb struct coda_mntinfo *mi;
1802eec68d7Srvb int err;
1812eec68d7Srvb
1822eec68d7Srvb ENTRY;
1832eec68d7Srvb
184461a86f9Schristos if (minor(dev) >= NVCODA)
1852eec68d7Srvb return(ENXIO);
1862eec68d7Srvb
1870aa47cd0Srvb mi = &coda_mnttbl[minor(dev)];
1882eec68d7Srvb vcp = &(mi->mi_vcomm);
1892eec68d7Srvb
1902eec68d7Srvb if (!VC_OPEN(vcp))
1912eec68d7Srvb panic("vcclose: not open");
1922eec68d7Srvb
1932eec68d7Srvb /* prevent future operations on this vfs from succeeding by auto-
1942eec68d7Srvb * unmounting any vfs mounted via this device. This frees user or
1952eec68d7Srvb * sysadm from having to remember where all mount points are located.
1962eec68d7Srvb * Put this before WAKEUPs to avoid queuing new messages between
1972eec68d7Srvb * the WAKEUP and the unmount (which can happen if we're unlucky)
1982eec68d7Srvb */
199e7f0c598Srvb if (!mi->mi_rootvp) {
200e7f0c598Srvb /* just a simple open/close w no mount */
201e7f0c598Srvb MARK_VC_CLOSED(vcp);
202e7f0c598Srvb return 0;
203e7f0c598Srvb }
204e7f0c598Srvb
2052eec68d7Srvb /* Let unmount know this is for real */
2062eec68d7Srvb VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING;
2070aa47cd0Srvb coda_unmounting(mi->mi_vfsp);
2082eec68d7Srvb
2092eec68d7Srvb /* Wakeup clients so they can return. */
21072ac0bccSplunky while ((vmp = TAILQ_FIRST(&vcp->vc_requests)) != NULL) {
21172ac0bccSplunky TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
21272ac0bccSplunky
2132eec68d7Srvb /* Free signal request messages and don't wakeup cause
2142eec68d7Srvb no one is waiting. */
2150aa47cd0Srvb if (vmp->vm_opcode == CODA_SIGNAL) {
2166e030479Splunky CODA_FREE(vmp->vm_data, VC_IN_NO_DATA);
2176e030479Splunky CODA_FREE(vmp, sizeof(struct vmsg));
2182eec68d7Srvb continue;
2192eec68d7Srvb }
220e7f0c598Srvb outstanding_upcalls++;
2212eec68d7Srvb wakeup(&vmp->vm_sleep);
2222eec68d7Srvb }
2232eec68d7Srvb
22472ac0bccSplunky while ((vmp = TAILQ_FIRST(&vcp->vc_replies)) != NULL) {
22572ac0bccSplunky TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
22672ac0bccSplunky
227e7f0c598Srvb outstanding_upcalls++;
2282eec68d7Srvb wakeup(&vmp->vm_sleep);
2292eec68d7Srvb }
2302eec68d7Srvb
2312eec68d7Srvb MARK_VC_CLOSED(vcp);
232e7f0c598Srvb
233e7f0c598Srvb if (outstanding_upcalls) {
234e7f0c598Srvb #ifdef CODA_VERBOSE
235e7f0c598Srvb printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls);
236e7f0c598Srvb (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
237e7f0c598Srvb printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls);
238e7f0c598Srvb #else
239e7f0c598Srvb (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0);
240e7f0c598Srvb #endif
241e7f0c598Srvb }
242e7f0c598Srvb
24395e1ffb1Schristos err = dounmount(mi->mi_vfsp, flag, l);
244e7f0c598Srvb if (err)
245461a86f9Schristos myprintf(("Error %d unmounting vfs in vcclose(%llu)\n",
246461a86f9Schristos err, (unsigned long long)minor(dev)));
247c6186facSrmind seldestroy(&vcp->vc_selproc);
2482eec68d7Srvb return 0;
2492eec68d7Srvb }
2502eec68d7Srvb
2512eec68d7Srvb int
vc_nb_read(dev_t dev,struct uio * uiop,int flag)252168cd830Schristos vc_nb_read(dev_t dev, struct uio *uiop, int flag)
2532eec68d7Srvb {
254a82aeb55Saugustss struct vcomm * vcp;
255a82aeb55Saugustss struct vmsg *vmp;
2562eec68d7Srvb int error = 0;
2572eec68d7Srvb
2582eec68d7Srvb ENTRY;
2592eec68d7Srvb
260461a86f9Schristos if (minor(dev) >= NVCODA)
2612eec68d7Srvb return(ENXIO);
2622eec68d7Srvb
2630aa47cd0Srvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
2642eec68d7Srvb
26572ac0bccSplunky /* Get message at head of request queue. */
26672ac0bccSplunky vmp = TAILQ_FIRST(&vcp->vc_requests);
26772ac0bccSplunky if (vmp == NULL)
26872ac0bccSplunky return(0); /* Nothing to read */
2692eec68d7Srvb
2702eec68d7Srvb /* Move the input args into userspace */
2712eec68d7Srvb uiop->uio_rw = UIO_READ;
2722eec68d7Srvb error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop);
2732eec68d7Srvb if (error) {
2742eec68d7Srvb myprintf(("vcread: error (%d) on uiomove\n", error));
2752eec68d7Srvb error = EINVAL;
2762eec68d7Srvb }
2772eec68d7Srvb
27872ac0bccSplunky TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
2792eec68d7Srvb
2802eec68d7Srvb /* If request was a signal, free up the message and don't
2812eec68d7Srvb enqueue it in the reply queue. */
2820aa47cd0Srvb if (vmp->vm_opcode == CODA_SIGNAL) {
2830aa47cd0Srvb if (codadebug)
2842eec68d7Srvb myprintf(("vcread: signal msg (%d, %d)\n",
2852eec68d7Srvb vmp->vm_opcode, vmp->vm_unique));
2866e030479Splunky CODA_FREE(vmp->vm_data, VC_IN_NO_DATA);
2876e030479Splunky CODA_FREE(vmp, sizeof(struct vmsg));
2882eec68d7Srvb return(error);
2892eec68d7Srvb }
2902eec68d7Srvb
2912eec68d7Srvb vmp->vm_flags |= VM_READ;
29272ac0bccSplunky TAILQ_INSERT_TAIL(&vcp->vc_replies, vmp, vm_chain);
2932eec68d7Srvb
2942eec68d7Srvb return(error);
2952eec68d7Srvb }
2962eec68d7Srvb
2972eec68d7Srvb int
vc_nb_write(dev_t dev,struct uio * uiop,int flag)298168cd830Schristos vc_nb_write(dev_t dev, struct uio *uiop, int flag)
2992eec68d7Srvb {
300a82aeb55Saugustss struct vcomm * vcp;
301a82aeb55Saugustss struct vmsg *vmp;
3020aa47cd0Srvb struct coda_out_hdr *out;
3032eec68d7Srvb u_long seq;
3042eec68d7Srvb u_long opcode;
30581cb2a76Schristos int tbuf[2];
3062eec68d7Srvb int error = 0;
3072eec68d7Srvb
3082eec68d7Srvb ENTRY;
3092eec68d7Srvb
310461a86f9Schristos if (minor(dev) >= NVCODA)
3112eec68d7Srvb return(ENXIO);
3122eec68d7Srvb
3130aa47cd0Srvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
3142eec68d7Srvb
3150ac7f4ddSandvar /* Peek at the opcode, unique without transferring the data. */
3162eec68d7Srvb uiop->uio_rw = UIO_WRITE;
3176e030479Splunky error = uiomove(tbuf, sizeof(int) * 2, uiop);
3182eec68d7Srvb if (error) {
3192eec68d7Srvb myprintf(("vcwrite: error (%d) on uiomove\n", error));
3202eec68d7Srvb return(EINVAL);
3212eec68d7Srvb }
3222eec68d7Srvb
32381cb2a76Schristos opcode = tbuf[0];
32481cb2a76Schristos seq = tbuf[1];
3252eec68d7Srvb
3260aa47cd0Srvb if (codadebug)
3272eec68d7Srvb myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq));
3282eec68d7Srvb
3292eec68d7Srvb if (DOWNCALL(opcode)) {
3302eec68d7Srvb union outputArgs pbuf;
3312eec68d7Srvb
3322eec68d7Srvb /* get the rest of the data. */
3332eec68d7Srvb uiop->uio_rw = UIO_WRITE;
3346e030479Splunky error = uiomove(&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop);
3352eec68d7Srvb if (error) {
3362eec68d7Srvb myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n",
3372eec68d7Srvb error, opcode, seq));
3382eec68d7Srvb return(EINVAL);
3392eec68d7Srvb }
3402eec68d7Srvb
3412eec68d7Srvb return handleDownCall(opcode, &pbuf);
3422eec68d7Srvb }
3432eec68d7Srvb
3442eec68d7Srvb /* Look for the message on the (waiting for) reply queue. */
34572ac0bccSplunky TAILQ_FOREACH(vmp, &vcp->vc_replies, vm_chain) {
3462eec68d7Srvb if (vmp->vm_unique == seq) break;
3472eec68d7Srvb }
3482eec68d7Srvb
34972ac0bccSplunky if (vmp == NULL) {
3500aa47cd0Srvb if (codadebug)
3512eec68d7Srvb myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq));
3522eec68d7Srvb
3532eec68d7Srvb return(ESRCH);
3542eec68d7Srvb }
3552eec68d7Srvb
3562eec68d7Srvb /* Remove the message from the reply queue */
35772ac0bccSplunky TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
3582eec68d7Srvb
3592eec68d7Srvb /* move data into response buffer. */
3600aa47cd0Srvb out = (struct coda_out_hdr *)vmp->vm_data;
3612eec68d7Srvb /* Don't need to copy opcode and uniquifier. */
3622eec68d7Srvb
3632eec68d7Srvb /* get the rest of the data. */
3642eec68d7Srvb if (vmp->vm_outSize < uiop->uio_resid) {
3659aab9d33Smatt myprintf(("vcwrite: more data than asked for (%d < %lu)\n",
3669aab9d33Smatt vmp->vm_outSize, (unsigned long) uiop->uio_resid));
3672eec68d7Srvb wakeup(&vmp->vm_sleep); /* Notify caller of the error. */
3682eec68d7Srvb return(EINVAL);
3692eec68d7Srvb }
3702eec68d7Srvb
37181cb2a76Schristos tbuf[0] = uiop->uio_resid; /* Save this value. */
3722eec68d7Srvb uiop->uio_rw = UIO_WRITE;
3736e030479Splunky error = uiomove(&out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop);
3742eec68d7Srvb if (error) {
3752eec68d7Srvb myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n",
3762eec68d7Srvb error, opcode, seq));
3772eec68d7Srvb return(EINVAL);
3782eec68d7Srvb }
3792eec68d7Srvb
3802eec68d7Srvb /* I don't think these are used, but just in case. */
3812eec68d7Srvb /* XXX - aren't these two already correct? -bnoble */
3822eec68d7Srvb out->opcode = opcode;
3832eec68d7Srvb out->unique = seq;
38481cb2a76Schristos vmp->vm_outSize = tbuf[0]; /* Amount of data transferred? */
3852eec68d7Srvb vmp->vm_flags |= VM_WRITE;
3862eec68d7Srvb wakeup(&vmp->vm_sleep);
3872eec68d7Srvb
3882eec68d7Srvb return(0);
3892eec68d7Srvb }
3902eec68d7Srvb
3912eec68d7Srvb int
vc_nb_ioctl(dev_t dev,u_long cmd,void * addr,int flag,struct lwp * l)39253524e44Schristos vc_nb_ioctl(dev_t dev, u_long cmd, void *addr, int flag,
393168cd830Schristos struct lwp *l)
3942eec68d7Srvb {
3952eec68d7Srvb ENTRY;
3962eec68d7Srvb
3972eec68d7Srvb switch (cmd) {
3980aa47cd0Srvb case CODARESIZE: {
3990aa47cd0Srvb struct coda_resize *data = (struct coda_resize *)addr;
4000aa47cd0Srvb return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL));
4012eec68d7Srvb break;
4022eec68d7Srvb }
4030aa47cd0Srvb case CODASTATS:
4040aa47cd0Srvb if (coda_nc_use) {
4050aa47cd0Srvb coda_nc_gather_stats();
4062eec68d7Srvb return(0);
4072eec68d7Srvb } else {
4082eec68d7Srvb return(ENODEV);
4092eec68d7Srvb }
4102eec68d7Srvb break;
4110aa47cd0Srvb case CODAPRINT:
4120aa47cd0Srvb if (coda_nc_use) {
4130aa47cd0Srvb print_coda_nc();
4142eec68d7Srvb return(0);
4152eec68d7Srvb } else {
4162eec68d7Srvb return(ENODEV);
4172eec68d7Srvb }
4182eec68d7Srvb break;
419b951d6c0Srvb case CIOC_KERNEL_VERSION:
420b951d6c0Srvb switch (*(u_int *)addr) {
421b951d6c0Srvb case 0:
422b951d6c0Srvb *(u_int *)addr = coda_kernel_version;
423b951d6c0Srvb return 0;
424b951d6c0Srvb break;
425b951d6c0Srvb case 1:
426b951d6c0Srvb case 2:
427b951d6c0Srvb if (coda_kernel_version != *(u_int *)addr)
428b951d6c0Srvb return ENOENT;
429b951d6c0Srvb else
430b951d6c0Srvb return 0;
431b951d6c0Srvb default:
432b951d6c0Srvb return ENOENT;
433b951d6c0Srvb }
434b951d6c0Srvb break;
4352eec68d7Srvb default :
4362eec68d7Srvb return(EINVAL);
4372eec68d7Srvb break;
4382eec68d7Srvb }
4392eec68d7Srvb }
4402eec68d7Srvb
4412eec68d7Srvb int
vc_nb_poll(dev_t dev,int events,struct lwp * l)44295e1ffb1Schristos vc_nb_poll(dev_t dev, int events, struct lwp *l)
4432eec68d7Srvb {
444a82aeb55Saugustss struct vcomm *vcp;
4452eec68d7Srvb int event_msk = 0;
4462eec68d7Srvb
4472eec68d7Srvb ENTRY;
4482eec68d7Srvb
449461a86f9Schristos if (minor(dev) >= NVCODA)
4502eec68d7Srvb return(ENXIO);
4512eec68d7Srvb
4520aa47cd0Srvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
4532eec68d7Srvb
4542eec68d7Srvb event_msk = events & (POLLIN|POLLRDNORM);
4552eec68d7Srvb if (!event_msk)
4562eec68d7Srvb return(0);
4572eec68d7Srvb
45872ac0bccSplunky if (!TAILQ_EMPTY(&vcp->vc_requests))
4592eec68d7Srvb return(events & (POLLIN|POLLRDNORM));
4602eec68d7Srvb
46195e1ffb1Schristos selrecord(l, &(vcp->vc_selproc));
4622eec68d7Srvb
4632eec68d7Srvb return(0);
4642eec68d7Srvb }
4652eec68d7Srvb
466e0cc03a0Sjdolecek static void
filt_vc_nb_detach(struct knote * kn)467e0cc03a0Sjdolecek filt_vc_nb_detach(struct knote *kn)
468e0cc03a0Sjdolecek {
469e0cc03a0Sjdolecek struct vcomm *vcp = kn->kn_hook;
470e0cc03a0Sjdolecek
4711c3a0558Sthorpej selremove_knote(&vcp->vc_selproc, kn);
472e0cc03a0Sjdolecek }
473e0cc03a0Sjdolecek
474e0cc03a0Sjdolecek static int
filt_vc_nb_read(struct knote * kn,long hint)475168cd830Schristos filt_vc_nb_read(struct knote *kn, long hint)
476e0cc03a0Sjdolecek {
477e0cc03a0Sjdolecek struct vcomm *vcp = kn->kn_hook;
478e0cc03a0Sjdolecek struct vmsg *vmp;
479e0cc03a0Sjdolecek
48072ac0bccSplunky vmp = TAILQ_FIRST(&vcp->vc_requests);
48172ac0bccSplunky if (vmp == NULL)
482e0cc03a0Sjdolecek return (0);
483e0cc03a0Sjdolecek
484e0cc03a0Sjdolecek kn->kn_data = vmp->vm_inSize;
485e0cc03a0Sjdolecek return (1);
486e0cc03a0Sjdolecek }
487e0cc03a0Sjdolecek
48818b796d4Smaya static const struct filterops vc_nb_read_filtops = {
48912ae65d9Sthorpej .f_flags = FILTEROP_ISFD,
49018b796d4Smaya .f_attach = NULL,
49118b796d4Smaya .f_detach = filt_vc_nb_detach,
49218b796d4Smaya .f_event = filt_vc_nb_read,
49318b796d4Smaya };
494e0cc03a0Sjdolecek
495e0cc03a0Sjdolecek int
vc_nb_kqfilter(dev_t dev,struct knote * kn)496e0cc03a0Sjdolecek vc_nb_kqfilter(dev_t dev, struct knote *kn)
497e0cc03a0Sjdolecek {
498e0cc03a0Sjdolecek struct vcomm *vcp;
499e0cc03a0Sjdolecek
500e0cc03a0Sjdolecek ENTRY;
501e0cc03a0Sjdolecek
502461a86f9Schristos if (minor(dev) >= NVCODA)
503e0cc03a0Sjdolecek return(ENXIO);
504e0cc03a0Sjdolecek
505e0cc03a0Sjdolecek vcp = &coda_mnttbl[minor(dev)].mi_vcomm;
506e0cc03a0Sjdolecek
507e0cc03a0Sjdolecek switch (kn->kn_filter) {
508e0cc03a0Sjdolecek case EVFILT_READ:
509e0cc03a0Sjdolecek kn->kn_fop = &vc_nb_read_filtops;
510e0cc03a0Sjdolecek break;
511e0cc03a0Sjdolecek
512e0cc03a0Sjdolecek default:
5134e38160dSpooka return (EINVAL);
514e0cc03a0Sjdolecek }
515e0cc03a0Sjdolecek
516e0cc03a0Sjdolecek kn->kn_hook = vcp;
517e0cc03a0Sjdolecek
5181c3a0558Sthorpej selrecord_knote(&vcp->vc_selproc, kn);
519e0cc03a0Sjdolecek
520e0cc03a0Sjdolecek return (0);
521e0cc03a0Sjdolecek }
522e0cc03a0Sjdolecek
5232eec68d7Srvb /*
5242eec68d7Srvb * Statistics
5252eec68d7Srvb */
5260aa47cd0Srvb struct coda_clstat coda_clstat;
5272eec68d7Srvb
5282eec68d7Srvb /*
5297e681f70Swiz * Key question: whether to sleep interruptably or uninterruptably when
5302eec68d7Srvb * waiting for Venus. The former seems better (cause you can ^C a
5312eec68d7Srvb * job), but then GNU-EMACS completion breaks. Use tsleep with no
5322eec68d7Srvb * timeout, and no longjmp happens. But, when sleeping
5332eec68d7Srvb * "uninterruptibly", we don't get told if it returns abnormally
5342eec68d7Srvb * (e.g. kill -9).
5352eec68d7Srvb */
5362eec68d7Srvb
5372eec68d7Srvb int
coda_call(struct coda_mntinfo * mntinfo,int inSize,int * outSize,void * buffer)538323d4b7aSxtraeme coda_call(struct coda_mntinfo *mntinfo, int inSize, int *outSize,
53953524e44Schristos void *buffer)
5402eec68d7Srvb {
5412eec68d7Srvb struct vcomm *vcp;
5422eec68d7Srvb struct vmsg *vmp;
5432eec68d7Srvb int error;
5442eec68d7Srvb #ifdef CTL_C
54595e1ffb1Schristos struct lwp *l = curlwp;
54695e1ffb1Schristos struct proc *p = l->l_proc;
5479187d280Srvb sigset_t psig_omask;
5482eec68d7Srvb int i;
549b07ec3fcSad psig_omask = l->l_sigmask; /* XXXSA */
5502eec68d7Srvb #endif
5512eec68d7Srvb if (mntinfo == NULL) {
5522eec68d7Srvb /* Unlikely, but could be a race condition with a dying warden */
5532eec68d7Srvb return ENODEV;
5542eec68d7Srvb }
5552eec68d7Srvb
5562eec68d7Srvb vcp = &(mntinfo->mi_vcomm);
5572eec68d7Srvb
5580aa47cd0Srvb coda_clstat.ncalls++;
5590aa47cd0Srvb coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++;
5602eec68d7Srvb
5612eec68d7Srvb if (!VC_OPEN(vcp))
5622eec68d7Srvb return(ENODEV);
5632eec68d7Srvb
5640aa47cd0Srvb CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg));
5652eec68d7Srvb /* Format the request message. */
5662eec68d7Srvb vmp->vm_data = buffer;
5672eec68d7Srvb vmp->vm_flags = 0;
5682eec68d7Srvb vmp->vm_inSize = inSize;
5692eec68d7Srvb vmp->vm_outSize
5702eec68d7Srvb = *outSize ? *outSize : inSize; /* |buffer| >= inSize */
5710aa47cd0Srvb vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode;
5722eec68d7Srvb vmp->vm_unique = ++vcp->vc_seq;
5730aa47cd0Srvb if (codadebug)
5742eec68d7Srvb myprintf(("Doing a call for %d.%d\n",
5752eec68d7Srvb vmp->vm_opcode, vmp->vm_unique));
5762eec68d7Srvb
5772eec68d7Srvb /* Fill in the common input args. */
5780aa47cd0Srvb ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique;
5792eec68d7Srvb
5802eec68d7Srvb /* Append msg to request queue and poke Venus. */
58172ac0bccSplunky TAILQ_INSERT_TAIL(&vcp->vc_requests, vmp, vm_chain);
582c6186facSrmind selnotify(&(vcp->vc_selproc), 0, 0);
5832eec68d7Srvb
5842eec68d7Srvb /* We can be interrupted while we wait for Venus to process
5852eec68d7Srvb * our request. If the interrupt occurs before Venus has read
5862eec68d7Srvb * the request, we dequeue and return. If it occurs after the
5872eec68d7Srvb * read but before the reply, we dequeue, send a signal
5882eec68d7Srvb * message, and return. If it occurs after the reply we ignore
5892eec68d7Srvb * it. In no case do we want to restart the syscall. If it
5902eec68d7Srvb * was interrupted by a venus shutdown (vcclose), return
5912eec68d7Srvb * ENODEV. */
5922eec68d7Srvb
5932eec68d7Srvb /* Ignore return, We have to check anyway */
5942eec68d7Srvb #ifdef CTL_C
5950aa47cd0Srvb /* This is work in progress. Setting coda_pcatch lets tsleep reawaken
5962eec68d7Srvb on a ^c or ^z. The problem is that emacs sets certain interrupts
5972eec68d7Srvb as SA_RESTART. This means that we should exit sleep handle the
5982eec68d7Srvb "signal" and then go to sleep again. Mostly this is done by letting
5992eec68d7Srvb the syscall complete and be restarted. We are not idempotent and
6002eec68d7Srvb can not do this. A better solution is necessary.
6012eec68d7Srvb */
6022eec68d7Srvb i = 0;
6032eec68d7Srvb do {
6040aa47cd0Srvb error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2);
6052eec68d7Srvb if (error == 0)
6062eec68d7Srvb break;
607284c2b9aSad mutex_enter(p->p_lock);
608b07ec3fcSad if (error == EWOULDBLOCK) {
609976280c9Srvb #ifdef CODA_VERBOSE
6100aa47cd0Srvb printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i);
611c559082bSrvb #endif
612b07ec3fcSad } else if (sigispending(l, SIGIO)) {
613b07ec3fcSad sigaddset(&l->l_sigmask, SIGIO);
614976280c9Srvb #ifdef CODA_VERBOSE
6150aa47cd0Srvb printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i);
616c559082bSrvb #endif
617b07ec3fcSad } else if (sigispending(l, SIGALRM)) {
618b07ec3fcSad sigaddset(&l->l_sigmask, SIGALRM);
619e7f0c598Srvb #ifdef CODA_VERBOSE
620e7f0c598Srvb printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i);
621e7f0c598Srvb #endif
6222eec68d7Srvb } else {
6239187d280Srvb sigset_t tmp;
624b07ec3fcSad tmp = p->p_sigpend.sp_set; /* array assignment */
625b07ec3fcSad sigminusset(&l->l_sigmask, &tmp);
6269187d280Srvb
627976280c9Srvb #ifdef CODA_VERBOSE
6280aa47cd0Srvb printf("coda_call: tsleep returns %d, cnt %d\n", error, i);
6299187d280Srvb printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n",
630b07ec3fcSad p->p_sigpend.sp_set.__bits[0], p->p_sigpend.sp_set.__bits[1],
631b07ec3fcSad p->p_sigpend.sp_set.__bits[2], p->p_sigpend.sp_set.__bits[3],
632b07ec3fcSad l->l_sigmask.__bits[0], l->l_sigmask.__bits[1],
633b07ec3fcSad l->l_sigmask.__bits[2], l->l_sigmask.__bits[3],
6349187d280Srvb tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]);
635c559082bSrvb #endif
636284c2b9aSad mutex_exit(p->p_lock);
6372eec68d7Srvb break;
638c559082bSrvb #ifdef notyet
639b07ec3fcSad sigminusset(&l->l_sigmask, &p->p_sigpend.sp_set);
6409187d280Srvb printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n",
641b07ec3fcSad p->p_sigpend.sp_set.__bits[0], p->p_sigpend.sp_set.__bits[1],
642b07ec3fcSad p->p_sigpend.sp_set.__bits[2], p->p_sigpend.sp_set.__bits[3],
643b07ec3fcSad l->l_sigmask.__bits[0], l->l_sigmask.__bits[1],
644b07ec3fcSad l->l_sigmask.__bits[2], l->l_sigmask.__bits[3]);
645c559082bSrvb #endif
6462eec68d7Srvb }
647284c2b9aSad mutex_exit(p->p_lock);
648e7f0c598Srvb } while (error && i++ < 128 && VC_OPEN(vcp));
649b07ec3fcSad l->l_sigmask = psig_omask; /* XXXSA */
6502eec68d7Srvb #else
6510aa47cd0Srvb (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0);
6522eec68d7Srvb #endif
6532eec68d7Srvb if (VC_OPEN(vcp)) { /* Venus is still alive */
6542eec68d7Srvb /* Op went through, interrupt or not... */
6552eec68d7Srvb if (vmp->vm_flags & VM_WRITE) {
6562eec68d7Srvb error = 0;
6572eec68d7Srvb *outSize = vmp->vm_outSize;
6582eec68d7Srvb }
6592eec68d7Srvb
6602eec68d7Srvb else if (!(vmp->vm_flags & VM_READ)) {
6612eec68d7Srvb /* Interrupted before venus read it. */
662976280c9Srvb #ifdef CODA_VERBOSE
663976280c9Srvb if (1)
664976280c9Srvb #else
665c559082bSrvb if (codadebug)
666c559082bSrvb #endif
6672eec68d7Srvb myprintf(("interrupted before read: op = %d.%d, flags = %x\n",
6682eec68d7Srvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
66972ac0bccSplunky
67072ac0bccSplunky TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain);
6712eec68d7Srvb error = EINTR;
6722eec68d7Srvb }
6732eec68d7Srvb
6742eec68d7Srvb else {
6752eec68d7Srvb /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after
6762eec68d7Srvb upcall started */
6772eec68d7Srvb /* Interrupted after start of upcall, send venus a signal */
6780aa47cd0Srvb struct coda_in_hdr *dog;
6792eec68d7Srvb struct vmsg *svmp;
6802eec68d7Srvb
681976280c9Srvb #ifdef CODA_VERBOSE
682976280c9Srvb if (1)
683976280c9Srvb #else
684c559082bSrvb if (codadebug)
685c559082bSrvb #endif
6862eec68d7Srvb myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n",
6872eec68d7Srvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
6882eec68d7Srvb
68972ac0bccSplunky TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain);
6902eec68d7Srvb error = EINTR;
6912eec68d7Srvb
6920aa47cd0Srvb CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg));
6932eec68d7Srvb
6940aa47cd0Srvb CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr));
6950aa47cd0Srvb dog = (struct coda_in_hdr *)svmp->vm_data;
6962eec68d7Srvb
6972eec68d7Srvb svmp->vm_flags = 0;
6980aa47cd0Srvb dog->opcode = svmp->vm_opcode = CODA_SIGNAL;
6992eec68d7Srvb dog->unique = svmp->vm_unique = vmp->vm_unique;
7000aa47cd0Srvb svmp->vm_inSize = sizeof (struct coda_in_hdr);
7010aa47cd0Srvb /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr);
7022eec68d7Srvb
7030aa47cd0Srvb if (codadebug)
70427b381f4Sandvar myprintf(("coda_call: enqueuing signal msg (%d, %d)\n",
7052eec68d7Srvb svmp->vm_opcode, svmp->vm_unique));
7062eec68d7Srvb
707755dfb4fSplunky /* insert at head of queue */
708755dfb4fSplunky TAILQ_INSERT_HEAD(&vcp->vc_requests, svmp, vm_chain);
709c6186facSrmind selnotify(&(vcp->vc_selproc), 0, 0);
7102eec68d7Srvb }
7112eec68d7Srvb }
7122eec68d7Srvb
7132eec68d7Srvb else { /* If venus died (!VC_OPEN(vcp)) */
714b8743242Srin if (codadebug) {
7152eec68d7Srvb myprintf(("vcclose woke op %d.%d flags %d\n",
7162eec68d7Srvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags));
717b8743242Srin }
7182eec68d7Srvb
7192eec68d7Srvb error = ENODEV;
7202eec68d7Srvb }
7212eec68d7Srvb
7220aa47cd0Srvb CODA_FREE(vmp, sizeof(struct vmsg));
7232eec68d7Srvb
724e7f0c598Srvb if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0))
725e7f0c598Srvb wakeup(&outstanding_upcalls);
726e7f0c598Srvb
7272eec68d7Srvb if (!error)
7280aa47cd0Srvb error = ((struct coda_out_hdr *)buffer)->result;
7292eec68d7Srvb return(error);
7302eec68d7Srvb }
7319187d280Srvb
732704aca39Schristos MODULE(MODULE_CLASS_DRIVER, vcoda, NULL);
733704aca39Schristos
734704aca39Schristos static int
vcoda_modcmd(modcmd_t cmd,void * arg)735704aca39Schristos vcoda_modcmd(modcmd_t cmd, void *arg)
736704aca39Schristos {
737289bc9f7Schristos int error = 0;
738704aca39Schristos
739704aca39Schristos switch (cmd) {
740704aca39Schristos case MODULE_CMD_INIT:
741704aca39Schristos #ifdef _MODULE
74265fba946Sriz {
743289bc9f7Schristos int cmajor, dmajor;
744704aca39Schristos vcodaattach(NVCODA);
745704aca39Schristos
746289bc9f7Schristos dmajor = cmajor = -1;
747704aca39Schristos return devsw_attach("vcoda", NULL, &dmajor,
748704aca39Schristos &vcoda_cdevsw, &cmajor);
74965fba946Sriz }
750704aca39Schristos #endif
751704aca39Schristos break;
752704aca39Schristos
753704aca39Schristos case MODULE_CMD_FINI:
754704aca39Schristos #ifdef _MODULE
755704aca39Schristos {
756704aca39Schristos for (size_t i = 0; i < NVCODA; i++) {
757704aca39Schristos struct vcomm *vcp = &coda_mnttbl[i].mi_vcomm;
758704aca39Schristos if (VC_OPEN(vcp))
759704aca39Schristos return EBUSY;
760704aca39Schristos }
761e7bed289Sriastradh devsw_detach(NULL, &vcoda_cdevsw);
762704aca39Schristos }
763704aca39Schristos #endif
764704aca39Schristos break;
765704aca39Schristos
766704aca39Schristos case MODULE_CMD_STAT:
767704aca39Schristos return ENOTTY;
768704aca39Schristos
769704aca39Schristos default:
770704aca39Schristos return ENOTTY;
771704aca39Schristos }
772704aca39Schristos return error;
773704aca39Schristos }
774