summaryrefslogtreecommitdiff
path: root/sys/miscfs/specfs
diff options
context:
space:
mode:
authorPedro Martelletto <pedro@cvs.openbsd.org>2006-06-02 20:25:10 +0000
committerPedro Martelletto <pedro@cvs.openbsd.org>2006-06-02 20:25:10 +0000
commit854e01c2288676f277db0e5828b69925f388839c (patch)
treed09bd3e60f26057cb57681c89a472ff67aca6d86 /sys/miscfs/specfs
parentd6614a5341f43974e48e8eb4eaa3799015def4bd (diff)
Add a clonable devices implementation. Hacked along with thib@, input
from krw@ and toby@, subliminal prodding from dlg@, okay deraadt@.
Diffstat (limited to 'sys/miscfs/specfs')
-rw-r--r--sys/miscfs/specfs/spec_subr.c95
-rw-r--r--sys/miscfs/specfs/spec_vnops.c6
-rw-r--r--sys/miscfs/specfs/specdev.h18
3 files changed, 117 insertions, 2 deletions
diff --git a/sys/miscfs/specfs/spec_subr.c b/sys/miscfs/specfs/spec_subr.c
new file mode 100644
index 00000000000..8cc38e4829f
--- /dev/null
+++ b/sys/miscfs/specfs/spec_subr.c
@@ -0,0 +1,95 @@
+/* $OpenBSD: spec_subr.c,v 1.1 2006/06/02 20:25:09 pedro Exp $ */
+
+/*
+ * Copyright (c) 2006 Pedro Martelletto <pedro@openbsd.org>
+ * Copyright (c) 2006 Thordur Bjornsson <thib@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+#include <sys/stat.h>
+
+#include <miscfs/specfs/specdev.h>
+
+int
+spec_open_clone(struct vop_open_args *ap)
+{
+ struct vnode *cvp, *vp = ap->a_vp;
+ struct cloneinfo *cip;
+ int error, i;
+
+ for (i = 1; i < sizeof(vp->v_specbitmap) * NBBY; i++)
+ if (isclr(vp->v_specbitmap, i)) {
+ setbit(vp->v_specbitmap, i);
+ break;
+ }
+
+ if (i == sizeof(vp->v_specbitmap) * NBBY)
+ return (EBUSY);
+
+ printf("spec_open_clone(): cloning device (%d, %d) for pid %u\n",
+ major(vp->v_rdev), minor(vp->v_rdev), curproc->p_pid);
+
+ error = cdevvp(makedev(major(vp->v_rdev), i), &cvp);
+ if (error)
+ return (error); /* out of vnodes */
+
+ VOP_UNLOCK(vp, 0, ap->a_p);
+
+ error = cdevsw[major(vp->v_rdev)].d_open(cvp->v_rdev, ap->a_mode,
+ S_IFCHR, ap->a_p);
+
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, ap->a_p);
+
+ if (error) {
+ clrbit(vp->v_specbitmap, i);
+ return (error);
+ }
+
+ cip = malloc(sizeof(struct cloneinfo), M_TEMP, M_WAITOK);
+ cip->ci_data = vp->v_data;
+ cip->ci_vp = cvp;
+
+ cvp->v_specparent = vp;
+ vp->v_flag |= VCLONED;
+ vp->v_data = cip;
+
+ printf("spec_open_clone(): new minor for cloned device is %d\n",
+ minor(cvp->v_rdev));
+
+ return (0); /* device cloned */
+}
+
+int
+spec_close_clone(struct vop_close_args *ap)
+{
+ struct vnode *pvp, *vp = ap->a_vp;
+ int error;
+
+ error = cdevsw[major(vp->v_rdev)].d_close(vp->v_rdev, ap->a_fflag,
+ S_IFCHR, ap->a_p);
+ if (error)
+ return (error);
+
+ pvp = vp->v_specparent; /* get parent device */
+ clrbit(pvp->v_specbitmap, minor(vp->v_rdev));
+
+ printf("spec_close_clone(): freeing minor %d of dev %d for"
+ " pid %u\n", minor(vp->v_rdev), major(vp->v_rdev), curproc->p_pid);
+
+ return (0);
+}
diff --git a/sys/miscfs/specfs/spec_vnops.c b/sys/miscfs/specfs/spec_vnops.c
index 1f3fe5db55f..6b5558c733f 100644
--- a/sys/miscfs/specfs/spec_vnops.c
+++ b/sys/miscfs/specfs/spec_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: spec_vnops.c,v 1.33 2006/03/05 21:48:56 miod Exp $ */
+/* $OpenBSD: spec_vnops.c,v 1.34 2006/06/02 20:25:09 pedro Exp $ */
/* $NetBSD: spec_vnops.c,v 1.29 1996/04/22 01:42:38 christos Exp $ */
/*
@@ -191,6 +191,8 @@ spec_open(v)
}
if (cdevsw[maj].d_type == D_TTY)
vp->v_flag |= VISTTY;
+ if (cdevsw[maj].d_flags & D_CLONE)
+ return (spec_open_clone(ap));
VOP_UNLOCK(vp, 0, p);
error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, ap->a_p);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
@@ -624,6 +626,8 @@ spec_close(v)
*/
if (vcount(vp) > 1 && (vp->v_flag & VXLOCK) == 0)
return (0);
+ if (cdevsw[major(dev)].d_flags & D_CLONE)
+ return (spec_close_clone(ap));
devclose = cdevsw[major(dev)].d_close;
mode = S_IFCHR;
break;
diff --git a/sys/miscfs/specfs/specdev.h b/sys/miscfs/specfs/specdev.h
index bb95a71025d..8fc18c628b5 100644
--- a/sys/miscfs/specfs/specdev.h
+++ b/sys/miscfs/specfs/specdev.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: specdev.h,v 1.17 2003/09/23 16:51:13 millert Exp $ */
+/* $OpenBSD: specdev.h,v 1.18 2006/06/02 20:25:09 pedro Exp $ */
/* $NetBSD: specdev.h,v 1.12 1996/02/13 13:13:01 mycroft Exp $ */
/*
@@ -44,7 +44,17 @@ struct specinfo {
dev_t si_rdev;
struct lockf *si_lockf;
daddr_t si_lastr;
+ union {
+ struct vnode *ci_parent; /* pointer back to parent device */
+ u_int8_t ci_bitmap[8]; /* bitmap of devices cloned off us */
+ } si_ci;
};
+
+struct cloneinfo {
+ struct vnode *ci_vp; /* cloned vnode */
+ void *ci_data; /* original vnode's v_data */
+};
+
/*
* Exported shorthand
*/
@@ -53,6 +63,8 @@ struct specinfo {
#define v_specnext v_specinfo->si_specnext
#define v_specmountpoint v_specinfo->si_mountpoint
#define v_speclockf v_specinfo->si_lockf
+#define v_specparent v_specinfo->si_ci.ci_parent
+#define v_specbitmap v_specinfo->si_ci.ci_bitmap
/*
* Special device management
@@ -119,3 +131,7 @@ int spec_advlock(void *);
#define spec_revoke vop_generic_revoke
int spec_vnoperate(void *);
+
+/* spec_subr.c */
+int spec_open_clone(struct vop_open_args *);
+int spec_close_clone(struct vop_close_args *);