Use synchronous device destruction instead of asynchronous, so that a new

device having the same name like a previous one is not created before the old
one is gone. This fixes some panics due to asserts in the devfs code which
were added recently.

Approved by:    re (kib)
MFC after:      1 week
This commit is contained in:
Hans Petter Selasky 2011-08-11 11:30:21 +00:00
parent aa0da2e494
commit 2ffd5fdcc4
4 changed files with 63 additions and 62 deletions

View File

@ -1648,7 +1648,6 @@ usb_fifo_attach(struct usb_device *udev, void *priv_sc,
struct usb_fifo *f_rx;
char devname[32];
uint8_t n;
struct usb_fs_privdata* pd;
f_sc->fp[USB_FIFO_TX] = NULL;
f_sc->fp[USB_FIFO_RX] = NULL;
@ -1746,22 +1745,10 @@ usb_fifo_attach(struct usb_device *udev, void *priv_sc,
usb_alloc_symlink(devname);
}
/*
* Initialize device private data - this is used to find the
* actual USB device itself.
*/
pd = malloc(sizeof(struct usb_fs_privdata), M_USBDEV, M_WAITOK | M_ZERO);
pd->bus_index = device_get_unit(udev->bus->bdev);
pd->dev_index = udev->device_index;
pd->ep_addr = -1; /* not an endpoint */
pd->fifo_index = f_tx->fifo_index & f_rx->fifo_index;
pd->mode = FREAD|FWRITE;
/* Now, create the device itself */
f_sc->dev = make_dev(&usb_devsw, 0, uid, gid, mode,
"%s", devname);
/* XXX setting si_drv1 and creating the device is not atomic! */
f_sc->dev->si_drv1 = pd;
/* Create the device */
f_sc->dev = usb_make_dev(udev, devname, -1,
f_tx->fifo_index & f_rx->fifo_index,
FREAD|FWRITE, uid, gid, mode);
}
DPRINTFN(2, "attached %p/%p\n", f_tx, f_rx);
@ -1814,12 +1801,6 @@ usb_fifo_free_buffer(struct usb_fifo *f)
bzero(&f->used_q, sizeof(f->used_q));
}
static void
usb_fifo_cleanup(void* ptr)
{
free(ptr, M_USBDEV);
}
void
usb_fifo_detach(struct usb_fifo_sc *f_sc)
{
@ -1832,11 +1813,9 @@ usb_fifo_detach(struct usb_fifo_sc *f_sc)
f_sc->fp[USB_FIFO_TX] = NULL;
f_sc->fp[USB_FIFO_RX] = NULL;
if (f_sc->dev != NULL) {
destroy_dev_sched_cb(f_sc->dev,
usb_fifo_cleanup, f_sc->dev->si_drv1);
f_sc->dev = NULL;
}
usb_destroy_dev(f_sc->dev);
f_sc->dev = NULL;
DPRINTFN(2, "detached %p\n", f_sc);
}

View File

@ -102,10 +102,8 @@ static void usb_notify_addq(const char *type, struct usb_device *);
#endif
#if USB_HAVE_UGEN
static void usb_fifo_free_wrap(struct usb_device *, uint8_t, uint8_t);
static struct cdev *usb_make_dev(struct usb_device *, int, int);
static void usb_cdev_create(struct usb_device *);
static void usb_cdev_free(struct usb_device *);
static void usb_cdev_cleanup(void *);
#endif
/* This variable is global to allow easy access to it: */
@ -1626,10 +1624,12 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
LIST_INIT(&udev->pd_list);
/* Create the control endpoint device */
udev->ctrl_dev = usb_make_dev(udev, 0, FREAD|FWRITE);
udev->ctrl_dev = usb_make_dev(udev, NULL, 0, 0,
FREAD|FWRITE, UID_ROOT, GID_OPERATOR, 0600);
/* Create a link from /dev/ugenX.X to the default endpoint */
make_dev_alias(udev->ctrl_dev, "%s", udev->ugen_name);
if (udev->ctrl_dev != NULL)
make_dev_alias(udev->ctrl_dev->cdev, "%s", udev->ugen_name);
#endif
/* Initialise device */
if (bus->methods->device_init != NULL) {
@ -1884,11 +1884,12 @@ usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
}
#if USB_HAVE_UGEN
static struct cdev *
usb_make_dev(struct usb_device *udev, int ep, int mode)
struct usb_fs_privdata *
usb_make_dev(struct usb_device *udev, const char *devname, int ep,
int fi, int rwmode, uid_t uid, gid_t gid, int mode)
{
struct usb_fs_privdata* pd;
char devname[20];
char buffer[32];
/* Store information to locate ourselves again later */
pd = malloc(sizeof(struct usb_fs_privdata), M_USBDEV,
@ -1896,16 +1897,39 @@ usb_make_dev(struct usb_device *udev, int ep, int mode)
pd->bus_index = device_get_unit(udev->bus->bdev);
pd->dev_index = udev->device_index;
pd->ep_addr = ep;
pd->mode = mode;
pd->fifo_index = fi;
pd->mode = rwmode;
/* Now, create the device itself */
snprintf(devname, sizeof(devname), "%u.%u.%u",
pd->bus_index, pd->dev_index, pd->ep_addr);
pd->cdev = make_dev(&usb_devsw, 0, UID_ROOT,
GID_OPERATOR, 0600, USB_DEVICE_DIR "/%s", devname);
if (devname == NULL) {
devname = buffer;
snprintf(buffer, sizeof(buffer), USB_DEVICE_DIR "/%u.%u.%u",
pd->bus_index, pd->dev_index, pd->ep_addr);
}
pd->cdev = make_dev(&usb_devsw, 0, uid, gid, mode, "%s", devname);
if (pd->cdev == NULL) {
DPRINTFN(0, "Failed to create device %s\n", devname);
free(pd, M_USBDEV);
return (NULL);
}
/* XXX setting si_drv1 and creating the device is not atomic! */
pd->cdev->si_drv1 = pd;
return (pd->cdev);
return (pd);
}
void
usb_destroy_dev(struct usb_fs_privdata *pd)
{
if (pd == NULL)
return;
destroy_dev(pd->cdev);
free(pd, M_USBDEV);
}
static void
@ -1915,7 +1939,6 @@ usb_cdev_create(struct usb_device *udev)
struct usb_endpoint_descriptor *ed;
struct usb_descriptor *desc;
struct usb_fs_privdata* pd;
struct cdev *dev;
int inmode, outmode, inmask, outmask, mode;
uint8_t ep;
@ -1957,14 +1980,16 @@ usb_cdev_create(struct usb_device *udev)
/* Create all available endpoints except EP0 */
for (ep = 1; ep < 16; ep++) {
mode = inmask & (1 << ep) ? inmode : 0;
mode |= outmask & (1 << ep) ? outmode : 0;
mode = (inmask & (1 << ep)) ? inmode : 0;
mode |= (outmask & (1 << ep)) ? outmode : 0;
if (mode == 0)
continue; /* no IN or OUT endpoint */
dev = usb_make_dev(udev, ep, mode);
pd = dev->si_drv1;
LIST_INSERT_HEAD(&udev->pd_list, pd, pd_next);
pd = usb_make_dev(udev, NULL, ep, 0,
mode, UID_ROOT, GID_OPERATOR, 0600);
if (pd != NULL)
LIST_INSERT_HEAD(&udev->pd_list, pd, pd_next);
}
}
@ -1972,25 +1997,16 @@ static void
usb_cdev_free(struct usb_device *udev)
{
struct usb_fs_privdata* pd;
struct cdev* pcdev;
DPRINTFN(2, "Freeing device nodes\n");
while ((pd = LIST_FIRST(&udev->pd_list)) != NULL) {
KASSERT(pd->cdev->si_drv1 == pd, ("privdata corrupt"));
pcdev = pd->cdev;
pd->cdev = NULL;
LIST_REMOVE(pd, pd_next);
if (pcdev != NULL)
destroy_dev_sched_cb(pcdev, usb_cdev_cleanup, pd);
}
}
static void
usb_cdev_cleanup(void* arg)
{
free(arg, M_USBDEV);
usb_destroy_dev(pd);
}
}
#endif
@ -2046,8 +2062,7 @@ usb_free_device(struct usb_device *udev, uint8_t flag)
}
mtx_unlock(&usb_ref_lock);
destroy_dev_sched_cb(udev->ctrl_dev, usb_cdev_cleanup,
udev->ctrl_dev->si_drv1);
usb_destroy_dev(udev->ctrl_dev);
#endif
if (udev->flags.usb_mode == USB_MODE_DEVICE) {

View File

@ -29,6 +29,7 @@
struct usb_symlink; /* UGEN */
struct usb_device; /* linux compat */
struct usb_fs_privdata;
#define USB_CTRL_XFER_MAX 2
@ -135,7 +136,7 @@ struct usb_device {
#if USB_HAVE_UGEN
struct usb_fifo *fifo[USB_FIFO_MAX];
struct usb_symlink *ugen_symlink; /* our generic symlink */
struct cdev *ctrl_dev; /* Control Endpoint 0 device node */
struct usb_fs_privdata *ctrl_dev; /* Control Endpoint 0 device node */
LIST_HEAD(,usb_fs_privdata) pd_list;
char ugen_name[20]; /* name of ugenX.X device */
#endif
@ -202,6 +203,11 @@ struct usb_device *usb_alloc_device(device_t parent_dev, struct usb_bus *bus,
struct usb_device *parent_hub, uint8_t depth,
uint8_t port_index, uint8_t port_no,
enum usb_dev_speed speed, enum usb_hc_mode mode);
#if USB_HAVE_UGEN
struct usb_fs_privdata *usb_make_dev(struct usb_device *, const char *,
int, int, int, uid_t, gid_t, int);
void usb_destroy_dev(struct usb_fs_privdata *);
#endif
usb_error_t usb_probe_and_attach(struct usb_device *udev,
uint8_t iface_index);
void usb_detach_device(struct usb_device *, uint8_t, uint8_t);

View File

@ -37,6 +37,7 @@ struct usb_page_search;
struct usb_process;
struct usb_proc_msg;
struct usb_mbuf;
struct usb_fs_privdata;
struct mbuf;
typedef enum { /* keep in sync with usb_errstr_table */
@ -449,7 +450,7 @@ struct usb_fifo_methods {
struct usb_fifo_sc {
struct usb_fifo *fp[2];
struct cdev* dev;
struct usb_fs_privdata *dev;
};
const char *usbd_errstr(usb_error_t error);