summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/kern/spec_vnops.c96
1 files changed, 93 insertions, 3 deletions
diff --git a/sys/kern/spec_vnops.c b/sys/kern/spec_vnops.c
index faae895fb1f..46e94768ccf 100644
--- a/sys/kern/spec_vnops.c
+++ b/sys/kern/spec_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: spec_vnops.c,v 1.65 2011/07/04 17:12:53 nicm Exp $ */
+/* $OpenBSD: spec_vnops.c,v 1.66 2011/07/04 20:51:19 deraadt Exp $ */
/* $NetBSD: spec_vnops.c,v 1.29 1996/04/22 01:42:38 christos Exp $ */
/*
@@ -49,8 +49,8 @@
#include <sys/lockf.h>
#include <sys/poll.h>
#include <sys/dkio.h>
-
-#include <miscfs/specfs/specdev.h>
+#include <sys/malloc.h>
+#include <sys/specdev.h>
#define v_lastr v_specinfo->si_lastr
@@ -652,3 +652,93 @@ spec_badop(void *v)
panic("spec_badop called");
/* NOTREACHED */
}
+
+/*
+ * Copyright (c) 2006 Pedro Martelletto <pedro@ambientworks.net>
+ * 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.
+ */
+
+#ifdef CLONE_DEBUG
+#define DNPRINTF(m...) do { printf(m); } while (0)
+#else
+#define DNPRINTF(m...) /* nothing */
+#endif
+
+int
+spec_open_clone(struct vop_open_args *ap)
+{
+ struct vnode *cvp, *vp = ap->a_vp;
+ struct cloneinfo *cip;
+ int error, i;
+
+ DNPRINTF("cloning vnode\n");
+
+ 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); /* too many open instances */
+
+ 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); /* device open failed */
+ }
+
+ cvp->v_flag |= VCLONE;
+
+ 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;
+
+ DNPRINTF("clone of vnode %p is vnode %p\n", vp, cvp);
+
+ 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); /* device close failed */
+
+ pvp = vp->v_specparent; /* get parent device */
+ clrbit(pvp->v_specbitmap, minor(vp->v_rdev));
+ vrele(pvp);
+
+ return (0); /* clone closed */
+}