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; } }Received on Thu Mar 03 2005 - 22:01:23 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:29 UTC