From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1DgxFP-0000E4-61 for qemu-devel@nongnu.org; Sat, 11 Jun 2005 00:05:28 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1DgxFC-00006T-AS for qemu-devel@nongnu.org; Sat, 11 Jun 2005 00:05:14 -0400 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1DgxFC-0008RK-4A for qemu-devel@nongnu.org; Sat, 11 Jun 2005 00:05:14 -0400 Received: from [69.55.238.164] (helo=ion.gank.org) by monty-python.gnu.org with esmtp (Exim 4.34) id 1DgwtR-0008Vb-IU for qemu-devel@nongnu.org; Fri, 10 Jun 2005 23:42:45 -0400 Date: Fri, 10 Jun 2005 22:42:09 -0500 From: Craig Boston Message-ID: <20050611034209.GA3948@nowhere> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="1yeeQ81UyVL57Vl7" Content-Disposition: inline Subject: [Qemu-devel] KQemu FreeBSD wrapper cloning support Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: nox@jelal.kn-bremen.de, antony.t.curtis@ntlworld.com Cc: qemu-devel@nongnu.org --1yeeQ81UyVL57Vl7 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hello, Attached is an experimental patch I threw together this evening that adds support for FreeBSD 5.x+ device cloning to Antony's kqemu wrapper. I haven't done just a whole lot of testing, but it passes the "works for me" test. With it I'm able to load the module, start up a few concurrent qemu instances (all using the accelerator), close some, open one or two more, then close them all and unload the module. So far the only problem I've run into is a panic if you repeatedly ls -l /dev/kqemu and /dev/kqemu[0-9]. However, I am able to cause the same panic by doing that with the tun device, so it appears to be a bug in FreeBSD (possibly specific to 6.0-current). It still has the 4 instance limit, which appears to have been copied from the Linux module. I debated removing it, but figured there must be some reason it's in there... Just thought you might be interested. Craig --1yeeQ81UyVL57Vl7 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="kmod_bsd_clone.patch" --- kmod_bsd.c.orig Fri Jun 10 19:14:08 2005 +++ kmod_bsd.c Fri Jun 10 22:27:13 2005 @@ -284,6 +284,10 @@ #define KQEMU_MAX_INSTANCES 4 struct kqemu_instance { +#if __FreeBSD_version > 500000 + TAILQ_ENTRY(kqemu_instance) kqemu_ent; + struct cdev *kqemu_dev; +#endif struct kqemu_state *state; }; @@ -292,7 +296,9 @@ #if __FreeBSD_version < 500000 static dev_t kqemu_dev; #else -static struct cdev *kqemu_dev; +static struct clonedevs *kqemuclones; +static TAILQ_HEAD(,kqemu_instance) kqemuhead = TAILQ_HEAD_INITIALIZER(kqemuhead); +static eventhandler_tag clonetag; #endif @@ -325,6 +331,61 @@ #endif }; +#if __FreeBSD_version > 500000 +static void +kqemu_clone(void *arg, char *name, int namelen, struct cdev **dev) +{ + int unit, r; + if (*dev != NULL) + return; + + if (strcmp(name, "kqemu") == 0) + unit = -1; + else if (dev_stdclone(name, NULL, "kqemu", &unit) != 1) + return; /* Bad name */ + if (unit != -1 && unit > KQEMU_MAX_INSTANCES) + return; + + r = clone_create(&kqemuclones, &kqemu_cdevsw, &unit, dev, 0); + if (r) { + *dev = make_dev(&kqemu_cdevsw, unit2minor(unit), + UID_ROOT, GID_WHEEL, 0660, "kqemu%d", unit); + if (*dev != NULL) { + dev_ref(*dev); + (*dev)->si_flags |= SI_CHEAPCLONE; + } + } +} +#endif + +static void kqemu_destroy(struct kqemu_instance *ks) +{ + struct cdev *dev = ks->kqemu_dev; + + if (ks->state) { + kqemu_delete(ks->state); + ks->state = NULL; + } + + free(ks, M_KQEMU); + dev->si_drv1 = NULL; +#if __FreeBSD_version > 500000 + mtx_lock_spin(&cache_lock); + TAILQ_REMOVE(&kqemuhead, ks, kqemu_ent); +#endif + if (!--kqemu_ref_count) { + int i; + for (i = 1023; i >= 0; i--) + kqemu_vfree(pagecache[i]); + memset(pagecache, 0, 1024 * sizeof(void *)); + } +#if __FreeBSD_version > 500000 + mtx_unlock_spin(&cache_lock); + + destroy_dev(dev); +#endif +} + int #if __FreeBSD_version < 500000 kqemu_open(dev, flags, fmt, p) @@ -355,7 +416,9 @@ dev->si_drv1 = ks; #if __FreeBSD_version > 500000 + ks->kqemu_dev = dev; mtx_lock_spin(&cache_lock); + TAILQ_INSERT_TAIL(&kqemuhead, ks, kqemu_ent); #endif kqemu_ref_count++; #if __FreeBSD_version > 500000 @@ -382,25 +445,8 @@ #endif struct kqemu_instance *ks = (struct kqemu_instance *) dev->si_drv1; - if (ks->state) { - kqemu_delete(ks->state); - ks->state = NULL; - } - - free(ks, M_KQEMU); - dev->si_drv1 = NULL; -#if __FreeBSD_version > 500000 - mtx_lock_spin(&cache_lock); -#endif - if (!--kqemu_ref_count) { - int i; - for (i = 1023; i >= 0; i--) - kqemu_vfree(pagecache[i]); - memset(pagecache, 0, 1024 * sizeof(void *)); - } -#if __FreeBSD_version > 500000 - mtx_unlock_spin(&cache_lock); -#endif + kqemu_destroy(ks); + kqemu_log("closed by pid=%d\n", p->p_pid); return(0); } @@ -513,9 +559,14 @@ kqemu_log("error registering cdevsw, rc=%d\n", rc); return(ENOENT); } -#endif kqemu_dev = make_dev(&kqemu_cdevsw, 0, UID_ROOT, GID_WHEEL, 0660, "kqemu"); +#else + clone_setup(&kqemuclones); + clonetag = EVENTHANDLER_REGISTER(dev_clone, kqemu_clone, 0, 1000); + if (!clonetag) + return ENOMEM; +#endif kqemu_log("KQEMU installed, max_instances=%d max_locked_mem=%dkB.\n", KQEMU_MAX_INSTANCES, max_locked_pages * 4); @@ -529,12 +580,25 @@ { #if __FreeBSD_version < 500000 int rc; +#else + struct kqemu_instance *ks; #endif - destroy_dev(kqemu_dev); #if __FreeBSD_version < 500000 + destroy_dev(kqemu_dev); if ((rc = cdevsw_remove(&kqemu_cdevsw))) kqemu_log("error unregistering, rc=%d\n", rc); +#else + EVENTHANDLER_DEREGISTER(dev_clone, clonetag); + mtx_lock_spin(&cache_lock); + while ((ks = TAILQ_FIRST(&kqemuhead)) != NULL) { + mtx_unlock_spin(&cache_lock); + kqemu_destroy(ks); + mtx_lock_spin(&cache_lock); + } + mtx_unlock_spin(&cache_lock); + mtx_destroy(&cache_lock); + clone_cleanup(&kqemuclones); #endif kqemu_vfree(pagecache); --1yeeQ81UyVL57Vl7--