From owner-freebsd-current@FreeBSD.ORG Thu Mar 3 23:01:23 2005 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 9A82F16A4CE for ; Thu, 3 Mar 2005 23:01:23 +0000 (GMT) Received: from duke.cs.duke.edu (duke.cs.duke.edu [152.3.140.1]) by mx1.FreeBSD.org (Postfix) with ESMTP id 1FD8143D31 for ; Thu, 3 Mar 2005 23:01:23 +0000 (GMT) (envelope-from gallatin@cs.duke.edu) Received: from grasshopper.cs.duke.edu (grasshopper.cs.duke.edu [152.3.145.30]) by duke.cs.duke.edu (8.13.1/8.13.1) with ESMTP id j23N1MV8028172 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Thu, 3 Mar 2005 18:01:22 -0500 (EST) Received: (from gallatin@localhost) by grasshopper.cs.duke.edu (8.12.9p2/8.12.9/Submit) id j23N1HYa016244; Thu, 3 Mar 2005 18:01:17 -0500 (EST) (envelope-from gallatin) From: Andrew Gallatin MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <16935.38717.96802.616769@grasshopper.cs.duke.edu> Date: Thu, 3 Mar 2005 18:01:17 -0500 (EST) To: freebsd-current@freebsd.org X-Mailer: VM 6.75 under 21.1 (patch 12) "Channel Islands" XEmacs Lucid Subject: panic: dev ... is on clonelist X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 Mar 2005 23:01:23 -0000 Hi, I've got a character driver which I'd like to make behave as much like a linux cloning driver as possible because I'm maintaining linux binary compat. I'm using the cloning interface in 5.x and 6.0. My driver *seems* to work fine in 5.4, even with INVARIANTS. But in 6.0, I'm dying with: "dev 0xc2f89c00 (mx_fake.1) is on clonelist". >From the si_drv{1,2} fields, it looks like the cdev was closed. Did something change between 5.x and 6.0? Or am I doing something that's bogus in 5.x and I'm just getting lucky? What I want is to have a unique cdev generated for each open of the device. Then I would like to use the si_drv1 and si_drv2 fields of the cdev to hang per-open information from. So, if the user opens /dev/mx0, then I'd like a unique cdev generated. And if somebody else opens /dev/mx0, then I'd like a second unique cdev generated. What I've been doing (and what seemed to work in 5.x) was this: - Don't make any /dev/mx devices at all, use clone handler for all device creation. - Use dev_stdclone() in to get the "real" unit number (0 from /dev/mx0, 1 from /dev/mx1, etc, where the unit corresponds to a physical device). - Prepare a "fake" device for the user, so that every open has a unique cdev. To do this, I have been calling clone_create() with a "fake" unit number (starting at 0, and increasing) until I find either a free "fake" cdev, or a "fake" cdev which does not exist. By free, I make a cdev whose si_drv1 indicates he's free. By "fake", I mean I don't care what the unit number is. - if the "fake" cdev does not exist, create a /dev/mx_fake.%d, using the "fake" unit number via make_dev() - using the cdev obtained from either clone_create(), or make_dev(), set (*cdev)->si_drv1 to the "real" unit number so my open routine knows what to do. Any idea what I'm doing wrong? Thanks for the help, Drew static void mx_clone(void *arg, char *name, int namelen, struct cdev **cdev) { int u, i, privileged, mode, fake_unit, free_cdev; if (*cdev != NULL) { /* printf("mx_clone called with non-null struct cdev *??\n");*/ return; } if (dev_stdclone(name, NULL, "mxp", &u)) { privileged = 1; mode = 0600; } else if (dev_stdclone(name, NULL, "mx", &u)) { privileged = 0; mode = 0666; } else {/* Don't recognize the name */ return; } if (u >= mx_num_instances) return; /* unit too large */ if (privileged && suser(curthread)) return; /* EPERM */ /* Now we iterate over our clone list. We start at index 0, and keep going until we find a free clone. We know the clone is free because either the cdev is null (in which case it was never allocated, and no /dev/mx_fake.%d entry exists) or the cdev is non-null, and its si_drv1 field is null (which means that it has been closed by another process, and a /dev/mx_fake.%d exists). Its important to find priviliged devices, so we always search only odd units when we want a priviliged device. */ fake_unit = 0 + privileged; do { i = clone_create(&mx_clones, &mx_cdevsw, &fake_unit, cdev, 0); free_cdev = i || ((*cdev)->si_drv1 == NULL); #if 1 printf("dev: %d. i: %d", fake_unit, i); if (i == 0) printf(" drv1: %p", (*cdev)->si_drv1); else printf(" drv1: NULL"); printf(" Free = %d\n", free_cdev); #endif if (!free_cdev) fake_unit+=2; } while (!free_cdev); if (i) { /* need to allocate a new /dev/mx_fake.%d device node */ *cdev = make_dev(&mx_cdevsw, unit2minor(fake_unit), UID_ROOT, GID_WHEEL, mode, "mx_fake.%d", fake_unit); } if (*cdev != NULL) { /* Treat si_drv1 like a bitfield. Low bit is "in use" flag, second bit is privileged bit, remainder is the real unit that the opener requested */ mx_always_assert((*cdev)->si_drv1 == NULL); (*cdev)->si_drv1 = (void *)(uintptr_t)(1 | (privileged << 1) | (u << 2)); (*cdev)->si_drv2 = NULL; } }