panic: dev ... is on clonelist

From: Andrew Gallatin (gallatin_at_cs.duke.edu)
Date: 03/04/05

  • Next message: Remington: "Re: FXP driver not attaching"
    Date: Thu, 3 Mar 2005 18:01:17 -0500 (EST)
    To: freebsd-current@freebsd.org
    
    

    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;
      }
    }

    _______________________________________________
    freebsd-current@freebsd.org mailing list
    http://lists.freebsd.org/mailman/listinfo/freebsd-current
    To unsubscribe, send any mail to "freebsd-current-unsubscribe@freebsd.org"


  • Next message: Remington: "Re: FXP driver not attaching"

    Relevant Pages

    • Re: [PATCH] RFC: Attributes in /sys/cdev
      ... > some purpose... ... find the cdev allocated by register_chrdev, ... since it has no relationship to any driver objects). ... I would be just fine with not seeing these guys in sysfs - they don't ...
      (Linux-Kernel)
    • Im counting my threads, one, two, three, four, five... [1]
      ... cdev and consequently, with a bit of adding up, also for each cdevsw. ... The next step is to add a new method to the cdevsw which purges threads ... and exit the driver with ENXIO error return. ... hardware without panicing in the lower layers of the kernel. ...
      (freebsd-arch)
    • Re: [PATCH] Driver Core update for 2.6.4
      ... of device driver books - and, with luck, driver authors too. ... static struct cdev tty_cdev, console_cdev; ... static void cdev_unmap ...
      (Linux-Kernel)
    • [PATCH] cdev 1/2: Eliminate /sys/cdev
      ... of device driver books - and, with luck, driver authors too. ... static struct cdev tty_cdev, console_cdev; ... static void cdev_unmap ...
      (Linux-Kernel)
    • [PATCH] cdev_init: zero out cdev before kobject_init()
      ... a driver passes an uninitialized struct cdev to cdev_init, ... struct cdev in advance (and indeed most if not all of the things ... send the line "unsubscribe linux-kernel" in ...
      (Linux-Kernel)