Subject: kern/6060: clone device-driver
To: None <gnats-bugs@gnats.netbsd.org>
From: Stefan Grefen <grefen@hprc.tandem.com>
List: netbsd-bugs
Date: 08/27/1998 23:35:28
>Number: 6060
>Category: kern
>Synopsis: clone device missing :-)
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Thu Aug 27 15:05:01 1998
>Last-Modified:
>Originator: Stefan Grefen
>Organization:
Stefan Grefen Tandem Computers Europe Inc.
grefen@hprc.tandem.com High Performance Research Center
--- Hacking's just another word for nothing left to kludge. ---
>Release: 27.9.1998<NetBSD-current source date>
>Environment:
System: NetBSD hicks 1.3G NetBSD 1.3G (CPQ) #41: Thu Aug 27 21:21:52 CEST 1998 grefen@hicks:/usr/src/sys/arch/i386/compile/CPQ i386
>Description:
Clone device driver and cloneing ability for all devices
>How-To-Repeat:
>Fix:
*** /usr/sup/src/sys/conf/files Sun Aug 23 13:14:01 1998
--- /usr/src/sys/conf/files Thu Aug 27 18:36:39 1998
***************
*** 341,346 ****
--- 341,348 ----
pseudo-device sequencer
+ pseudo-device clonedev
+
# kernel sources
file adosfs/adlookup.c adosfs
file adosfs/adutil.c adosfs
***************
*** 384,389 ****
--- 386,393 ----
file dev/rndpool.c rnd needs-flag
file dev/i2c/i2c_bus.c i2c
file dev/i2c/i2c_eeprom.c i2c_eeprom
+ file dev/clone_dev.c clonedev
+ file dev/clone_subr.c clone
file filecorefs/filecore_bmap.c filecore
file filecorefs/filecore_lookup.c filecore
file filecorefs/filecore_node.c filecore
*** /dev/null Thu Aug 27 21:30:28 1998
--- /usr/src/sys/dev/clone.h Thu Aug 27 18:50:11 1998
***************
*** 0 ****
--- 1,61 ----
+ /* $NetBSD: clone.h,v 1.16 1997/05/28 02:44:57 grefen Exp $ */
+
+ /*
+ * Header file used by clone device driver & clients
+ *
+ * Copyright (c) 1997,1998 Stefan Grefen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Terrence R. Lambert.
+ * 4. The name Terrence R. Lambert may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+ #ifndef __SYS_CLONE_
+ #define __SYS_CLONE_
+
+ #ifdef __NetBSD__
+ #ifndef CLONE_DEV
+ /*
+ * Last of LKM's until we get an official one
+ */
+ #define CLONE_DEV 34
+ #endif
+ #endif
+
+ #ifndef VISCLONE
+ typedef int (*cl_open)(dev_t, int, int, struct proc *, dev_t *);
+
+
+ int open_clone(dev_t dev, int flags, int type, struct proc *p,cl_open cl_open,
+ dev_t *newminorp);
+ #endif
+
+ int clone_get_minor __P((u_int maj,u_int start));
+ void clone_free_minor __P((dev_t dev));
+ int clone_init_minors __P((void));
+
+ #endif
*** /dev/null Thu Aug 27 21:30:28 1998
--- /usr/src/sys/dev/clone_subr.c Thu Aug 27 18:56:04 1998
***************
*** 0 ****
--- 1,276 ----
+ /*
+ *
+ * Copyright (c) 1996, 1997, 1998 Stefan Grefen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+ #include <sys/param.h>
+ #include <sys/filedesc.h>
+ #include <sys/kernel.h>
+ #include <sys/malloc.h>
+ #include <sys/systm.h>
+ #include <sys/buf.h>
+ #include <sys/ioctl.h>
+ #include <sys/errno.h>
+ #include <sys/syslog.h>
+ #include <sys/device.h>
+ #include <sys/proc.h>
+ #include <sys/conf.h>
+ #include <sys/mount.h>
+ #include <sys/vnode.h>
+ #include <sys/stat.h>
+ #include <sys/file.h>
+
+
+ #include <dev/clone.h>
+ #include <machine/cpu.h>
+
+ #ifdef CLONE_DEBUG
+ #define DPRINTF(a) printf a
+ #else
+ #define DPRINTF(a)
+ #endif
+
+ /*
+ * Helper for the clone device
+ * This keeps a map of allocated minor number so we don't have
+ * to retry them all the time
+ */
+
+ #define NBITS (sizeof(unsigned int)*NBBY)
+ #define NFIELD (1024/NBITS)
+
+ struct min_map {
+ struct min_map *next;
+ int start;
+ unsigned int bits[NFIELD];
+ } **dev_min_map = NULL;
+
+ #ifdef __bsdi__
+ #define MAXDEV ndevsw
+ #endif
+
+ #if (defined __NetBSD__)
+ #define MAXDEV nchrdev
+ #endif
+
+
+
+ /*
+ * Common attach function
+ */
+
+ int
+ clone_init_minors() {
+
+ if(dev_min_map != NULL) {
+ return 0;
+ }
+
+ dev_min_map=malloc(MAXDEV*sizeof(struct min_map *),M_DEVBUF, M_NOWAIT);
+
+ if(dev_min_map==NULL) {
+ return ENOMEM;
+ }
+
+ bzero(dev_min_map,MAXDEV*sizeof(struct min_map *));
+
+ return 0;
+ }
+
+ /*
+ * The real stuff starts here ..
+ */
+
+ /*
+ * Allocate a minor number without trying each minor number.
+ * Still have to check as the device may have been opend without
+ * going through the clone code
+ */
+ int
+ clone_get_minor(u_int maj,u_int start) {
+ int ms=0;
+ int ret=-1;
+ struct min_map *m,**mp;
+
+ mp=&dev_min_map[maj];
+
+ while(ret==-1) {
+ while((m=*mp) && (m->start+NBITS*NFIELD)<=start) mp=&(m->next);
+ while((m=*mp)!=NULL) {
+ int i = 0;
+ unsigned int *ip=&(m->bits[0]);
+ ms=m->start;
+ for(i=0;i<NFIELD && ret==-1;i++) {
+ if(*ip == ~0 || ms+NBITS<=start) {
+ ip++;
+ ms+=NBITS;
+ if(start && start-ms<0)
+ start=0;
+ } else {
+ unsigned int bits=~(*ip);
+ if(start>=ms) {
+ start-=ms;
+ }
+ if(start) {
+ bits&=~((1<<start)-1);
+ }
+ ret=bits&(-bits);
+ *ip|=ret;
+ ret=ms+(ffs(ret)-1);
+ return ret;
+ }
+ }
+ mp=&m->next;
+ }
+ if((m=*mp)==NULL) {
+ *mp=malloc(sizeof(struct min_map),M_DEVBUF, M_NOWAIT);
+ if((m=*mp)==NULL) {
+ break;
+ }
+ m->start=ms;
+ m->next=NULL;
+ bzero(m->bits,sizeof(m->bits));
+ }
+ }
+ return ret;
+ };
+
+ void
+ clone_free_minor(dev_t dev) {
+ struct min_map *m;
+ unsigned int *ip,ms;
+ int major=major(dev),minor=minor(dev);
+
+ if(major<MAXDEV) {
+ m=dev_min_map[major];
+ while(m && (m->start+NBITS*NFIELD)<=minor) { m=m->next; }
+ if(m) {
+ ip=m->bits;
+ ms=m->start;
+ while(ms+NBITS<=minor) { ip++; ms+=NBITS; }
+ *ip&=~(1<<(minor-ms));
+ }
+ }
+
+
+ #ifdef _LKM
+ /*
+ * In case of an LKM unload waiting for the last clone to
+ * close
+ *
+ * This safe because:
+ * clone_cleanup will never be called in an interrupt
+ * clone_free_minor is also not called in an interrupt
+ */
+ if(clone_draining) {
+ int s=splhigh();
+ wakeup(&cln_ready);
+ clone_draining = 0;
+ splx(s);
+ }
+ #endif
+ }
+
+ #ifndef VISCLONE
+
+ /*
+ * Not a clone enabled specfs
+ */
+
+ int
+ clone_dev_cloned(dev_t dev) {
+ struct min_map *m;
+ unsigned int *ip,ms;
+ int major=major(dev),minor=minor(dev);
+
+ if(major<MAXDEV) {
+ m=dev_min_map[major];
+ while(m && (m->start+NBITS*NFIELD)<=minor) { m=m->next; }
+ if(m) {
+ ip=m->bits;
+ ms=m->start;
+ while(ms+NBITS<=minor) { ip++; ms+=NBITS; }
+ return *ip&(1<<(minor-ms));
+ }
+ }
+ return 0;
+ }
+ #endif
+
+ #ifdef _LKM
+ int
+ clone_cleanup( int wait ) {
+ int i;
+ int used=0;
+
+ wait=wait?1:0;
+
+ do {
+
+ clone_draining=1;
+
+ for(i=0;i<MAXDEV;i++) {
+ struct min_map *m,**mp;
+ mp=&dev_min_map[i];
+ while((m=*mp)!=NULL) {
+ int j;
+ for(j=0;j<NFIELD;j++) {
+ if(m->bits[j]) {
+ used=1;
+ break;
+ }
+ }
+ if(j>=NBITS) {
+ *mp=m->next;
+ free(m,M_DEVBUF);
+ } else {
+ mp=&m->next;
+ }
+ }
+ }
+ if (wait && used) {
+ int s=splhigh();
+ int error=0;
+
+ /*
+ * rescan if list has changed
+ */
+
+ if(clone_draining) {
+ error=tsleep(&cln_ready,PZERO|PCATCH,"cln-cleanup",5*hz);
+ if (error == 0) {
+ wait=0; /* abort */
+ }
+ }
+ splx(s);
+ }
+ } while(wait && used);
+ return used;
+ }
+ #endif
+
*** /dev/null Thu Aug 27 21:30:28 1998
--- /usr/src/sys/dev/clone_dev.c Thu Aug 27 20:48:19 1998
***************
*** 0 ****
--- 1,110 ----
+ /*
+ *
+ * Copyright (c) 1996, 1997, 1998 Stefan Grefen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+ #include <sys/param.h>
+ #include <sys/kernel.h>
+ #include <sys/malloc.h>
+ #include <sys/systm.h>
+ #include <sys/errno.h>
+ #include <sys/device.h>
+ #include <sys/proc.h>
+ #include <sys/conf.h>
+ #include <sys/file.h>
+ #include <sys/vnode.h>
+
+
+ /*
+ * Safeguard
+ */
+ #ifndef VISCLONE
+ #error "Can't use clone dev without specfs support (maybe option CLONE is missing?)"
+ #endif
+
+ #define CLONE_DEV 61
+
+ #include <dev/clone.h>
+
+ #include <machine/cpu.h>
+
+ #ifdef CLONE_DEBUG
+ #define DPRINTF(a) printf a
+ #else
+ #define DPRINTF(a)
+ #endif
+
+ /*
+ * If specfs is compiled with clone support,
+ * the clone device has to be configured also
+ */
+
+ static int clone_open(dev_t, int, int, struct proc *,dev_t *);
+
+ void clonedevattach(int num);
+
+ static int cln_ready=0;
+
+ /*
+ * NetBSD device config
+ */
+ struct cdevsw clonesw = {
+ (dev_type_open((*))) clone_open,(dev_type_close((*))) enodev,
+ (dev_type_read((*))) enodev, (dev_type_write((*))) enodev,
+ (dev_type_ioctl((*))) enodev, (dev_type_stop((*))) enodev,
+ 0, seltrue, (dev_type_mmap((*))) enodev };
+ #define MAXDEV nchrdev
+
+ /*
+ * Common attach function
+ */
+
+ void
+ clonedevattach(int num) {
+ if (clone_init_minors() != 0 )
+ return;
+
+ /*
+ * Until we get an official place
+ * hack it into the CLONE_DEV as lkm would do ...
+ */
+ bcopy(&clonesw,&cdevsw[CLONE_DEV],sizeof(clonesw));
+
+ cln_ready=1;
+
+ return;
+ }
+
+ int
+ clone_open(dev_t dev, int flag, int type, struct proc *p, dev_t *devp) {
+ if (major(dev) == minor(dev) || devp == NULL )
+ return ENXIO;
+ *devp=makedev(minor(dev),minor(~0));
+ return 0;
+ }
+
*** /usr/sup/src/sys/sys/vnode.h Fri Aug 14 13:14:10 1998
--- /usr/src/sys/sys/vnode.h Thu Aug 27 17:12:10 1998
***************
*** 146,151 ****
--- 146,154 ----
#define VBWAIT 0x0400 /* waiting for output to complete */
#define VALIASED 0x0800 /* vnode has an alias */
#define VDIROP 0x1000 /* LFS: vnode is involved in a directory op */
+ #if (!defined _KERNEL) || (defined CLONE)
+ #define VISCLONE 0x2000 /* specfs: vnode is a cloned device */
+ #endif
/*
* Vnode attributes. A field value of VNOVAL represents a field whose value
*** /dev/null Thu Aug 27 21:30:28 1998
--- /usr/src/share/man/man4/clone.4 Thu Aug 27 22:56:16 1998
***************
*** 0 ****
--- 1,24 ----
+ .\"
+ .Dd Aug 19, 1998
+ .Dt CLONEDEV 4
+ .Os NetBSD 1.3G
+ .Sh NAME
+ .Nm clonedev
+ .Nd clone device support
+ .Sh SYNOPSIS
+ .Cd pseudo-device clonedev Op Ar count
+ .Sh DESCRIPTION
+ The
+ .Nm clonedev
+ device driver creates a virtual device, which opens an unused instance of
+ the device specified by its minor number.
+ .Pp
+ The count parameter in the config file is ignored.
+ .Pp
+ Assuming the
+ .Nm clone
+ major number is 61, the device 61/23 would open an unused instance of
+ /dev/bpf.
+ .Pp
+ .Xr intro 4
+ .Sh BUGS
*** /dev/null Thu Aug 27 21:30:28 1998
--- /usr/src/share/man/man9/clone.9 Thu Aug 27 22:58:17 1998
***************
*** 0 ****
--- 1,37 ----
+ .\"
+ .Dd Aug 19, 1998
+ .Dt CLONE 4
+ .Os NetBSD 1.3G
+ .Sh NAME
+ .Nm clone
+ .Nd clone device support
+ .Sh SYNOPSIS
+ .Cd option CLONE
+ .Sh DESCRIPTION
+ .Pp
+ Specifing this option changes the parameter to the
+ .Nm open
+ entry for a character device. An addtionial parameter, a pointer to
+ the dev parameter, is added.
+ If the additional argument is NULL this is a 'reopen' after a major or minor number change, this can't change the device again.
+ .Pp
+ Changing the device results in the creation of a clone device with the
+ specifed major/minor device numbers.
+ .Pp
+ The rules are:
+ .Bl -tag -width major(dev) == major(vp->v_rdev)
+ .It Dv dev == vp->v_rdev
+ not cloning continue as usual
+ .It Dv minor(dev) == minor(~0)
+ The clone code picks an used minor number
+ .It Dv minor(dev) != minor(~0)
+ minor number to use
+ .It Dv major(dev) == major(vp->v_rdev)
+ handle the minor number and contiune, no additional call to d_open
+ .It Dv major(dev) == 0
+ after handling the minor number call d_open for the device with the new
+ device-id
+ .It Dv major(dev) != major(vp->v_rdev)
+ New major number, will result in a call to d_open for the device with the new device-id, after the handling the minor number stuff
+ .Sh BUGS
+ simplelock code for alias handling missing.
>Audit-Trail:
>Unformatted: