Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-2.6:
  SCSI: fix race in device_create
  USB: Core: fix race in device_create
  USB: Phidget: fix race in device_create
  s390: fix race in device_create
  SOUND: fix race in device_create
  UIO: fix race in device_create
  Power Supply: fix race in device_create
  LEDS: fix race in device_create
  IB: fix race in device_create
  ide: fix race in device_create
  fbdev: fix race in device_create
  mm: bdi: fix race in bdi_class device creation
  Driver core: add device_create_vargs and device_create_drvdata
This commit is contained in:
Linus Torvalds 2008-05-20 17:20:23 -07:00
commit 57312b75aa
20 changed files with 179 additions and 108 deletions

View File

@ -1083,6 +1083,102 @@ static void device_create_release(struct device *dev)
kfree(dev);
}
/**
* device_create_vargs - creates a device and registers it with sysfs
* @class: pointer to the struct class that this device should be registered to
* @parent: pointer to the parent struct device of this new device, if any
* @devt: the dev_t for the char device to be added
* @drvdata: the data to be added to the device for callbacks
* @fmt: string for the device's name
* @args: va_list for the device's name
*
* This function can be used by char device classes. A struct device
* will be created in sysfs, registered to the specified class.
*
* A "dev" file will be created, showing the dev_t for the device, if
* the dev_t is not 0,0.
* If a pointer to a parent struct device is passed in, the newly created
* struct device will be a child of that device in sysfs.
* The pointer to the struct device will be returned from the call.
* Any further sysfs files that might be required can be created using this
* pointer.
*
* Note: the struct class passed to this function must have previously
* been created with a call to class_create().
*/
struct device *device_create_vargs(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt,
va_list args)
{
struct device *dev = NULL;
int retval = -ENODEV;
if (class == NULL || IS_ERR(class))
goto error;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
retval = -ENOMEM;
goto error;
}
dev->devt = devt;
dev->class = class;
dev->parent = parent;
dev->release = device_create_release;
dev_set_drvdata(dev, drvdata);
vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
retval = device_register(dev);
if (retval)
goto error;
return dev;
error:
kfree(dev);
return ERR_PTR(retval);
}
EXPORT_SYMBOL_GPL(device_create_vargs);
/**
* device_create_drvdata - creates a device and registers it with sysfs
* @class: pointer to the struct class that this device should be registered to
* @parent: pointer to the parent struct device of this new device, if any
* @devt: the dev_t for the char device to be added
* @drvdata: the data to be added to the device for callbacks
* @fmt: string for the device's name
*
* This function can be used by char device classes. A struct device
* will be created in sysfs, registered to the specified class.
*
* A "dev" file will be created, showing the dev_t for the device, if
* the dev_t is not 0,0.
* If a pointer to a parent struct device is passed in, the newly created
* struct device will be a child of that device in sysfs.
* The pointer to the struct device will be returned from the call.
* Any further sysfs files that might be required can be created using this
* pointer.
*
* Note: the struct class passed to this function must have previously
* been created with a call to class_create().
*/
struct device *device_create_drvdata(struct class *class,
struct device *parent,
dev_t devt,
void *drvdata,
const char *fmt, ...)
{
va_list vargs;
struct device *dev;
va_start(vargs, fmt);
dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
va_end(vargs);
return dev;
}
EXPORT_SYMBOL_GPL(device_create_drvdata);
/**
* device_create - creates a device and registers it with sysfs
* @class: pointer to the struct class that this device should be registered to
@ -1107,36 +1203,13 @@ static void device_create_release(struct device *dev)
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, const char *fmt, ...)
{
va_list args;
struct device *dev = NULL;
int retval = -ENODEV;
if (class == NULL || IS_ERR(class))
goto error;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
retval = -ENOMEM;
goto error;
}
dev->devt = devt;
dev->class = class;
dev->parent = parent;
dev->release = device_create_release;
va_start(args, fmt);
vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
va_end(args);
retval = device_register(dev);
if (retval)
goto error;
va_list vargs;
struct device *dev;
va_start(vargs, fmt);
dev = device_create_vargs(class, parent, devt, NULL, fmt, vargs);
va_end(vargs);
return dev;
error:
kfree(dev);
return ERR_PTR(retval);
}
EXPORT_SYMBOL_GPL(device_create);

View File

@ -648,13 +648,12 @@ static int ide_register_port(ide_hwif_t *hwif)
get_device(&hwif->gendev);
hwif->portdev = device_create(ide_port_class, &hwif->gendev,
MKDEV(0, 0), hwif->name);
hwif->portdev = device_create_drvdata(ide_port_class, &hwif->gendev,
MKDEV(0, 0), hwif, hwif->name);
if (IS_ERR(hwif->portdev)) {
ret = PTR_ERR(hwif->portdev);
device_unregister(&hwif->gendev);
}
dev_set_drvdata(hwif->portdev, hwif);
out:
return ret;
}

View File

@ -1005,8 +1005,9 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
if (cdev_add(port->cdev, base_dev + port->dev_num, 1))
goto err_cdev;
port->dev = device_create(umad_class, device->dma_device,
port->cdev->dev, "umad%d", port->dev_num);
port->dev = device_create_drvdata(umad_class, device->dma_device,
port->cdev->dev, port,
"umad%d", port->dev_num);
if (IS_ERR(port->dev))
goto err_cdev;
@ -1024,15 +1025,12 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
if (cdev_add(port->sm_cdev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1))
goto err_sm_cdev;
port->sm_dev = device_create(umad_class, device->dma_device,
port->sm_cdev->dev,
"issm%d", port->dev_num);
port->sm_dev = device_create_drvdata(umad_class, device->dma_device,
port->sm_cdev->dev, port,
"issm%d", port->dev_num);
if (IS_ERR(port->sm_dev))
goto err_sm_cdev;
dev_set_drvdata(port->dev, port);
dev_set_drvdata(port->sm_dev, port);
if (device_create_file(port->sm_dev, &dev_attr_ibdev))
goto err_sm_dev;
if (device_create_file(port->sm_dev, &dev_attr_port))

View File

@ -755,14 +755,15 @@ static void ib_uverbs_add_one(struct ib_device *device)
if (cdev_add(uverbs_dev->cdev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1))
goto err_cdev;
uverbs_dev->dev = device_create(uverbs_class, device->dma_device,
uverbs_dev->cdev->dev,
"uverbs%d", uverbs_dev->devnum);
uverbs_dev->dev = device_create_drvdata(uverbs_class,
device->dma_device,
uverbs_dev->cdev->dev,
uverbs_dev,
"uverbs%d",
uverbs_dev->devnum);
if (IS_ERR(uverbs_dev->dev))
goto err_cdev;
dev_set_drvdata(uverbs_dev->dev, uverbs_dev);
if (device_create_file(uverbs_dev->dev, &dev_attr_ibdev))
goto err_class;
if (device_create_file(uverbs_dev->dev, &dev_attr_abi_version))

View File

@ -103,13 +103,11 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
int rc;
led_cdev->dev = device_create(leds_class, parent, 0, "%s",
led_cdev->name);
led_cdev->dev = device_create_drvdata(leds_class, parent, 0, led_cdev,
"%s", led_cdev->name);
if (IS_ERR(led_cdev->dev))
return PTR_ERR(led_cdev->dev);
dev_set_drvdata(led_cdev->dev, led_cdev);
/* register the attributes */
rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
if (rc)

View File

@ -91,15 +91,13 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
{
int rc = 0;
psy->dev = device_create(power_supply_class, parent, 0,
"%s", psy->name);
psy->dev = device_create_drvdata(power_supply_class, parent, 0,
psy, "%s", psy->name);
if (IS_ERR(psy->dev)) {
rc = PTR_ERR(psy->dev);
goto dev_create_failed;
}
dev_set_drvdata(psy->dev, psy);
INIT_WORK(&psy->changed_work, power_supply_changed_work);
rc = power_supply_create_attrs(psy);

View File

@ -762,10 +762,10 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
device_unregister(dev);
return ret;
}
priv->class_device = device_create(vmlogrdr_class, dev,
MKDEV(vmlogrdr_major,
priv->minor_num),
"%s", dev->bus_id);
priv->class_device = device_create_drvdata(vmlogrdr_class, dev,
MKDEV(vmlogrdr_major,
priv->minor_num),
priv, "%s", dev->bus_id);
if (IS_ERR(priv->class_device)) {
ret = PTR_ERR(priv->class_device);
priv->class_device=NULL;
@ -773,7 +773,6 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
device_unregister(dev);
return ret;
}
dev->driver_data = priv;
priv->device = dev;
return 0;
}

View File

@ -910,9 +910,9 @@ static int ch_probe(struct device *dev)
ch->minor = minor;
sprintf(ch->name,"ch%d",ch->minor);
class_dev = device_create(ch_sysfs_class, dev,
MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
"s%s", ch->name);
class_dev = device_create_drvdata(ch_sysfs_class, dev,
MKDEV(SCSI_CHANGER_MAJOR, ch->minor),
ch, "s%s", ch->name);
if (IS_ERR(class_dev)) {
printk(KERN_WARNING "ch%d: device_create failed\n",
ch->minor);
@ -926,7 +926,6 @@ static int ch_probe(struct device *dev)
if (init)
ch_init_elem(ch);
dev_set_drvdata(dev, ch);
sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
return 0;

View File

@ -5695,13 +5695,12 @@ static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * S
struct device *osst_member;
int err;
osst_member = device_create(osst_sysfs_class, device, dev, "%s", name);
osst_member = device_create_drvdata(osst_sysfs_class, device, dev, STp, "%s", name);
if (IS_ERR(osst_member)) {
printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
return PTR_ERR(osst_member);
}
dev_set_drvdata(osst_member, STp);
err = device_create_file(osst_member, &dev_attr_ADR_rev);
if (err)
goto err_out;

View File

@ -1441,17 +1441,18 @@ sg_add(struct device *cl_dev, struct class_interface *cl_intf)
if (sg_sysfs_valid) {
struct device *sg_class_member;
sg_class_member = device_create(sg_sysfs_class, cl_dev->parent,
MKDEV(SCSI_GENERIC_MAJOR,
sdp->index),
"%s", disk->disk_name);
sg_class_member = device_create_drvdata(sg_sysfs_class,
cl_dev->parent,
MKDEV(SCSI_GENERIC_MAJOR,
sdp->index),
sdp,
"%s", disk->disk_name);
if (IS_ERR(sg_class_member)) {
printk(KERN_ERR "sg_add: "
"device_create failed\n");
error = PTR_ERR(sg_class_member);
goto cdev_add_err;
}
dev_set_drvdata(sg_class_member, sdp);
error = sysfs_create_link(&scsidp->sdev_gendev.kobj,
&sg_class_member->kobj, "generic");
if (error)

View File

@ -4424,17 +4424,19 @@ static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
snprintf(name, 10, "%s%s%s", rew ? "n" : "",
STp->disk->disk_name, st_formats[i]);
st_class_member =
device_create(st_sysfs_class, &STp->device->sdev_gendev,
MKDEV(SCSI_TAPE_MAJOR,
TAPE_MINOR(dev_num, mode, rew)),
"%s", name);
device_create_drvdata(st_sysfs_class,
&STp->device->sdev_gendev,
MKDEV(SCSI_TAPE_MAJOR,
TAPE_MINOR(dev_num,
mode, rew)),
&STp->modes[mode],
"%s", name);
if (IS_ERR(st_class_member)) {
printk(KERN_WARNING "st%d: device_create failed\n",
dev_num);
error = PTR_ERR(st_class_member);
goto out;
}
dev_set_drvdata(st_class_member, &STp->modes[mode]);
error = device_create_file(st_class_member,
&dev_attr_defined);

View File

@ -649,15 +649,14 @@ int __uio_register_device(struct module *owner,
if (ret)
goto err_get_minor;
idev->dev = device_create(uio_class->class, parent,
MKDEV(uio_major, idev->minor),
"uio%d", idev->minor);
idev->dev = device_create_drvdata(uio_class->class, parent,
MKDEV(uio_major, idev->minor), idev,
"uio%d", idev->minor);
if (IS_ERR(idev->dev)) {
printk(KERN_ERR "UIO: device register failed\n");
ret = PTR_ERR(idev->dev);
goto err_device_create;
}
dev_set_drvdata(idev->dev, idev);
ret = uio_dev_add_attributes(idev);
if (ret)

View File

@ -818,12 +818,12 @@ static int usb_register_bus(struct usb_bus *bus)
set_bit (busnum, busmap.busmap);
bus->busnum = busnum;
bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0),
"usb_host%d", busnum);
bus->dev = device_create_drvdata(usb_host_class, bus->controller,
MKDEV(0, 0), bus,
"usb_host%d", busnum);
result = PTR_ERR(bus->dev);
if (IS_ERR(bus->dev))
goto error_create_class_dev;
dev_set_drvdata(bus->dev, bus);
/* Add it to the local list of buses */
list_add (&bus->bus_list, &usb_bus_list);

View File

@ -595,14 +595,14 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
} while(value);
kit->dev_no = bit;
kit->dev = device_create(phidget_class, &kit->udev->dev, 0,
"interfacekit%d", kit->dev_no);
kit->dev = device_create_drvdata(phidget_class, &kit->udev->dev,
MKDEV(0, 0), kit,
"interfacekit%d", kit->dev_no);
if (IS_ERR(kit->dev)) {
rc = PTR_ERR(kit->dev);
kit->dev = NULL;
goto out;
}
dev_set_drvdata(kit->dev, kit);
if (usb_submit_urb(kit->irq, GFP_KERNEL)) {
rc = -EIO;

View File

@ -365,16 +365,15 @@ static int motorcontrol_probe(struct usb_interface *intf, const struct usb_devic
} while(value);
mc->dev_no = bit;
mc->dev = device_create(phidget_class, &mc->udev->dev, 0,
"motorcontrol%d", mc->dev_no);
mc->dev = device_create_drvdata(phidget_class, &mc->udev->dev,
MKDEV(0, 0), mc,
"motorcontrol%d", mc->dev_no);
if (IS_ERR(mc->dev)) {
rc = PTR_ERR(mc->dev);
mc->dev = NULL;
goto out;
}
dev_set_drvdata(mc->dev, mc);
if (usb_submit_urb(mc->irq, GFP_KERNEL)) {
rc = -EIO;
goto out;

View File

@ -275,14 +275,14 @@ servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
} while (value);
dev->dev_no = bit;
dev->dev = device_create(phidget_class, &dev->udev->dev, 0,
"servo%d", dev->dev_no);
dev->dev = device_create_drvdata(phidget_class, &dev->udev->dev,
MKDEV(0, 0), dev,
"servo%d", dev->dev_no);
if (IS_ERR(dev->dev)) {
rc = PTR_ERR(dev->dev);
dev->dev = NULL;
goto out;
}
dev_set_drvdata(dev->dev, dev);
servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;

View File

@ -26,6 +26,7 @@
#include <linux/ctype.h>
#include <linux/idr.h>
#include <linux/err.h>
#include <linux/kdev_t.h>
static ssize_t display_show_name(struct device *dev,
struct device_attribute *attr, char *buf)
@ -152,10 +153,13 @@ struct display_device *display_device_register(struct display_driver *driver,
mutex_unlock(&allocated_dsp_lock);
if (!ret) {
new_dev->dev = device_create(display_class, parent, 0,
"display%d", new_dev->idx);
new_dev->dev = device_create_drvdata(display_class,
parent,
MKDEV(0,0),
new_dev,
"display%d",
new_dev->idx);
if (!IS_ERR(new_dev->dev)) {
dev_set_drvdata(new_dev->dev, new_dev);
new_dev->parent = parent;
new_dev->driver = driver;
mutex_init(&new_dev->lock);

View File

@ -449,9 +449,21 @@ extern int __must_check device_reprobe(struct device *dev);
/*
* Easy functions for dynamically creating devices on the fly
*/
extern struct device *device_create_vargs(struct class *cls,
struct device *parent,
dev_t devt,
void *drvdata,
const char *fmt,
va_list vargs);
extern struct device *device_create(struct class *cls, struct device *parent,
dev_t devt, const char *fmt, ...)
__attribute__((format(printf, 4, 5)));
extern struct device *device_create_drvdata(struct class *cls,
struct device *parent,
dev_t devt,
void *drvdata,
const char *fmt, ...)
__attribute__((format(printf, 5, 6)));
extern void device_destroy(struct class *cls, dev_t devt);
/*

View File

@ -172,30 +172,22 @@ postcore_initcall(bdi_class_init);
int bdi_register(struct backing_dev_info *bdi, struct device *parent,
const char *fmt, ...)
{
char *name;
va_list args;
int ret = 0;
struct device *dev;
va_start(args, fmt);
name = kvasprintf(GFP_KERNEL, fmt, args);
dev = device_create_vargs(bdi_class, parent, MKDEV(0, 0), bdi, fmt, args);
va_end(args);
if (!name)
return -ENOMEM;
dev = device_create(bdi_class, parent, MKDEV(0, 0), name);
if (IS_ERR(dev)) {
ret = PTR_ERR(dev);
goto exit;
}
bdi->dev = dev;
dev_set_drvdata(bdi->dev, bdi);
bdi_debug_register(bdi, name);
bdi_debug_register(bdi, dev_name(dev));
exit:
kfree(name);
return ret;
}
EXPORT_SYMBOL(bdi_register);

View File

@ -259,8 +259,9 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
return minor;
}
snd_minors[minor] = preg;
preg->dev = device_create(sound_class, device, MKDEV(major, minor),
"%s", name);
preg->dev = device_create_drvdata(sound_class, device,
MKDEV(major, minor),
private_data, "%s", name);
if (IS_ERR(preg->dev)) {
snd_minors[minor] = NULL;
mutex_unlock(&sound_mutex);
@ -269,9 +270,6 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
return minor;
}
if (preg->dev)
dev_set_drvdata(preg->dev, private_data);
mutex_unlock(&sound_mutex);
return 0;
}