From 31b9025aa0f89b392077db3f87458fd46bcc4f58 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 18 Jan 2007 12:23:51 -0800 Subject: Kobject: make kobject apis more robust in handling NULL pointers It should be ok to pass in NULL for some kobject functions, so add error checking for all exported kobject functions to be more robust. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/kobject.c b/lib/kobject.c index 7ce6dc138e90..9aed594bfcac 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -126,6 +126,8 @@ EXPORT_SYMBOL_GPL(kobject_get_path); */ void kobject_init(struct kobject * kobj) { + if (!kobj) + return; kref_init(&kobj->kref); INIT_LIST_HEAD(&kobj->entry); init_waitqueue_head(&kobj->poll); @@ -366,6 +368,8 @@ out: void kobject_del(struct kobject * kobj) { + if (!kobj) + return; sysfs_remove_dir(kobj); unlink(kobj); } @@ -377,6 +381,8 @@ void kobject_del(struct kobject * kobj) void kobject_unregister(struct kobject * kobj) { + if (!kobj) + return; pr_debug("kobject %s: unregistering\n",kobject_name(kobj)); kobject_uevent(kobj, KOBJ_REMOVE); kobject_del(kobj); @@ -523,6 +529,8 @@ int kset_add(struct kset * k) int kset_register(struct kset * k) { + if (!k) + return -EINVAL; kset_init(k); return kset_add(k); } @@ -535,6 +543,8 @@ int kset_register(struct kset * k) void kset_unregister(struct kset * k) { + if (!k) + return; kobject_unregister(&k->kobj); } @@ -586,6 +596,9 @@ int subsystem_register(struct subsystem * s) { int error; + if (!s) + return -EINVAL; + subsystem_init(s); pr_debug("subsystem %s: registering\n",s->kset.kobj.name); @@ -598,6 +611,8 @@ int subsystem_register(struct subsystem * s) void subsystem_unregister(struct subsystem * s) { + if (!s) + return; pr_debug("subsystem %s: unregistering\n",s->kset.kobj.name); kset_unregister(&s->kset); } @@ -612,6 +627,10 @@ void subsystem_unregister(struct subsystem * s) int subsys_create_file(struct subsystem * s, struct subsys_attribute * a) { int error = 0; + + if (!s || !a) + return -EINVAL; + if (subsys_get(s)) { error = sysfs_create_file(&s->kset.kobj,&a->attr); subsys_put(s); -- cgit v1.2.3 From 873733188a019acdb7fa253011cbdc0a8afd97f3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 12 Sep 2006 17:00:10 +0200 Subject: Driver core: convert pcmcia code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/cs.c | 34 ++++++------- drivers/pcmcia/cs_internal.h | 4 +- drivers/pcmcia/ds.c | 14 +++--- drivers/pcmcia/i82092.c | 2 +- drivers/pcmcia/i82365.c | 2 +- drivers/pcmcia/pcmcia_ioctl.c | 1 - drivers/pcmcia/pcmcia_resource.c | 1 - drivers/pcmcia/pd6729.c | 2 +- drivers/pcmcia/rsrc_nonstatic.c | 56 +++++++++++---------- drivers/pcmcia/soc_common.c | 6 +-- drivers/pcmcia/socket_sysfs.c | 104 +++++++++++++++++++++++---------------- drivers/pcmcia/tcic.c | 2 +- drivers/pcmcia/yenta_socket.c | 2 +- include/pcmcia/ss.h | 2 +- 14 files changed, 127 insertions(+), 105 deletions(-) diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 606a46740338..ac004248324a 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -110,7 +110,7 @@ int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state) down_read(&pcmcia_socket_list_rwsem); list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { - if (socket->dev.dev != dev) + if (socket->dev.parent != dev) continue; mutex_lock(&socket->skt_mutex); socket_suspend(socket); @@ -128,7 +128,7 @@ int pcmcia_socket_dev_resume(struct device *dev) down_read(&pcmcia_socket_list_rwsem); list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { - if (socket->dev.dev != dev) + if (socket->dev.parent != dev) continue; mutex_lock(&socket->skt_mutex); socket_resume(socket); @@ -143,12 +143,12 @@ EXPORT_SYMBOL(pcmcia_socket_dev_resume); struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt) { - struct class_device *cl_dev = class_device_get(&skt->dev); - if (!cl_dev) + struct device *dev = get_device(&skt->dev); + if (!dev) return NULL; - skt = class_get_devdata(cl_dev); + skt = dev_get_drvdata(dev); if (!try_module_get(skt->owner)) { - class_device_put(&skt->dev); + put_device(&skt->dev); return NULL; } return (skt); @@ -159,14 +159,14 @@ EXPORT_SYMBOL(pcmcia_get_socket); void pcmcia_put_socket(struct pcmcia_socket *skt) { module_put(skt->owner); - class_device_put(&skt->dev); + put_device(&skt->dev); } EXPORT_SYMBOL(pcmcia_put_socket); -static void pcmcia_release_socket(struct class_device *class_dev) +static void pcmcia_release_socket(struct device *dev) { - struct pcmcia_socket *socket = class_get_devdata(class_dev); + struct pcmcia_socket *socket = dev_get_drvdata(dev); complete(&socket->socket_released); } @@ -181,7 +181,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) struct task_struct *tsk; int ret; - if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops) + if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops) return -EINVAL; cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops); @@ -226,9 +226,9 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) #endif /* set proper values in socket->dev */ - socket->dev.class_data = socket; + dev_set_drvdata(&socket->dev, socket); socket->dev.class = &pcmcia_socket_class; - snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock); + snprintf(socket->dev.bus_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock); /* base address = 0, map = 0 */ socket->cis_mem.flags = 0; @@ -640,7 +640,7 @@ static int pccardd(void *__skt) skt->ops->set_socket(skt, &skt->socket); /* register with the device core */ - ret = class_device_register(&skt->dev); + ret = device_register(&skt->dev); if (ret) { printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n", skt); @@ -689,7 +689,7 @@ static int pccardd(void *__skt) remove_wait_queue(&skt->thread_wait, &wait); /* remove from the device core */ - class_device_unregister(&skt->dev); + device_unregister(&skt->dev); return 0; } @@ -904,7 +904,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) EXPORT_SYMBOL(pcmcia_insert_card); -static int pcmcia_socket_uevent(struct class_device *dev, char **envp, +static int pcmcia_socket_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); @@ -930,8 +930,8 @@ static void pcmcia_release_socket_class(struct class *data) struct class pcmcia_socket_class = { .name = "pcmcia_socket", - .uevent = pcmcia_socket_uevent, - .release = pcmcia_release_socket, + .dev_uevent = pcmcia_socket_uevent, + .dev_release = pcmcia_release_socket, .class_release = pcmcia_release_socket_class, }; EXPORT_SYMBOL(pcmcia_socket_class); diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index f573ea04db6f..9fa207e3c7b3 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -142,7 +142,7 @@ struct pcmcia_callback{ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); -#define cs_socket_name(skt) ((skt)->dev.class_id) +#define cs_socket_name(skt) ((skt)->dev.bus_id) #ifdef DEBUG extern int cs_debug_level(int); @@ -158,6 +158,6 @@ extern int cs_debug_level(int); #endif #define cs_err(skt, fmt, arg...) \ - printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg) + printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.bus_id , ## arg) #endif /* _LINUX_CS_INTERNAL_H */ diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 7355eb455a88..18e111e12339 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -572,7 +572,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f p_dev->func = function; p_dev->dev.bus = &pcmcia_bus_type; - p_dev->dev.parent = s->dev.dev; + p_dev->dev.parent = s->dev.parent; p_dev->dev.release = pcmcia_release_dev; bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); @@ -1328,10 +1328,10 @@ static struct pcmcia_callback pcmcia_bus_callback = { .resume = pcmcia_bus_resume, }; -static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, +static int __devinit pcmcia_bus_add_socket(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *socket = class_get_devdata(class_dev); + struct pcmcia_socket *socket = dev_get_drvdata(dev); int ret; socket = pcmcia_get_socket(socket); @@ -1364,10 +1364,10 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, return 0; } -static void pcmcia_bus_remove_socket(struct class_device *class_dev, +static void pcmcia_bus_remove_socket(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *socket = class_get_devdata(class_dev); + struct pcmcia_socket *socket = dev_get_drvdata(dev); if (!socket) return; @@ -1389,8 +1389,8 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev, /* the pcmcia_bus_interface is used to handle pcmcia socket devices */ static struct class_interface pcmcia_bus_interface = { .class = &pcmcia_socket_class, - .add = &pcmcia_bus_add_socket, - .remove = &pcmcia_bus_remove_socket, + .add_dev = &pcmcia_bus_add_socket, + .remove_dev = &pcmcia_bus_remove_socket, }; diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index c2ea07aa7a12..df21e2d16f87 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -161,7 +161,7 @@ static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_de pci_set_drvdata(dev, &sockets[i].socket); for (i = 0; idev; + sockets[i].socket.dev.parent = &dev->dev; sockets[i].socket.ops = &i82092aa_operations; sockets[i].socket.resource_ops = &pccard_nonstatic_ops; ret = pcmcia_register_socket(&sockets[i].socket); diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index ea74f98a7350..72ff2f615b33 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -1298,7 +1298,7 @@ static int __init init_i82365(void) /* register sockets with the pcmcia core */ for (i = 0; i < sockets; i++) { - socket[i].socket.dev.dev = &i82365_device->dev; + socket[i].socket.dev.parent = &i82365_device->dev; socket[i].socket.ops = &pcic_operations; socket[i].socket.resource_ops = &pccard_nonstatic_ops; socket[i].socket.owner = THIS_MODULE; diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 327372b7a54e..88494149e910 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -59,7 +59,6 @@ typedef struct user_info_t { #ifdef DEBUG extern int ds_pc_debug; -#define cs_socket_name(skt) ((skt)->dev.class_id) #define ds_dbg(lvl, fmt, arg...) do { \ if (ds_pc_debug >= lvl) \ diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index b9201c2ec38b..0ce39de834c4 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -48,7 +48,6 @@ static u8 pcmcia_used_irq[NR_IRQS]; #ifdef DEBUG extern int ds_pc_debug; -#define cs_socket_name(skt) ((skt)->dev.class_id) #define ds_dbg(skt, lvl, fmt, arg...) do { \ if (ds_pc_debug >= lvl) \ diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 360c24896548..dd0ddf19ee57 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -682,7 +682,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, socket[i].socket.ops = &pd6729_operations; socket[i].socket.resource_ops = &pccard_nonstatic_ops; - socket[i].socket.dev.dev = &dev->dev; + socket[i].socket.dev.parent = &dev->dev; socket[i].socket.driver_data = &socket[i]; } diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index c3176b16b7be..bfcaad6021cf 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -616,7 +616,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star static struct resource *nonstatic_find_io_region(unsigned long base, int num, unsigned long align, struct pcmcia_socket *s) { - struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id); + struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.bus_id); struct socket_data *s_data = s->resource_data; struct pcmcia_align_data data; unsigned long min = base; @@ -650,7 +650,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num, static struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long align, int low, struct pcmcia_socket *s) { - struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id); + struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.bus_id); struct socket_data *s_data = s->resource_data; struct pcmcia_align_data data; unsigned long min, max; @@ -897,9 +897,10 @@ EXPORT_SYMBOL(pccard_nonstatic_ops); /* sysfs interface to the resource database */ -static ssize_t show_io_db(struct class_device *class_dev, char *buf) +static ssize_t show_io_db(struct device *dev, + struct device_attribute *attr, char *buf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); struct socket_data *data; struct resource_map *p; ssize_t ret = 0; @@ -920,9 +921,11 @@ static ssize_t show_io_db(struct class_device *class_dev, char *buf) return (ret); } -static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size_t count) +static ssize_t store_io_db(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); unsigned long start_addr, end_addr; unsigned int add = ADD_MANAGED_RESOURCE; ssize_t ret = 0; @@ -947,11 +950,12 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size return ret ? ret : count; } -static CLASS_DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db); +static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db); -static ssize_t show_mem_db(struct class_device *class_dev, char *buf) +static ssize_t show_mem_db(struct device *dev, + struct device_attribute *attr, char *buf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); struct socket_data *data; struct resource_map *p; ssize_t ret = 0; @@ -972,9 +976,11 @@ static ssize_t show_mem_db(struct class_device *class_dev, char *buf) return (ret); } -static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, size_t count) +static ssize_t store_mem_db(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct pcmcia_socket *s = class_get_devdata(class_dev); + struct pcmcia_socket *s = dev_get_drvdata(dev); unsigned long start_addr, end_addr; unsigned int add = ADD_MANAGED_RESOURCE; ssize_t ret = 0; @@ -999,25 +1005,25 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz return ret ? ret : count; } -static CLASS_DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db); +static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db); -static struct class_device_attribute *pccard_rsrc_attributes[] = { - &class_device_attr_available_resources_io, - &class_device_attr_available_resources_mem, +static struct device_attribute *pccard_rsrc_attributes[] = { + &dev_attr_available_resources_io, + &dev_attr_available_resources_mem, NULL, }; -static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev, +static int __devinit pccard_sysfs_add_rsrc(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); - struct class_device_attribute **attr; + struct pcmcia_socket *s = dev_get_drvdata(dev); + struct device_attribute **attr; int ret = 0; if (s->resource_ops != &pccard_nonstatic_ops) return 0; for (attr = pccard_rsrc_attributes; *attr; attr++) { - ret = class_device_create_file(class_dev, *attr); + ret = device_create_file(dev, *attr); if (ret) break; } @@ -1025,23 +1031,23 @@ static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev, return ret; } -static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev, +static void __devexit pccard_sysfs_remove_rsrc(struct device *dev, struct class_interface *class_intf) { - struct pcmcia_socket *s = class_get_devdata(class_dev); - struct class_device_attribute **attr; + struct pcmcia_socket *s = dev_get_drvdata(dev); + struct device_attribute **attr; if (s->resource_ops != &pccard_nonstatic_ops) return; for (attr = pccard_rsrc_attributes; *attr; attr++) - class_device_remove_file(class_dev, *attr); + device_remove_file(dev, *attr); } static struct class_interface pccard_rsrc_interface = { .class = &pcmcia_socket_class, - .add = &pccard_sysfs_add_rsrc, - .remove = __devexit_p(&pccard_sysfs_remove_rsrc), + .add_dev = &pccard_sysfs_add_rsrc, + .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc), }; static int __init nonstatic_sysfs_init(void) diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index e433704e026a..d2a3bea55de2 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -478,10 +478,10 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i * * Returns: the number of characters added to the buffer */ -static ssize_t show_status(struct class_device *class_dev, char *buf) +static ssize_t show_status(struct device *dev, char *buf) { struct soc_pcmcia_socket *skt = - container_of(class_dev, struct soc_pcmcia_socket, socket.dev); + container_of(dev, struct soc_pcmcia_socket, socket.dev); char *p = buf; p+=sprintf(p, "slot : %d\n", skt->nr); @@ -747,7 +747,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops add_timer(&skt->poll_timer); - class_device_create_file(&skt->socket.dev, &class_device_attr_status); + device_create_file(&skt->socket.dev, &device_attr_status); } dev_set_drvdata(dev, sinfo); diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index b005602d6b53..ea5765c3bdc0 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -40,7 +40,8 @@ #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev) -static ssize_t pccard_show_type(struct class_device *dev, char *buf) +static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); @@ -50,9 +51,10 @@ static ssize_t pccard_show_type(struct class_device *dev, char *buf) return sprintf(buf, "32-bit\n"); return sprintf(buf, "16-bit\n"); } -static CLASS_DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL); +static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL); -static ssize_t pccard_show_voltage(struct class_device *dev, char *buf) +static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); @@ -63,28 +65,31 @@ static ssize_t pccard_show_voltage(struct class_device *dev, char *buf) s->socket.Vcc % 10); return sprintf(buf, "X.XV\n"); } -static CLASS_DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL); +static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL); -static ssize_t pccard_show_vpp(struct class_device *dev, char *buf) +static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); if (!(s->state & SOCKET_PRESENT)) return -ENODEV; return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10); } -static CLASS_DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL); +static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL); -static ssize_t pccard_show_vcc(struct class_device *dev, char *buf) +static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); if (!(s->state & SOCKET_PRESENT)) return -ENODEV; return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10); } -static CLASS_DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL); +static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL); -static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret; struct pcmcia_socket *s = to_socket(dev); @@ -96,16 +101,20 @@ static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, si return ret ? ret : count; } -static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); +static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert); -static ssize_t pccard_show_card_pm_state(struct class_device *dev, char *buf) +static ssize_t pccard_show_card_pm_state(struct device *dev, + struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); return sprintf(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on"); } -static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_card_pm_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret = -EINVAL; struct pcmcia_socket *s = to_socket(dev); @@ -120,9 +129,11 @@ static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char * return ret ? -ENODEV : count; } -static CLASS_DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state); +static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state); -static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_eject(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret; struct pcmcia_socket *s = to_socket(dev); @@ -134,16 +145,20 @@ static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, siz return ret ? ret : count; } -static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); +static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject); -static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf) +static ssize_t pccard_show_irq_mask(struct device *dev, + struct device_attribute *attr, + char *buf) { struct pcmcia_socket *s = to_socket(dev); return sprintf(buf, "0x%04x\n", s->irq_mask); } -static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_irq_mask(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { ssize_t ret; struct pcmcia_socket *s = to_socket(dev); @@ -161,16 +176,19 @@ static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, return ret ? ret : count; } -static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); +static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask); -static ssize_t pccard_show_resource(struct class_device *dev, char *buf) +static ssize_t pccard_show_resource(struct device *dev, + struct device_attribute *attr, char *buf) { struct pcmcia_socket *s = to_socket(dev); return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no"); } -static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count) +static ssize_t pccard_store_resource(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { unsigned long flags; struct pcmcia_socket *s = to_socket(dev); @@ -196,7 +214,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, return count; } -static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); +static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource); static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count) @@ -279,7 +297,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size if (off + count > size) count = size - off; - s = to_socket(container_of(kobj, struct class_device, kobj)); + s = to_socket(container_of(kobj, struct device, kobj)); if (!(s->state & SOCKET_PRESENT)) return -ENODEV; @@ -296,7 +314,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count) { - struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj)); + struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj)); cisdump_t *cis; int error; @@ -335,16 +353,16 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz } -static struct class_device_attribute *pccard_socket_attributes[] = { - &class_device_attr_card_type, - &class_device_attr_card_voltage, - &class_device_attr_card_vpp, - &class_device_attr_card_vcc, - &class_device_attr_card_insert, - &class_device_attr_card_pm_state, - &class_device_attr_card_eject, - &class_device_attr_card_irq_mask, - &class_device_attr_available_resources_setup_done, +static struct device_attribute *pccard_socket_attributes[] = { + &dev_attr_card_type, + &dev_attr_card_voltage, + &dev_attr_card_vpp, + &dev_attr_card_vcc, + &dev_attr_card_insert, + &dev_attr_card_pm_state, + &dev_attr_card_eject, + &dev_attr_card_irq_mask, + &dev_attr_available_resources_setup_done, NULL, }; @@ -355,35 +373,35 @@ static struct bin_attribute pccard_cis_attr = { .write = pccard_store_cis, }; -static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev, +static int __devinit pccard_sysfs_add_socket(struct device *dev, struct class_interface *class_intf) { - struct class_device_attribute **attr; + struct device_attribute **attr; int ret = 0; for (attr = pccard_socket_attributes; *attr; attr++) { - ret = class_device_create_file(class_dev, *attr); + ret = device_create_file(dev, *attr); if (ret) break; } if (!ret) - ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr); + ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr); return ret; } -static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev, +static void __devexit pccard_sysfs_remove_socket(struct device *dev, struct class_interface *class_intf) { - struct class_device_attribute **attr; + struct device_attribute **attr; - sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr); + sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr); for (attr = pccard_socket_attributes; *attr; attr++) - class_device_remove_file(class_dev, *attr); + device_remove_file(dev, *attr); } struct class_interface pccard_sysfs_interface = { .class = &pcmcia_socket_class, - .add = &pccard_sysfs_add_socket, - .remove = __devexit_p(&pccard_sysfs_remove_socket), + .add_dev = &pccard_sysfs_add_socket, + .remove_dev = __devexit_p(&pccard_sysfs_remove_socket), }; diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index 2d2f415f80a8..c158cf38b9dd 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c @@ -512,7 +512,7 @@ static int __init init_tcic(void) for (i = 0; i < sockets; i++) { socket_table[i].socket.ops = &tcic_operations; socket_table[i].socket.resource_ops = &pccard_nonstatic_ops; - socket_table[i].socket.dev.dev = &tcic_device.dev; + socket_table[i].socket.dev.parent = &tcic_device.dev; ret = pcmcia_register_socket(&socket_table[i].socket); if (ret && i) pcmcia_unregister_socket(&socket_table[0].socket); diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index da471bddc972..a61d768f6e0e 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1104,7 +1104,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i /* prepare pcmcia_socket */ socket->socket.ops = ¥ta_socket_operations; socket->socket.resource_ops = &pccard_nonstatic_ops; - socket->socket.dev.dev = &dev->dev; + socket->socket.dev.parent = &dev->dev; socket->socket.driver_data = socket; socket->socket.owner = THIS_MODULE; socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD; diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index 623a0fc0dae1..6e84258b94de 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h @@ -284,7 +284,7 @@ struct pcmcia_socket { #endif /* socket device */ - struct class_device dev; + struct device dev; void *driver_data; /* data internal to the socket driver */ }; -- cgit v1.2.3 From 2943ecf2ed32632473c06f1975db47a7aa98c10f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 22 Jan 2007 13:45:38 -0800 Subject: Driver core: convert SPI code to use struct device Converts from using struct "class_device" to "struct device" making everything show up properly in /sys/devices/ with symlinks from the /sys/class directory. Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/spi/pxa2xx_spi.c | 2 +- drivers/spi/spi.c | 32 ++++++++++++++++---------------- drivers/spi/spi_bitbang.c | 6 +++--- drivers/spi/spi_butterfly.c | 4 ++-- include/linux/spi/spi.h | 10 +++++----- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 8b41f9cc2560..dccdc50b0296 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -1234,7 +1234,7 @@ static int init_queue(struct driver_data *drv_data) INIT_WORK(&drv_data->pump_messages, pump_messages); drv_data->workqueue = create_singlethread_workqueue( - drv_data->master->cdev.dev->bus_id); + drv_data->master->dev.parent->bus_id); if (drv_data->workqueue == NULL) return -EBUSY; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 6307428d2c94..35d8c01b42ac 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -193,7 +193,7 @@ struct spi_device *__init_or_module spi_new_device(struct spi_master *master, struct spi_board_info *chip) { struct spi_device *proxy; - struct device *dev = master->cdev.dev; + struct device *dev = &master->dev; int status; /* NOTE: caller did any chip->bus_num checks necessary */ @@ -215,7 +215,7 @@ spi_new_device(struct spi_master *master, struct spi_board_info *chip) proxy->modalias = chip->modalias; snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id, - "%s.%u", master->cdev.class_id, + "%s.%u", master->dev.bus_id, chip->chip_select); proxy->dev.parent = dev; proxy->dev.bus = &spi_bus_type; @@ -290,7 +290,7 @@ static void __init_or_module scan_boardinfo(struct spi_master *master) { struct boardinfo *bi; - struct device *dev = master->cdev.dev; + struct device *dev = master->dev.parent; down(&board_lock); list_for_each_entry(bi, &board_list, list) { @@ -319,18 +319,18 @@ scan_boardinfo(struct spi_master *master) /*-------------------------------------------------------------------------*/ -static void spi_master_release(struct class_device *cdev) +static void spi_master_release(struct device *dev) { struct spi_master *master; - master = container_of(cdev, struct spi_master, cdev); + master = container_of(dev, struct spi_master, dev); kfree(master); } static struct class spi_master_class = { .name = "spi_master", .owner = THIS_MODULE, - .release = spi_master_release, + .dev_release = spi_master_release, }; @@ -364,9 +364,9 @@ spi_alloc_master(struct device *dev, unsigned size) if (!master) return NULL; - class_device_initialize(&master->cdev); - master->cdev.class = &spi_master_class; - master->cdev.dev = get_device(dev); + device_initialize(&master->dev); + master->dev.class = &spi_master_class; + master->dev.parent = get_device(dev); spi_master_set_devdata(master, &master[1]); return master; @@ -396,7 +396,7 @@ int __init_or_module spi_register_master(struct spi_master *master) { static atomic_t dyn_bus_id = ATOMIC_INIT((1<<16) - 1); - struct device *dev = master->cdev.dev; + struct device *dev = master->dev.parent; int status = -ENODEV; int dynamic = 0; @@ -412,12 +412,12 @@ spi_register_master(struct spi_master *master) /* register the device, then userspace will see it. * registration fails if the bus ID is in use. */ - snprintf(master->cdev.class_id, sizeof master->cdev.class_id, + snprintf(master->dev.bus_id, sizeof master->dev.bus_id, "spi%u", master->bus_num); - status = class_device_add(&master->cdev); + status = device_add(&master->dev); if (status < 0) goto done; - dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id, + dev_dbg(dev, "registered master %s%s\n", master->dev.bus_id, dynamic ? " (dynamic)" : ""); /* populate children from any spi device tables */ @@ -449,8 +449,8 @@ void spi_unregister_master(struct spi_master *master) { int dummy; - dummy = device_for_each_child(master->cdev.dev, NULL, __unregister); - class_device_unregister(&master->cdev); + dummy = device_for_each_child(&master->dev, NULL, __unregister); + device_unregister(&master->dev); } EXPORT_SYMBOL_GPL(spi_unregister_master); @@ -471,7 +471,7 @@ struct spi_master *spi_busnum_to_master(u16 bus_num) down(&spi_master_class.sem); list_for_each_entry(cdev, &spi_master_class.children, node) { - m = container_of(cdev, struct spi_master, cdev); + m = container_of(cdev, struct spi_master, dev.kobj); if (m->bus_num == bus_num) { master = spi_master_get(m); break; diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 57289b61d0be..4638e6c83715 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -479,7 +479,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) /* this task is the only thing to touch the SPI bits */ bitbang->busy = 0; bitbang->workqueue = create_singlethread_workqueue( - bitbang->master->cdev.dev->bus_id); + bitbang->master->dev.parent->bus_id); if (bitbang->workqueue == NULL) { status = -EBUSY; goto err1; @@ -513,14 +513,14 @@ int spi_bitbang_stop(struct spi_bitbang *bitbang) while (!list_empty(&bitbang->queue) && limit--) { spin_unlock_irq(&bitbang->lock); - dev_dbg(bitbang->master->cdev.dev, "wait for queue\n"); + dev_dbg(&bitbang->master->dev, "wait for queue\n"); msleep(10); spin_lock_irq(&bitbang->lock); } spin_unlock_irq(&bitbang->lock); if (!list_empty(&bitbang->queue)) { - dev_err(bitbang->master->cdev.dev, "queue didn't empty\n"); + dev_err(&bitbang->master->dev, "queue didn't empty\n"); return -EBUSY; } diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c index 312987a03210..31b7970ae463 100644 --- a/drivers/spi/spi_butterfly.c +++ b/drivers/spi/spi_butterfly.c @@ -246,7 +246,7 @@ static void butterfly_attach(struct parport *p) * and no way to be selective about what it binds to. */ - /* FIXME where should master->cdev.dev come from? + /* FIXME where should master->dev.parent come from? * e.g. /sys/bus/pnp0/00:0b, some PCI thing, etc * setting up a platform device like this is an ugly kluge... */ @@ -386,7 +386,7 @@ static void butterfly_detach(struct parport *p) butterfly = NULL; /* stop() unregisters child devices too */ - pdev = to_platform_device(pp->bitbang.master->cdev.dev); + pdev = to_platform_device(pp->bitbang.master->dev.parent); status = spi_bitbang_stop(&pp->bitbang); /* turn off VCC */ diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 176f6e36dbfa..8c2edd82a073 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -170,7 +170,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * message's completion function when the transaction completes. */ struct spi_master { - struct class_device cdev; + struct device dev; /* other than negative (== assign one dynamically), bus_num is fully * board-specific. usually that simplifies to being SOC-specific. @@ -216,17 +216,17 @@ struct spi_master { static inline void *spi_master_get_devdata(struct spi_master *master) { - return class_get_devdata(&master->cdev); + return dev_get_drvdata(&master->dev); } static inline void spi_master_set_devdata(struct spi_master *master, void *data) { - class_set_devdata(&master->cdev, data); + dev_set_drvdata(&master->dev, data); } static inline struct spi_master *spi_master_get(struct spi_master *master) { - if (!master || !class_device_get(&master->cdev)) + if (!master || !get_device(&master->dev)) return NULL; return master; } @@ -234,7 +234,7 @@ static inline struct spi_master *spi_master_get(struct spi_master *master) static inline void spi_master_put(struct spi_master *master) { if (master) - class_device_put(&master->cdev); + put_device(&master->dev); } -- cgit v1.2.3 From 43cb76d91ee85f579a69d42bc8efc08bac560278 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 9 Apr 2002 12:14:34 -0700 Subject: Network: convert network devices to use struct device instead of class_device This lets the network core have the ability to handle suspend/resume issues, if it wants to. Thanks to Frederik Deweerdt for the arm driver fixes. Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 33 ++-- drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 11 +- drivers/net/arm/at91_ether.c | 2 +- drivers/net/arm/etherh.c | 2 +- drivers/net/bonding/bond_sysfs.c | 287 ++++++++++++++++++------------ drivers/net/iseries_veth.c | 2 +- drivers/net/macb.c | 36 ++-- drivers/net/smc911x.c | 2 +- drivers/net/smc91x.c | 2 +- drivers/net/wireless/hostap/hostap_main.c | 2 +- drivers/net/wireless/orinoco.c | 4 +- drivers/net/wireless/orinoco_cs.c | 2 +- drivers/net/wireless/spectrum_cs.c | 2 +- include/linux/netdevice.h | 5 +- net/bridge/br_if.c | 2 +- net/bridge/br_sysfs_br.c | 234 +++++++++++++----------- net/bridge/br_sysfs_if.c | 2 +- net/core/dev.c | 6 +- net/core/net-sysfs.c | 175 +++++++++--------- net/core/skbuff.c | 2 +- 20 files changed, 451 insertions(+), 362 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 705eb1d0e554..af5ee2ec4499 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -958,16 +958,17 @@ struct ipoib_dev_priv *ipoib_intf_alloc(const char *name) return netdev_priv(dev); } -static ssize_t show_pkey(struct class_device *cdev, char *buf) +static ssize_t show_pkey(struct device *dev, + struct device_attribute *attr, char *buf) { - struct ipoib_dev_priv *priv = - netdev_priv(container_of(cdev, struct net_device, class_dev)); + struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev)); return sprintf(buf, "0x%04x\n", priv->pkey); } -static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); +static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL); -static ssize_t create_child(struct class_device *cdev, +static ssize_t create_child(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { int pkey; @@ -985,14 +986,14 @@ static ssize_t create_child(struct class_device *cdev, */ pkey |= 0x8000; - ret = ipoib_vlan_add(container_of(cdev, struct net_device, class_dev), - pkey); + ret = ipoib_vlan_add(to_net_dev(dev), pkey); return ret ? ret : count; } -static CLASS_DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child); +static DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child); -static ssize_t delete_child(struct class_device *cdev, +static ssize_t delete_child(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { int pkey; @@ -1004,18 +1005,16 @@ static ssize_t delete_child(struct class_device *cdev, if (pkey < 0 || pkey > 0xffff) return -EINVAL; - ret = ipoib_vlan_delete(container_of(cdev, struct net_device, class_dev), - pkey); + ret = ipoib_vlan_delete(to_net_dev(dev), pkey); return ret ? ret : count; } -static CLASS_DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child); +static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child); int ipoib_add_pkey_attr(struct net_device *dev) { - return class_device_create_file(&dev->class_dev, - &class_device_attr_pkey); + return device_create_file(&dev->dev, &dev_attr_pkey); } static struct net_device *ipoib_add_port(const char *format, @@ -1083,11 +1082,9 @@ static struct net_device *ipoib_add_port(const char *format, if (ipoib_add_pkey_attr(priv->dev)) goto sysfs_failed; - if (class_device_create_file(&priv->dev->class_dev, - &class_device_attr_create_child)) + if (device_create_file(&priv->dev->dev, &dev_attr_create_child)) goto sysfs_failed; - if (class_device_create_file(&priv->dev->class_dev, - &class_device_attr_delete_child)) + if (device_create_file(&priv->dev->dev, &dev_attr_delete_child)) goto sysfs_failed; return priv->dev; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index f887780e8093..085eafe6667c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -42,15 +42,15 @@ #include "ipoib.h" -static ssize_t show_parent(struct class_device *class_dev, char *buf) +static ssize_t show_parent(struct device *d, struct device_attribute *attr, + char *buf) { - struct net_device *dev = - container_of(class_dev, struct net_device, class_dev); + struct net_device *dev = to_net_dev(d); struct ipoib_dev_priv *priv = netdev_priv(dev); return sprintf(buf, "%s\n", priv->parent->name); } -static CLASS_DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); +static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL); int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) { @@ -118,8 +118,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) if (ipoib_add_pkey_attr(priv->dev)) goto sysfs_failed; - if (class_device_create_file(&priv->dev->class_dev, - &class_device_attr_parent)) + if (device_create_file(&priv->dev->dev, &dev_attr_parent)) goto sysfs_failed; list_add_tail(&priv->list, &ppriv->child_intfs); diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index fada15d959de..1621b8fe35cf 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -641,7 +641,7 @@ static void at91ether_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); + strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } static const struct ethtool_ops at91ether_ethtool_ops = { diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index f3faa4fe58e7..72c41f5907f2 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -587,7 +587,7 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i { strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev->class_dev.dev->bus_id, + strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ced9ed8f995a..0e610aa1fdf9 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -39,8 +39,7 @@ /* #define BONDING_DEBUG 1 */ #include "bonding.h" -#define to_class_dev(obj) container_of(obj,struct class_device,kobj) -#define to_net_dev(class) container_of(class, struct net_device, class_dev) +#define to_dev(obj) container_of(obj,struct device,kobj) #define to_bond(cd) ((struct bonding *)(to_net_dev(cd)->priv)) /*---------------------------- Declarations -------------------------------*/ @@ -154,7 +153,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t * If it's > expected, then there's a file open, * and we have to fail. */ - if (atomic_read(&bond->dev->class_dev.kobj.kref.refcount) + if (atomic_read(&bond->dev->dev.kobj.kref.refcount) > expected_refcount){ rtnl_unlock(); printk(KERN_INFO DRV_NAME @@ -201,13 +200,13 @@ int bond_create_slave_symlinks(struct net_device *master, struct net_device *sla int ret = 0; /* first, create a link from the slave back to the master */ - ret = sysfs_create_link(&(slave->class_dev.kobj), &(master->class_dev.kobj), + ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj), "master"); if (ret) return ret; /* next, create a link from the master to the slave */ sprintf(linkname,"slave_%s",slave->name); - ret = sysfs_create_link(&(master->class_dev.kobj), &(slave->class_dev.kobj), + ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj), linkname); return ret; @@ -217,20 +216,21 @@ void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *s { char linkname[IFNAMSIZ+7]; - sysfs_remove_link(&(slave->class_dev.kobj), "master"); + sysfs_remove_link(&(slave->dev.kobj), "master"); sprintf(linkname,"slave_%s",slave->name); - sysfs_remove_link(&(master->class_dev.kobj), linkname); + sysfs_remove_link(&(master->dev.kobj), linkname); } /* * Show the slaves in the current bond. */ -static ssize_t bonding_show_slaves(struct class_device *cd, char *buf) +static ssize_t bonding_show_slaves(struct device *d, + struct device_attribute *attr, char *buf) { struct slave *slave; int i, res = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); read_lock_bh(&bond->lock); bond_for_each_slave(bond, slave, i) { @@ -254,14 +254,16 @@ static ssize_t bonding_show_slaves(struct class_device *cd, char *buf) * up for this to succeed. * This function is largely the same flow as bonding_update_bonds(). */ -static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, size_t count) +static ssize_t bonding_store_slaves(struct device *d, + struct device_attribute *attr, + const char *buffer, size_t count) { char command[IFNAMSIZ + 1] = { 0, }; char *ifname; int i, res, found, ret = count; struct slave *slave; struct net_device *dev = NULL; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); /* Quick sanity check -- is the bond interface up? */ if (!(bond->dev->flags & IFF_UP)) { @@ -387,25 +389,28 @@ out: return ret; } -static CLASS_DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves); +static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves); /* * Show and set the bonding mode. The bond interface must be down to * change the mode. */ -static ssize_t bonding_show_mode(struct class_device *cd, char *buf) +static ssize_t bonding_show_mode(struct device *d, + struct device_attribute *attr, char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%s %d\n", bond_mode_tbl[bond->params.mode].modename, bond->params.mode) + 1; } -static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_mode(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { printk(KERN_ERR DRV_NAME @@ -438,16 +443,18 @@ static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size out: return ret; } -static CLASS_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode); +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode); /* * Show and set the bonding transmit hash method. The bond interface must be down to * change the xmit hash policy. */ -static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf) +static ssize_t bonding_show_xmit_hash(struct device *d, + struct device_attribute *attr, + char *buf) { int count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if ((bond->params.mode != BOND_MODE_XOR) && (bond->params.mode != BOND_MODE_8023AD)) { @@ -462,10 +469,12 @@ static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf) return count; } -static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_xmit_hash(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { printk(KERN_ERR DRV_NAME @@ -501,24 +510,28 @@ static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, out: return ret; } -static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); +static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash); /* * Show and set arp_validate. */ -static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf) +static ssize_t bonding_show_arp_validate(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%s %d\n", arp_validate_tbl[bond->params.arp_validate].modename, bond->params.arp_validate) + 1; } -static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_arp_validate(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); new_value = bond_parse_parm((char *)buf, arp_validate_tbl); if (new_value < 0) { @@ -548,7 +561,7 @@ static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *b return count; } -static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); +static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); /* * Show and set the arp timer interval. There are two tricky bits @@ -556,17 +569,21 @@ static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_valid * MII monitoring. Second, if the ARP timer isn't running, we must * start it. */ -static ssize_t bonding_show_arp_interval(struct class_device *cd, char *buf) +static ssize_t bonding_show_arp_interval(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.arp_interval) + 1; } -static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_arp_interval(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { printk(KERN_ERR DRV_NAME @@ -638,15 +655,17 @@ static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *b out: return ret; } -static CLASS_DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval); +static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval); /* * Show and set the arp targets. */ -static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf) +static ssize_t bonding_show_arp_targets(struct device *d, + struct device_attribute *attr, + char *buf) { int i, res = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { if (bond->params.arp_targets[i]) @@ -660,11 +679,13 @@ static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf) return res; } -static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_arp_targets(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { u32 newtarget; int i = 0, done = 0, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); u32 *targets; targets = bond->params.arp_targets; @@ -742,24 +763,28 @@ static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *bu out: return ret; } -static CLASS_DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); +static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); /* * Show and set the up and down delays. These must be multiples of the * MII monitoring value, and are stored internally as the multiplier. * Thus, we must translate to MS for the real world. */ -static ssize_t bonding_show_downdelay(struct class_device *cd, char *buf) +static ssize_t bonding_show_downdelay(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1; } -static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_downdelay(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (!(bond->params.miimon)) { printk(KERN_ERR DRV_NAME @@ -800,20 +825,24 @@ static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, out: return ret; } -static CLASS_DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay); +static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay); -static ssize_t bonding_show_updelay(struct class_device *cd, char *buf) +static ssize_t bonding_show_updelay(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1; } -static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_updelay(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (!(bond->params.miimon)) { printk(KERN_ERR DRV_NAME @@ -854,25 +883,29 @@ static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, s out: return ret; } -static CLASS_DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay); +static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay); /* * Show and set the LACP interval. Interface must be down, and the mode * must be set to 802.3ad mode. */ -static ssize_t bonding_show_lacp(struct class_device *cd, char *buf) +static ssize_t bonding_show_lacp(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%s %d\n", bond_lacp_tbl[bond->params.lacp_fast].modename, bond->params.lacp_fast) + 1; } -static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_lacp(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->dev->flags & IFF_UP) { printk(KERN_ERR DRV_NAME @@ -906,7 +939,7 @@ static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size out: return ret; } -static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); +static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); /* * Show and set the MII monitor interval. There are two tricky bits @@ -914,17 +947,21 @@ static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bondin * ARP monitoring. Second, if the timer isn't running, we must * start it. */ -static ssize_t bonding_show_miimon(struct class_device *cd, char *buf) +static ssize_t bonding_show_miimon(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.miimon) + 1; } -static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_miimon(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { printk(KERN_ERR DRV_NAME @@ -1000,7 +1037,7 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si out: return ret; } -static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon); +static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon); /* * Show and set the primary slave. The store function is much @@ -1009,10 +1046,12 @@ static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding * The bond must be a mode that supports a primary for this be * set. */ -static ssize_t bonding_show_primary(struct class_device *cd, char *buf) +static ssize_t bonding_show_primary(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->primary_slave) count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1; @@ -1022,11 +1061,13 @@ static ssize_t bonding_show_primary(struct class_device *cd, char *buf) return count; } -static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_primary(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int i; struct slave *slave; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); write_lock_bh(&bond->lock); if (!USES_PRIMARY(bond->params.mode)) { @@ -1065,22 +1106,26 @@ out: write_unlock_bh(&bond->lock); return count; } -static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary); +static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary); /* * Show and set the use_carrier flag. */ -static ssize_t bonding_show_carrier(struct class_device *cd, char *buf) +static ssize_t bonding_show_carrier(struct device *d, + struct device_attribute *attr, + char *buf) { - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.use_carrier) + 1; } -static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_carrier(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int new_value, ret = count; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (sscanf(buf, "%d", &new_value) != 1) { @@ -1102,16 +1147,18 @@ static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, s out: return count; } -static CLASS_DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier); +static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier); /* * Show and set currently active_slave. */ -static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf) +static ssize_t bonding_show_active_slave(struct device *d, + struct device_attribute *attr, + char *buf) { struct slave *curr; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); int count; @@ -1126,13 +1173,15 @@ static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf) return count; } -static ssize_t bonding_store_active_slave(struct class_device *cd, const char *buf, size_t count) +static ssize_t bonding_store_active_slave(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) { int i; struct slave *slave; struct slave *old_active = NULL; struct slave *new_active = NULL; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); write_lock_bh(&bond->lock); if (!USES_PRIMARY(bond->params.mode)) { @@ -1194,16 +1243,18 @@ out: return count; } -static CLASS_DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave); +static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave); /* * Show link status of the bond interface. */ -static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf) +static ssize_t bonding_show_mii_status(struct device *d, + struct device_attribute *attr, + char *buf) { struct slave *curr; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); read_lock(&bond->curr_slave_lock); curr = bond->curr_active_slave; @@ -1211,16 +1262,18 @@ static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf) return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1; } -static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); +static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL); /* * Show current 802.3ad aggregator ID. */ -static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_aggregator(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1231,16 +1284,18 @@ static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf) return count; } -static CLASS_DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL); +static DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL); /* * Show number of active 802.3ad ports. */ -static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_num_ports(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1251,16 +1306,18 @@ static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf) return count; } -static CLASS_DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL); +static DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL); /* * Show current 802.3ad actor key. */ -static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_actor_key(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1271,16 +1328,18 @@ static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf) return count; } -static CLASS_DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL); +static DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL); /* * Show current 802.3ad partner key. */ -static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_partner_key(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1291,16 +1350,18 @@ static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf) return count; } -static CLASS_DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL); +static DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL); /* * Show current 802.3ad partner mac. */ -static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf) +static ssize_t bonding_show_ad_partner_mac(struct device *d, + struct device_attribute *attr, + char *buf) { int count = 0; - struct bonding *bond = to_bond(cd); + struct bonding *bond = to_bond(d); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; @@ -1319,30 +1380,30 @@ static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf) return count; } -static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); +static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); static struct attribute *per_bond_attrs[] = { - &class_device_attr_slaves.attr, - &class_device_attr_mode.attr, - &class_device_attr_arp_validate.attr, - &class_device_attr_arp_interval.attr, - &class_device_attr_arp_ip_target.attr, - &class_device_attr_downdelay.attr, - &class_device_attr_updelay.attr, - &class_device_attr_lacp_rate.attr, - &class_device_attr_xmit_hash_policy.attr, - &class_device_attr_miimon.attr, - &class_device_attr_primary.attr, - &class_device_attr_use_carrier.attr, - &class_device_attr_active_slave.attr, - &class_device_attr_mii_status.attr, - &class_device_attr_ad_aggregator.attr, - &class_device_attr_ad_num_ports.attr, - &class_device_attr_ad_actor_key.attr, - &class_device_attr_ad_partner_key.attr, - &class_device_attr_ad_partner_mac.attr, + &dev_attr_slaves.attr, + &dev_attr_mode.attr, + &dev_attr_arp_validate.attr, + &dev_attr_arp_interval.attr, + &dev_attr_arp_ip_target.attr, + &dev_attr_downdelay.attr, + &dev_attr_updelay.attr, + &dev_attr_lacp_rate.attr, + &dev_attr_xmit_hash_policy.attr, + &dev_attr_miimon.attr, + &dev_attr_primary.attr, + &dev_attr_use_carrier.attr, + &dev_attr_active_slave.attr, + &dev_attr_mii_status.attr, + &dev_attr_ad_aggregator.attr, + &dev_attr_ad_num_ports.attr, + &dev_attr_ad_actor_key.attr, + &dev_attr_ad_partner_key.attr, + &dev_attr_ad_partner_mac.attr, NULL, }; @@ -1367,7 +1428,7 @@ int bond_create_sysfs(void) if (!firstbond) return -ENODEV; - netdev_class = firstbond->dev->class_dev.class; + netdev_class = firstbond->dev->dev.class; if (!netdev_class) return -ENODEV; @@ -1395,13 +1456,13 @@ int bond_create_sysfs_entry(struct bonding *bond) struct net_device *dev = bond->dev; int err; - err = sysfs_create_group(&(dev->class_dev.kobj), &bonding_group); + err = sysfs_create_group(&(dev->dev.kobj), &bonding_group); if (err) { printk(KERN_EMERG "eek! didn't create group!\n"); } if (expected_refcount < 1) - expected_refcount = atomic_read(&bond->dev->class_dev.kobj.kref.refcount); + expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount); return err; } @@ -1412,6 +1473,6 @@ void bond_destroy_sysfs_entry(struct bonding *bond) { struct net_device *dev = bond->dev; - sysfs_remove_group(&(dev->class_dev.kobj), &bonding_group); + sysfs_remove_group(&(dev->dev.kobj), &bonding_group); } diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 2194b567239f..0e9ba3c3faf7 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -1102,7 +1102,7 @@ static struct net_device * __init veth_probe_one(int vlan, } kobject_init(&port->kobject); - port->kobject.parent = &dev->class_dev.kobj; + port->kobject.parent = &dev->dev.kobj; port->kobject.ktype = &veth_port_ktype; kobject_set_name(&port->kobject, "veth_port"); if (0 != kobject_add(&port->kobject)) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 25b559b5d5ed..2af204598144 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -27,8 +27,6 @@ #include "macb.h" -#define to_net_dev(class) container_of(class, struct net_device, class_dev) - #define RX_BUFFER_SIZE 128 #define RX_RING_SIZE 512 #define RX_RING_BYTES (sizeof(struct dma_desc) * RX_RING_SIZE) @@ -945,10 +943,10 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return ret; } -static ssize_t macb_mii_show(const struct class_device *cd, char *buf, +static ssize_t macb_mii_show(const struct device *_dev, char *buf, unsigned long addr) { - struct net_device *dev = to_net_dev(cd); + struct net_device *dev = to_net_dev(_dev); struct macb *bp = netdev_priv(dev); ssize_t ret = -EINVAL; @@ -962,11 +960,13 @@ static ssize_t macb_mii_show(const struct class_device *cd, char *buf, } #define MII_ENTRY(name, addr) \ -static ssize_t show_##name(struct class_device *cd, char *buf) \ +static ssize_t show_##name(struct device *_dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ - return macb_mii_show(cd, buf, addr); \ + return macb_mii_show(_dev, buf, addr); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) MII_ENTRY(bmcr, MII_BMCR); MII_ENTRY(bmsr, MII_BMSR); @@ -977,13 +977,13 @@ MII_ENTRY(lpa, MII_LPA); MII_ENTRY(expansion, MII_EXPANSION); static struct attribute *macb_mii_attrs[] = { - &class_device_attr_bmcr.attr, - &class_device_attr_bmsr.attr, - &class_device_attr_physid1.attr, - &class_device_attr_physid2.attr, - &class_device_attr_advertise.attr, - &class_device_attr_lpa.attr, - &class_device_attr_expansion.attr, + &dev_attr_bmcr.attr, + &dev_attr_bmsr.attr, + &dev_attr_physid1.attr, + &dev_attr_physid2.attr, + &dev_attr_advertise.attr, + &dev_attr_lpa.attr, + &dev_attr_expansion.attr, NULL, }; @@ -994,17 +994,17 @@ static struct attribute_group macb_mii_group = { static void macb_unregister_sysfs(struct net_device *net) { - struct class_device *class_dev = &net->class_dev; + struct device *_dev = &net->dev; - sysfs_remove_group(&class_dev->kobj, &macb_mii_group); + sysfs_remove_group(&_dev->kobj, &macb_mii_group); } static int macb_register_sysfs(struct net_device *net) { - struct class_device *class_dev = &net->class_dev; + struct device *_dev = &net->dev; int ret; - ret = sysfs_create_group(&class_dev->kobj, &macb_mii_group); + ret = sysfs_create_group(&_dev->kobj, &macb_mii_group); if (ret) printk(KERN_WARNING "%s: sysfs mii attribute registration failed: %d\n", diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 43af61438449..c95614131980 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -1659,7 +1659,7 @@ smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strncpy(info->driver, CARDNAME, sizeof(info->driver)); strncpy(info->version, version, sizeof(info->version)); - strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); + strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } static int smc911x_ethtool_nwayreset(struct net_device *dev) diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index e62a9586fb95..49f4b7712ebf 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1712,7 +1712,7 @@ smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strncpy(info->driver, CARDNAME, sizeof(info->driver)); strncpy(info->version, version, sizeof(info->version)); - strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); + strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info)); } static int smc_ethtool_nwayreset(struct net_device *dev) diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 04c19cefa1da..9077e6edde34 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -84,7 +84,7 @@ struct net_device * hostap_add_interface(struct local_info *local, if (strchr(dev->name, '%')) ret = dev_alloc_name(dev, dev->name); - SET_NETDEV_DEV(dev, mdev->class_dev.dev); + SET_NETDEV_DEV(dev, mdev->dev.parent); if (ret >= 0) ret = register_netdevice(dev); diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 936c888e03e1..656f216b857f 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -4293,8 +4293,8 @@ static void orinoco_get_drvinfo(struct net_device *dev, strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1); strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1); - if (dev->class_dev.dev) - strncpy(info->bus_info, dev->class_dev.dev->bus_id, + if (dev->dev.parent) + strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info) - 1); else snprintf(info->bus_info, sizeof(info->bus_info) - 1, diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index d08ae8d2726c..d1e502236b2a 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -332,7 +332,7 @@ orinoco_cs_config(struct pcmcia_device *link) /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id, + "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index cf2d1486b01d..af70460f008a 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -806,7 +806,7 @@ spectrum_cs_config(struct pcmcia_device *link) /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id, + "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index fea0d9db6846..2e37f5012788 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -529,10 +529,11 @@ struct net_device struct net_bridge_port *br_port; /* class/net/name entry */ - struct class_device class_dev; + struct device dev; /* space for optional statistics and wireless sysfs groups */ struct attribute_group *sysfs_groups[3]; }; +#define to_net_dev(d) container_of(d, struct net_device, dev) #define NETDEV_ALIGN 32 #define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) @@ -548,7 +549,7 @@ static inline void *netdev_priv(struct net_device *dev) /* Set the sysfs physical device reference for the network logical device * if set prior to registration will cause a symlink during initialization. */ -#define SET_NETDEV_DEV(net, pdev) ((net)->class_dev.dev = (pdev)) +#define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev)) struct packet_type { __be16 type; /* This is really htons(ether_type). */ diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 55bb2634c088..2b7c2c7dad48 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -286,7 +286,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, kobject_init(&p->kobj); kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); p->kobj.ktype = &brport_ktype; - p->kobj.parent = &(dev->class_dev.kobj); + p->kobj.parent = &(dev->dev.kobj); p->kobj.kset = NULL; return p; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index de9d1a9473f2..ce10464716a7 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -21,18 +21,17 @@ #include "br_private.h" -#define to_class_dev(obj) container_of(obj,struct class_device,kobj) -#define to_net_dev(class) container_of(class, struct net_device, class_dev) +#define to_dev(obj) container_of(obj, struct device, kobj) #define to_bridge(cd) ((struct net_bridge *)(to_net_dev(cd)->priv)) /* * Common code for storing bridge parameters. */ -static ssize_t store_bridge_parm(struct class_device *cd, +static ssize_t store_bridge_parm(struct device *d, const char *buf, size_t len, void (*set)(struct net_bridge *, unsigned long)) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); char *endp; unsigned long val; @@ -50,9 +49,10 @@ static ssize_t store_bridge_parm(struct class_device *cd, } -static ssize_t show_forward_delay(struct class_device *cd, char *buf) +static ssize_t show_forward_delay(struct device *d, + struct device_attribute *attr, char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay)); } @@ -64,18 +64,20 @@ static void set_forward_delay(struct net_bridge *br, unsigned long val) br->bridge_forward_delay = delay; } -static ssize_t store_forward_delay(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_forward_delay(struct device *d, + struct device_attribute *attr, + const char *buf, size_t len) { - return store_bridge_parm(cd, buf, len, set_forward_delay); + return store_bridge_parm(d, buf, len, set_forward_delay); } -static CLASS_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, - show_forward_delay, store_forward_delay); +static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR, + show_forward_delay, store_forward_delay); -static ssize_t show_hello_time(struct class_device *cd, char *buf) +static ssize_t show_hello_time(struct device *d, struct device_attribute *attr, + char *buf) { return sprintf(buf, "%lu\n", - jiffies_to_clock_t(to_bridge(cd)->hello_time)); + jiffies_to_clock_t(to_bridge(d)->hello_time)); } static void set_hello_time(struct net_bridge *br, unsigned long val) @@ -86,19 +88,20 @@ static void set_hello_time(struct net_bridge *br, unsigned long val) br->bridge_hello_time = t; } -static ssize_t store_hello_time(struct class_device *cd, const char *buf, +static ssize_t store_hello_time(struct device *d, + struct device_attribute *attr, const char *buf, size_t len) { - return store_bridge_parm(cd, buf, len, set_hello_time); + return store_bridge_parm(d, buf, len, set_hello_time); } +static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, + store_hello_time); -static CLASS_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time, - store_hello_time); - -static ssize_t show_max_age(struct class_device *cd, char *buf) +static ssize_t show_max_age(struct device *d, struct device_attribute *attr, + char *buf) { return sprintf(buf, "%lu\n", - jiffies_to_clock_t(to_bridge(cd)->max_age)); + jiffies_to_clock_t(to_bridge(d)->max_age)); } static void set_max_age(struct net_bridge *br, unsigned long val) @@ -109,18 +112,17 @@ static void set_max_age(struct net_bridge *br, unsigned long val) br->bridge_max_age = t; } -static ssize_t store_max_age(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_max_age(struct device *d, struct device_attribute *attr, + const char *buf, size_t len) { - return store_bridge_parm(cd, buf, len, set_max_age); + return store_bridge_parm(d, buf, len, set_max_age); } +static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age); -static CLASS_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, - store_max_age); - -static ssize_t show_ageing_time(struct class_device *cd, char *buf) +static ssize_t show_ageing_time(struct device *d, + struct device_attribute *attr, char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time)); } @@ -129,17 +131,19 @@ static void set_ageing_time(struct net_bridge *br, unsigned long val) br->ageing_time = clock_t_to_jiffies(val); } -static ssize_t store_ageing_time(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_ageing_time(struct device *d, + struct device_attribute *attr, + const char *buf, size_t len) { - return store_bridge_parm(cd, buf, len, set_ageing_time); + return store_bridge_parm(d, buf, len, set_ageing_time); } +static DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time, + store_ageing_time); -static CLASS_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time, - store_ageing_time); -static ssize_t show_stp_state(struct class_device *cd, char *buf) +static ssize_t show_stp_state(struct device *d, + struct device_attribute *attr, char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%d\n", br->stp_enabled); } @@ -148,18 +152,19 @@ static void set_stp_state(struct net_bridge *br, unsigned long val) br->stp_enabled = val; } -static ssize_t store_stp_state(struct class_device *cd, - const char *buf, size_t len) +static ssize_t store_stp_state(struct device *d, + struct device_attribute *attr, const char *buf, + size_t len) { - return store_bridge_parm(cd, buf, len, set_stp_state); + return store_bridge_parm(d, buf, len, set_stp_state); } +static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, + store_stp_state); -static CLASS_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state, - store_stp_state); - -static ssize_t show_priority(struct class_device *cd, char *buf) +static ssize_t show_priority(struct device *d, struct device_attribute *attr, + char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%d\n", (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]); } @@ -169,92 +174,107 @@ static void set_priority(struct net_bridge *br, unsigned long val) br_stp_set_bridge_priority(br, (u16) val); } -static ssize_t store_priority(struct class_device *cd, +static ssize_t store_priority(struct device *d, struct device_attribute *attr, const char *buf, size_t len) { - return store_bridge_parm(cd, buf, len, set_priority); + return store_bridge_parm(d, buf, len, set_priority); } -static CLASS_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, - store_priority); +static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority); -static ssize_t show_root_id(struct class_device *cd, char *buf) +static ssize_t show_root_id(struct device *d, struct device_attribute *attr, + char *buf) { - return br_show_bridge_id(buf, &to_bridge(cd)->designated_root); + return br_show_bridge_id(buf, &to_bridge(d)->designated_root); } -static CLASS_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL); +static DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL); -static ssize_t show_bridge_id(struct class_device *cd, char *buf) +static ssize_t show_bridge_id(struct device *d, struct device_attribute *attr, + char *buf) { - return br_show_bridge_id(buf, &to_bridge(cd)->bridge_id); + return br_show_bridge_id(buf, &to_bridge(d)->bridge_id); } -static CLASS_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL); +static DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL); -static ssize_t show_root_port(struct class_device *cd, char *buf) +static ssize_t show_root_port(struct device *d, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", to_bridge(cd)->root_port); + return sprintf(buf, "%d\n", to_bridge(d)->root_port); } -static CLASS_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL); +static DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL); -static ssize_t show_root_path_cost(struct class_device *cd, char *buf) +static ssize_t show_root_path_cost(struct device *d, + struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", to_bridge(cd)->root_path_cost); + return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost); } -static CLASS_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL); +static DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL); -static ssize_t show_topology_change(struct class_device *cd, char *buf) +static ssize_t show_topology_change(struct device *d, + struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", to_bridge(cd)->topology_change); + return sprintf(buf, "%d\n", to_bridge(d)->topology_change); } -static CLASS_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL); +static DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL); -static ssize_t show_topology_change_detected(struct class_device *cd, char *buf) +static ssize_t show_topology_change_detected(struct device *d, + struct device_attribute *attr, + char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%d\n", br->topology_change_detected); } -static CLASS_DEVICE_ATTR(topology_change_detected, S_IRUGO, show_topology_change_detected, NULL); +static DEVICE_ATTR(topology_change_detected, S_IRUGO, + show_topology_change_detected, NULL); -static ssize_t show_hello_timer(struct class_device *cd, char *buf) +static ssize_t show_hello_timer(struct device *d, + struct device_attribute *attr, char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer)); } -static CLASS_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL); +static DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL); -static ssize_t show_tcn_timer(struct class_device *cd, char *buf) +static ssize_t show_tcn_timer(struct device *d, struct device_attribute *attr, + char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer)); } -static CLASS_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL); +static DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL); -static ssize_t show_topology_change_timer(struct class_device *cd, char *buf) +static ssize_t show_topology_change_timer(struct device *d, + struct device_attribute *attr, + char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer)); } -static CLASS_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, NULL); +static DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, + NULL); -static ssize_t show_gc_timer(struct class_device *cd, char *buf) +static ssize_t show_gc_timer(struct device *d, struct device_attribute *attr, + char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer)); } -static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); +static DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL); -static ssize_t show_group_addr(struct class_device *cd, char *buf) +static ssize_t show_group_addr(struct device *d, + struct device_attribute *attr, char *buf) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); return sprintf(buf, "%x:%x:%x:%x:%x:%x\n", br->group_addr[0], br->group_addr[1], br->group_addr[2], br->group_addr[3], br->group_addr[4], br->group_addr[5]); } -static ssize_t store_group_addr(struct class_device *cd, const char *buf, - size_t len) +static ssize_t store_group_addr(struct device *d, + struct device_attribute *attr, + const char *buf, size_t len) { - struct net_bridge *br = to_bridge(cd); + struct net_bridge *br = to_bridge(d); unsigned new_addr[6]; int i; @@ -286,28 +306,28 @@ static ssize_t store_group_addr(struct class_device *cd, const char *buf, return len; } -static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, - show_group_addr, store_group_addr); +static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR, + show_group_addr, store_group_addr); static struct attribute *bridge_attrs[] = { - &class_device_attr_forward_delay.attr, - &class_device_attr_hello_time.attr, - &class_device_attr_max_age.attr, - &class_device_attr_ageing_time.attr, - &class_device_attr_stp_state.attr, - &class_device_attr_priority.attr, - &class_device_attr_bridge_id.attr, - &class_device_attr_root_id.attr, - &class_device_attr_root_path_cost.attr, - &class_device_attr_root_port.attr, - &class_device_attr_topology_change.attr, - &class_device_attr_topology_change_detected.attr, - &class_device_attr_hello_timer.attr, - &class_device_attr_tcn_timer.attr, - &class_device_attr_topology_change_timer.attr, - &class_device_attr_gc_timer.attr, - &class_device_attr_group_addr.attr, + &dev_attr_forward_delay.attr, + &dev_attr_hello_time.attr, + &dev_attr_max_age.attr, + &dev_attr_ageing_time.attr, + &dev_attr_stp_state.attr, + &dev_attr_priority.attr, + &dev_attr_bridge_id.attr, + &dev_attr_root_id.attr, + &dev_attr_root_path_cost.attr, + &dev_attr_root_port.attr, + &dev_attr_topology_change.attr, + &dev_attr_topology_change_detected.attr, + &dev_attr_hello_timer.attr, + &dev_attr_tcn_timer.attr, + &dev_attr_topology_change_timer.attr, + &dev_attr_gc_timer.attr, + &dev_attr_group_addr.attr, NULL }; @@ -325,8 +345,8 @@ static struct attribute_group bridge_group = { static ssize_t brforward_read(struct kobject *kobj, char *buf, loff_t off, size_t count) { - struct class_device *cdev = to_class_dev(kobj); - struct net_bridge *br = to_bridge(cdev); + struct device *dev = to_dev(kobj); + struct net_bridge *br = to_bridge(dev); int n; /* must read whole records */ @@ -363,7 +383,7 @@ static struct bin_attribute bridge_forward = { */ int br_sysfs_addbr(struct net_device *dev) { - struct kobject *brobj = &dev->class_dev.kobj; + struct kobject *brobj = &dev->dev.kobj; struct net_bridge *br = netdev_priv(dev); int err; @@ -395,9 +415,9 @@ int br_sysfs_addbr(struct net_device *dev) } return 0; out3: - sysfs_remove_bin_file(&dev->class_dev.kobj, &bridge_forward); + sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward); out2: - sysfs_remove_group(&dev->class_dev.kobj, &bridge_group); + sysfs_remove_group(&dev->dev.kobj, &bridge_group); out1: return err; @@ -405,7 +425,7 @@ int br_sysfs_addbr(struct net_device *dev) void br_sysfs_delbr(struct net_device *dev) { - struct kobject *kobj = &dev->class_dev.kobj; + struct kobject *kobj = &dev->dev.kobj; struct net_bridge *br = netdev_priv(dev); kobject_unregister(&br->ifobj); diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index c51c9e42aeb3..0bc2aef8f9f3 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -211,7 +211,7 @@ int br_sysfs_addif(struct net_bridge_port *p) struct brport_attribute **a; int err; - err = sysfs_create_link(&p->kobj, &br->dev->class_dev.kobj, + err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj, SYSFS_BRIDGE_PORT_LINK); if (err) goto out2; diff --git a/net/core/dev.c b/net/core/dev.c index e660cb57e42a..455d589683e8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -751,7 +751,7 @@ int dev_change_name(struct net_device *dev, char *newname) else strlcpy(dev->name, newname, IFNAMSIZ); - err = class_device_rename(&dev->class_dev, dev->name); + err = device_rename(&dev->dev, dev->name); if (!err) { hlist_del(&dev->name_hlist); hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); @@ -3221,8 +3221,8 @@ void free_netdev(struct net_device *dev) BUG_ON(dev->reg_state != NETREG_UNREGISTERED); dev->reg_state = NETREG_RELEASED; - /* will free via class release */ - class_device_put(&dev->class_dev); + /* will free via device release */ + put_device(&dev->dev); #else kfree((char *)dev - dev->padded); #endif diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index f47f319bb7dc..44db095a8f7e 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -18,9 +18,6 @@ #include #include -#define to_class_dev(obj) container_of(obj,struct class_device,kobj) -#define to_net_dev(class) container_of(class, struct net_device, class_dev) - static const char fmt_hex[] = "%#x\n"; static const char fmt_long_hex[] = "%#lx\n"; static const char fmt_dec[] = "%d\n"; @@ -32,10 +29,11 @@ static inline int dev_isalive(const struct net_device *dev) } /* use same locking rules as GIF* ioctl's */ -static ssize_t netdev_show(const struct class_device *cd, char *buf, +static ssize_t netdev_show(const struct device *dev, + struct device_attribute *attr, char *buf, ssize_t (*format)(const struct net_device *, char *)) { - struct net_device *net = to_net_dev(cd); + struct net_device *net = to_net_dev(dev); ssize_t ret = -EINVAL; read_lock(&dev_base_lock); @@ -52,14 +50,15 @@ static ssize_t format_##field(const struct net_device *net, char *buf) \ { \ return sprintf(buf, format_string, net->field); \ } \ -static ssize_t show_##field(struct class_device *cd, char *buf) \ +static ssize_t show_##field(struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ - return netdev_show(cd, buf, format_##field); \ + return netdev_show(dev, attr, buf, format_##field); \ } /* use same locking and permission rules as SIF* ioctl's */ -static ssize_t netdev_store(struct class_device *dev, +static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len, int (*set)(struct net_device *, unsigned long)) { @@ -104,7 +103,8 @@ static ssize_t format_addr(char *buf, const unsigned char *addr, int len) return cp - buf; } -static ssize_t show_address(struct class_device *dev, char *buf) +static ssize_t show_address(struct device *dev, struct device_attribute *attr, + char *buf) { struct net_device *net = to_net_dev(dev); ssize_t ret = -EINVAL; @@ -116,7 +116,8 @@ static ssize_t show_address(struct class_device *dev, char *buf) return ret; } -static ssize_t show_broadcast(struct class_device *dev, char *buf) +static ssize_t show_broadcast(struct device *dev, + struct device_attribute *attr, char *buf) { struct net_device *net = to_net_dev(dev); if (dev_isalive(net)) @@ -124,7 +125,8 @@ static ssize_t show_broadcast(struct class_device *dev, char *buf) return -EINVAL; } -static ssize_t show_carrier(struct class_device *dev, char *buf) +static ssize_t show_carrier(struct device *dev, + struct device_attribute *attr, char *buf) { struct net_device *netdev = to_net_dev(dev); if (netif_running(netdev)) { @@ -133,7 +135,8 @@ static ssize_t show_carrier(struct class_device *dev, char *buf) return -EINVAL; } -static ssize_t show_dormant(struct class_device *dev, char *buf) +static ssize_t show_dormant(struct device *dev, + struct device_attribute *attr, char *buf) { struct net_device *netdev = to_net_dev(dev); @@ -153,7 +156,8 @@ static const char *operstates[] = { "up" }; -static ssize_t show_operstate(struct class_device *dev, char *buf) +static ssize_t show_operstate(struct device *dev, + struct device_attribute *attr, char *buf) { const struct net_device *netdev = to_net_dev(dev); unsigned char operstate; @@ -178,9 +182,10 @@ static int change_mtu(struct net_device *net, unsigned long new_mtu) return dev_set_mtu(net, (int) new_mtu); } -static ssize_t store_mtu(struct class_device *dev, const char *buf, size_t len) +static ssize_t store_mtu(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) { - return netdev_store(dev, buf, len, change_mtu); + return netdev_store(dev, attr, buf, len, change_mtu); } NETDEVICE_SHOW(flags, fmt_hex); @@ -190,9 +195,10 @@ static int change_flags(struct net_device *net, unsigned long new_flags) return dev_change_flags(net, (unsigned) new_flags); } -static ssize_t store_flags(struct class_device *dev, const char *buf, size_t len) +static ssize_t store_flags(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) { - return netdev_store(dev, buf, len, change_flags); + return netdev_store(dev, attr, buf, len, change_flags); } NETDEVICE_SHOW(tx_queue_len, fmt_ulong); @@ -203,9 +209,11 @@ static int change_tx_queue_len(struct net_device *net, unsigned long new_len) return 0; } -static ssize_t store_tx_queue_len(struct class_device *dev, const char *buf, size_t len) +static ssize_t store_tx_queue_len(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) { - return netdev_store(dev, buf, len, change_tx_queue_len); + return netdev_store(dev, attr, buf, len, change_tx_queue_len); } NETDEVICE_SHOW(weight, fmt_dec); @@ -216,12 +224,13 @@ static int change_weight(struct net_device *net, unsigned long new_weight) return 0; } -static ssize_t store_weight(struct class_device *dev, const char *buf, size_t len) +static ssize_t store_weight(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) { - return netdev_store(dev, buf, len, change_weight); + return netdev_store(dev, attr, buf, len, change_weight); } -static struct class_device_attribute net_class_attributes[] = { +static struct device_attribute net_class_attributes[] = { __ATTR(addr_len, S_IRUGO, show_addr_len, NULL), __ATTR(iflink, S_IRUGO, show_iflink, NULL), __ATTR(ifindex, S_IRUGO, show_ifindex, NULL), @@ -242,10 +251,11 @@ static struct class_device_attribute net_class_attributes[] = { }; /* Show a given an attribute in the statistics group */ -static ssize_t netstat_show(const struct class_device *cd, char *buf, +static ssize_t netstat_show(const struct device *d, + struct device_attribute *attr, char *buf, unsigned long offset) { - struct net_device *dev = to_net_dev(cd); + struct net_device *dev = to_net_dev(d); struct net_device_stats *stats; ssize_t ret = -EINVAL; @@ -265,12 +275,13 @@ static ssize_t netstat_show(const struct class_device *cd, char *buf, /* generate a read-only statistics attribute */ #define NETSTAT_ENTRY(name) \ -static ssize_t show_##name(struct class_device *cd, char *buf) \ +static ssize_t show_##name(struct device *d, \ + struct device_attribute *attr, char *buf) \ { \ - return netstat_show(cd, buf, \ + return netstat_show(d, attr, buf, \ offsetof(struct net_device_stats, name)); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) +static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) NETSTAT_ENTRY(rx_packets); NETSTAT_ENTRY(tx_packets); @@ -297,29 +308,29 @@ NETSTAT_ENTRY(rx_compressed); NETSTAT_ENTRY(tx_compressed); static struct attribute *netstat_attrs[] = { - &class_device_attr_rx_packets.attr, - &class_device_attr_tx_packets.attr, - &class_device_attr_rx_bytes.attr, - &class_device_attr_tx_bytes.attr, - &class_device_attr_rx_errors.attr, - &class_device_attr_tx_errors.attr, - &class_device_attr_rx_dropped.attr, - &class_device_attr_tx_dropped.attr, - &class_device_attr_multicast.attr, - &class_device_attr_collisions.attr, - &class_device_attr_rx_length_errors.attr, - &class_device_attr_rx_over_errors.attr, - &class_device_attr_rx_crc_errors.attr, - &class_device_attr_rx_frame_errors.attr, - &class_device_attr_rx_fifo_errors.attr, - &class_device_attr_rx_missed_errors.attr, - &class_device_attr_tx_aborted_errors.attr, - &class_device_attr_tx_carrier_errors.attr, - &class_device_attr_tx_fifo_errors.attr, - &class_device_attr_tx_heartbeat_errors.attr, - &class_device_attr_tx_window_errors.attr, - &class_device_attr_rx_compressed.attr, - &class_device_attr_tx_compressed.attr, + &dev_attr_rx_packets.attr, + &dev_attr_tx_packets.attr, + &dev_attr_rx_bytes.attr, + &dev_attr_tx_bytes.attr, + &dev_attr_rx_errors.attr, + &dev_attr_tx_errors.attr, + &dev_attr_rx_dropped.attr, + &dev_attr_tx_dropped.attr, + &dev_attr_multicast.attr, + &dev_attr_collisions.attr, + &dev_attr_rx_length_errors.attr, + &dev_attr_rx_over_errors.attr, + &dev_attr_rx_crc_errors.attr, + &dev_attr_rx_frame_errors.attr, + &dev_attr_rx_fifo_errors.attr, + &dev_attr_rx_missed_errors.attr, + &dev_attr_tx_aborted_errors.attr, + &dev_attr_tx_carrier_errors.attr, + &dev_attr_tx_fifo_errors.attr, + &dev_attr_tx_heartbeat_errors.attr, + &dev_attr_tx_window_errors.attr, + &dev_attr_rx_compressed.attr, + &dev_attr_tx_compressed.attr, NULL }; @@ -331,11 +342,11 @@ static struct attribute_group netstat_group = { #ifdef WIRELESS_EXT /* helper function that does all the locking etc for wireless stats */ -static ssize_t wireless_show(struct class_device *cd, char *buf, +static ssize_t wireless_show(struct device *d, char *buf, ssize_t (*format)(const struct iw_statistics *, char *)) { - struct net_device *dev = to_net_dev(cd); + struct net_device *dev = to_net_dev(d); const struct iw_statistics *iw = NULL; ssize_t ret = -EINVAL; @@ -358,11 +369,12 @@ static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \ { \ return sprintf(buf, format_string, iw->field); \ } \ -static ssize_t show_iw_##name(struct class_device *cd, char *buf) \ +static ssize_t show_iw_##name(struct device *d, \ + struct device_attribute *attr, char *buf) \ { \ - return wireless_show(cd, buf, format_iw_##name); \ + return wireless_show(d, buf, format_iw_##name); \ } \ -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) +static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL) WIRELESS_SHOW(status, status, fmt_hex); WIRELESS_SHOW(link, qual.qual, fmt_dec); @@ -376,16 +388,16 @@ WIRELESS_SHOW(retries, discard.retries, fmt_dec); WIRELESS_SHOW(beacon, miss.beacon, fmt_dec); static struct attribute *wireless_attrs[] = { - &class_device_attr_status.attr, - &class_device_attr_link.attr, - &class_device_attr_level.attr, - &class_device_attr_noise.attr, - &class_device_attr_nwid.attr, - &class_device_attr_crypt.attr, - &class_device_attr_fragment.attr, - &class_device_attr_retries.attr, - &class_device_attr_misc.attr, - &class_device_attr_beacon.attr, + &dev_attr_status.attr, + &dev_attr_link.attr, + &dev_attr_level.attr, + &dev_attr_noise.attr, + &dev_attr_nwid.attr, + &dev_attr_crypt.attr, + &dev_attr_fragment.attr, + &dev_attr_retries.attr, + &dev_attr_misc.attr, + &dev_attr_beacon.attr, NULL }; @@ -396,10 +408,10 @@ static struct attribute_group wireless_group = { #endif #ifdef CONFIG_HOTPLUG -static int netdev_uevent(struct class_device *cd, char **envp, +static int netdev_uevent(struct device *d, char **envp, int num_envp, char *buf, int size) { - struct net_device *dev = to_net_dev(cd); + struct net_device *dev = to_net_dev(d); int i = 0; int n; @@ -419,12 +431,11 @@ static int netdev_uevent(struct class_device *cd, char **envp, /* * netdev_release -- destroy and free a dead device. - * Called when last reference to class_device kobject is gone. + * Called when last reference to device kobject is gone. */ -static void netdev_release(struct class_device *cd) +static void netdev_release(struct device *d) { - struct net_device *dev - = container_of(cd, struct net_device, class_dev); + struct net_device *dev = to_net_dev(d); BUG_ON(dev->reg_state != NETREG_RELEASED); @@ -433,31 +444,31 @@ static void netdev_release(struct class_device *cd) static struct class net_class = { .name = "net", - .release = netdev_release, - .class_dev_attrs = net_class_attributes, + .dev_release = netdev_release, + .dev_attrs = net_class_attributes, #ifdef CONFIG_HOTPLUG - .uevent = netdev_uevent, + .dev_uevent = netdev_uevent, #endif }; void netdev_unregister_sysfs(struct net_device * net) { - class_device_del(&(net->class_dev)); + device_del(&(net->dev)); } /* Create sysfs entries for network device. */ int netdev_register_sysfs(struct net_device *net) { - struct class_device *class_dev = &(net->class_dev); + struct device *dev = &(net->dev); struct attribute_group **groups = net->sysfs_groups; - class_device_initialize(class_dev); - class_dev->class = &net_class; - class_dev->class_data = net; - class_dev->groups = groups; + device_initialize(dev); + dev->class = &net_class; + dev->platform_data = net; + dev->groups = groups; BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ); - strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE); + strlcpy(dev->bus_id, net->name, BUS_ID_SIZE); if (net->get_stats) *groups++ = &netstat_group; @@ -467,7 +478,7 @@ int netdev_register_sysfs(struct net_device *net) *groups++ = &wireless_group; #endif - return class_device_add(class_dev); + return device_add(dev); } int netdev_sysfs_init(void) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index de7801d589e7..f3404ae9f190 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -268,7 +268,7 @@ nodata: struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int length, gfp_t gfp_mask) { - int node = dev->class_dev.dev ? dev_to_node(dev->class_dev.dev) : -1; + int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1; struct sk_buff *skb; skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node); -- cgit v1.2.3 From 717e48c29d9a58f4d31c1651bec364212da5f6b2 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 8 Jan 2007 20:16:41 +0100 Subject: driver core: Remove device_is_registered() in device_move(). device_is_registered() will always be false for a device with no bus. Remove this check and trust the caller to know what they're doing. Signed-off-by: Cornelia Huck Cc: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 67b79a7592a9..36eedfdeb547 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1004,10 +1004,6 @@ int device_move(struct device *dev, struct device *new_parent) if (!dev) return -EINVAL; - if (!device_is_registered(dev)) { - error = -EINVAL; - goto out; - } new_parent = get_device(new_parent); if (!new_parent) { error = -EINVAL; -- cgit v1.2.3 From c744aeae9d173a953b771a7ad5c872f91fa99dec Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 8 Jan 2007 20:16:44 +0100 Subject: driver core: Allow device_move(dev, NULL). If we allow NULL as the new parent in device_move(), we need to make sure that the device is placed into the same place as it would if it was newly registered: - Consider the device virtual tree. In order to be able to reuse code, setup_parent() has been tweaked a bit. - kobject_move() can fall back to the kset's kobject. - sysfs_move_dir() uses the sysfs root dir as fallback. Signed-off-by: Cornelia Huck Cc: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 76 +++++++++++++++++++++++++++++++++-------------------- fs/sysfs/dir.c | 6 ++--- lib/kobject.c | 6 ++--- 3 files changed, 52 insertions(+), 36 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 36eedfdeb547..c60114dbe5f5 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -390,22 +390,23 @@ void device_initialize(struct device *dev) } #ifdef CONFIG_SYSFS_DEPRECATED -static int setup_parent(struct device *dev, struct device *parent) +static struct kobject * get_device_parent(struct device *dev, + struct device *parent) { /* Set the parent to the class, not the parent device */ /* this keeps sysfs from having a symlink to make old udevs happy */ if (dev->class) - dev->kobj.parent = &dev->class->subsys.kset.kobj; + return &dev->class->subsys.kset.kobj; else if (parent) - dev->kobj.parent = &parent->kobj; + return &parent->kobj; - return 0; + return NULL; } #else -static int virtual_device_parent(struct device *dev) +static struct kobject * virtual_device_parent(struct device *dev) { if (!dev->class) - return -ENODEV; + return ERR_PTR(-ENODEV); if (!dev->class->virtual_dir) { static struct kobject *virtual_dir = NULL; @@ -415,25 +416,31 @@ static int virtual_device_parent(struct device *dev) dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); } - dev->kobj.parent = dev->class->virtual_dir; - return 0; + return dev->class->virtual_dir; } -static int setup_parent(struct device *dev, struct device *parent) +static struct kobject * get_device_parent(struct device *dev, + struct device *parent) { - int error; - /* if this is a class device, and has no parent, create one */ if ((dev->class) && (parent == NULL)) { - error = virtual_device_parent(dev); - if (error) - return error; + return virtual_device_parent(dev); } else if (parent) - dev->kobj.parent = &parent->kobj; + return &parent->kobj; + return NULL; +} +#endif +static int setup_parent(struct device *dev, struct device *parent) +{ + struct kobject *kobj; + kobj = get_device_parent(dev, parent); + if (IS_ERR(kobj)) + return PTR_ERR(kobj); + if (kobj) + dev->kobj.parent = kobj; return 0; } -#endif /** * device_add - add device to device hierarchy. @@ -976,12 +983,18 @@ static int device_move_class_links(struct device *dev, sysfs_remove_link(&dev->kobj, "device"); sysfs_remove_link(&old_parent->kobj, class_name); } - error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device"); - if (error) - goto out; - error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name); - if (error) - sysfs_remove_link(&dev->kobj, "device"); + if (new_parent) { + error = sysfs_create_link(&dev->kobj, &new_parent->kobj, + "device"); + if (error) + goto out; + error = sysfs_create_link(&new_parent->kobj, &dev->kobj, + class_name); + if (error) + sysfs_remove_link(&dev->kobj, "device"); + } + else + error = 0; out: kfree(class_name); return error; @@ -993,25 +1006,28 @@ out: /** * device_move - moves a device to a new parent * @dev: the pointer to the struct device to be moved - * @new_parent: the new parent of the device + * @new_parent: the new parent of the device (can by NULL) */ int device_move(struct device *dev, struct device *new_parent) { int error; struct device *old_parent; + struct kobject *new_parent_kobj; dev = get_device(dev); if (!dev) return -EINVAL; new_parent = get_device(new_parent); - if (!new_parent) { - error = -EINVAL; + new_parent_kobj = get_device_parent (dev, new_parent); + if (IS_ERR(new_parent_kobj)) { + error = PTR_ERR(new_parent_kobj); + put_device(new_parent); goto out; } pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, - new_parent->bus_id); - error = kobject_move(&dev->kobj, &new_parent->kobj); + new_parent ? new_parent->bus_id : ""); + error = kobject_move(&dev->kobj, new_parent_kobj); if (error) { put_device(new_parent); goto out; @@ -1020,7 +1036,8 @@ int device_move(struct device *dev, struct device *new_parent) dev->parent = new_parent; if (old_parent) klist_remove(&dev->knode_parent); - klist_add_tail(&dev->knode_parent, &new_parent->klist_children); + if (new_parent) + klist_add_tail(&dev->knode_parent, &new_parent->klist_children); if (!dev->class) goto out_put; error = device_move_class_links(dev, old_parent, new_parent); @@ -1028,7 +1045,8 @@ int device_move(struct device *dev, struct device *new_parent) /* We ignore errors on cleanup since we're hosed anyway... */ device_move_class_links(dev, new_parent, old_parent); if (!kobject_move(&dev->kobj, &old_parent->kobj)) { - klist_remove(&dev->knode_parent); + if (new_parent) + klist_remove(&dev->knode_parent); if (old_parent) klist_add_tail(&dev->knode_parent, &old_parent->klist_children); diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 511edef8b321..2bab1b4ddf5a 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -378,12 +378,10 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent) struct sysfs_dirent *new_parent_sd, *sd; int error; - if (!new_parent) - return -EINVAL; - old_parent_dentry = kobj->parent ? kobj->parent->dentry : sysfs_mount->mnt_sb->s_root; - new_parent_dentry = new_parent->dentry; + new_parent_dentry = new_parent ? + new_parent->dentry : sysfs_mount->mnt_sb->s_root; again: mutex_lock(&old_parent_dentry->d_inode->i_mutex); diff --git a/lib/kobject.c b/lib/kobject.c index 9aed594bfcac..c033dc8fa9af 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -314,7 +314,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name) /** * kobject_move - move object to another parent * @kobj: object in question. - * @new_parent: object's new parent + * @new_parent: object's new parent (can be NULL) */ int kobject_move(struct kobject *kobj, struct kobject *new_parent) @@ -330,8 +330,8 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) return -EINVAL; new_parent = kobject_get(new_parent); if (!new_parent) { - error = -EINVAL; - goto out; + if (kobj->kset) + new_parent = kobject_get(&kobj->kset->kobj); } /* old object path */ devpath = kobject_get_path(kobj, GFP_KERNEL); -- cgit v1.2.3 From f30c53a873d0d227493197064b8886af2d57bbd6 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Mon, 15 Jan 2007 20:22:02 +0100 Subject: MODULES: add the module name for built in kernel drivers Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- include/linux/device.h | 1 + include/linux/module.h | 2 +- kernel/module.c | 33 ++++++++++++++++++++++++--------- kernel/params.c | 12 +++++------- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/include/linux/device.h b/include/linux/device.h index f44247fe8135..da7221913114 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -126,6 +126,7 @@ struct device_driver { struct klist_node knode_bus; struct module * owner; + const char * mod_name; /* used for built-in modules */ int (*probe) (struct device * dev); int (*remove) (struct device * dev); diff --git a/include/linux/module.h b/include/linux/module.h index 10f771a49997..90dc2542978c 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -58,6 +58,7 @@ struct module_kobject { struct kobject kobj; struct module *mod; + struct kobject *drivers_dir; }; /* These are either module local, or the kernel's dummy ones. */ @@ -263,7 +264,6 @@ struct module struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; - struct kobject *drivers_dir; /* Exported symbols */ const struct kernel_symbol *syms; diff --git a/kernel/module.c b/kernel/module.c index d0f2260a0210..0f4489af3e29 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1131,8 +1131,8 @@ static int mod_sysfs_setup(struct module *mod, if (err) goto out; - mod->drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers"); - if (!mod->drivers_dir) { + mod->mkobj.drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers"); + if (!mod->mkobj.drivers_dir) { err = -ENOMEM; goto out_unreg; } @@ -1151,7 +1151,7 @@ static int mod_sysfs_setup(struct module *mod, out_unreg_param: module_param_sysfs_remove(mod); out_unreg_drivers: - kobject_unregister(mod->drivers_dir); + kobject_unregister(mod->mkobj.drivers_dir); out_unreg: kobject_del(&mod->mkobj.kobj); kobject_put(&mod->mkobj.kobj); @@ -1163,7 +1163,7 @@ static void mod_kobject_remove(struct module *mod) { module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); - kobject_unregister(mod->drivers_dir); + kobject_unregister(mod->mkobj.drivers_dir); kobject_unregister(&mod->mkobj.kobj); } @@ -2344,15 +2344,30 @@ void module_add_driver(struct module *mod, struct device_driver *drv) { char *driver_name; int no_warn; + struct module_kobject *mk = NULL; - if (!mod || !drv) + if (!drv) + return; + + if (mod) + mk = &mod->mkobj; + else if (drv->mod_name) { + struct kobject *mkobj; + + /* Lookup built-in module entry in /sys/modules */ + mkobj = kset_find_obj(&module_subsys.kset, drv->mod_name); + if (mkobj) + mk = container_of(mkobj, struct module_kobject, kobj); + } + + if (!mk) return; /* Don't check return codes; these calls are idempotent */ - no_warn = sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module"); + no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module"); driver_name = make_driver_name(drv); if (driver_name) { - no_warn = sysfs_create_link(mod->drivers_dir, &drv->kobj, + no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj, driver_name); kfree(driver_name); } @@ -2367,10 +2382,10 @@ void module_remove_driver(struct device_driver *drv) return; sysfs_remove_link(&drv->kobj, "module"); - if (drv->owner && drv->owner->drivers_dir) { + if (drv->owner && drv->owner->mkobj.drivers_dir) { driver_name = make_driver_name(drv); if (driver_name) { - sysfs_remove_link(drv->owner->drivers_dir, + sysfs_remove_link(drv->owner->mkobj.drivers_dir, driver_name); kfree(driver_name); } diff --git a/kernel/params.c b/kernel/params.c index 718945da8f58..737b7c5e93aa 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -561,14 +561,12 @@ static void __init kernel_param_sysfs_setup(const char *name, mk->mod = THIS_MODULE; kobj_set_kset_s(mk, module_subsys); kobject_set_name(&mk->kobj, name); - ret = kobject_register(&mk->kobj); + kobject_init(&mk->kobj); + ret = kobject_add(&mk->kobj); BUG_ON(ret < 0); - - /* no need to keep the kobject if no parameter is exported */ - if (!param_sysfs_setup(mk, kparam, num_params, name_skip)) { - kobject_unregister(&mk->kobj); - kfree(mk); - } + param_sysfs_setup(mk, kparam, num_params, name_skip); + mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers"); + kobject_uevent(&mk->kobj, KOBJ_ADD); } /* -- cgit v1.2.3 From fe480a2675ed236af396597d9f05245c7bbd0149 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Jan 2007 11:50:02 -0800 Subject: Modules: only add drivers/ direcory if needed This changes the module core to only create the drivers/ directory if we are going to put something in it. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- kernel/module.c | 20 +++++++++++--------- kernel/params.c | 1 - 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/kernel/module.c b/kernel/module.c index 0f4489af3e29..9de4209f6a67 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1131,12 +1131,6 @@ static int mod_sysfs_setup(struct module *mod, if (err) goto out; - mod->mkobj.drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers"); - if (!mod->mkobj.drivers_dir) { - err = -ENOMEM; - goto out_unreg; - } - err = module_param_sysfs_setup(mod, kparam, num_params); if (err) goto out_unreg_drivers; @@ -1151,8 +1145,6 @@ static int mod_sysfs_setup(struct module *mod, out_unreg_param: module_param_sysfs_remove(mod); out_unreg_drivers: - kobject_unregister(mod->mkobj.drivers_dir); -out_unreg: kobject_del(&mod->mkobj.kobj); kobject_put(&mod->mkobj.kobj); out: @@ -1163,7 +1155,8 @@ static void mod_kobject_remove(struct module *mod) { module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); - kobject_unregister(mod->mkobj.drivers_dir); + if (mod->mkobj.drivers_dir) + kobject_unregister(mod->mkobj.drivers_dir); kobject_unregister(&mod->mkobj.kobj); } @@ -2340,6 +2333,14 @@ static char *make_driver_name(struct device_driver *drv) return driver_name; } +static void module_create_drivers_dir(struct module_kobject *mk) +{ + if (!mk || mk->drivers_dir) + return; + + mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers"); +} + void module_add_driver(struct module *mod, struct device_driver *drv) { char *driver_name; @@ -2367,6 +2368,7 @@ void module_add_driver(struct module *mod, struct device_driver *drv) no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module"); driver_name = make_driver_name(drv); if (driver_name) { + module_create_drivers_dir(mk); no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj, driver_name); kfree(driver_name); diff --git a/kernel/params.c b/kernel/params.c index 737b7c5e93aa..cbaac85942d5 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -565,7 +565,6 @@ static void __init kernel_param_sysfs_setup(const char *name, ret = kobject_add(&mk->kobj); BUG_ON(ret < 0); param_sysfs_setup(mk, kparam, num_params, name_skip); - mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers"); kobject_uevent(&mk->kobj, KOBJ_ADD); } -- cgit v1.2.3 From 725522b5453dd680412f2b6463a988e4fd148757 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Jan 2007 11:50:02 -0800 Subject: PCI: add the sysfs driver name to all modules This adds the module name to all PCI drivers, if they are built into the kernel or not. It will show up in /sys/modules/MODULE_NAME/drivers/ It also fixes up the IDE core, which was calling __pci_register_driver() directly. Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/ide/setup-pci.c | 7 ++++--- drivers/pci/pci-driver.c | 4 +++- include/linux/ide.h | 4 ++-- include/linux/pci.h | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index 695e23904d30..a52c80fe7d3e 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -783,10 +783,11 @@ static LIST_HEAD(ide_pci_drivers); * Returns are the same as for pci_register_driver */ -int __ide_pci_register_driver(struct pci_driver *driver, struct module *module) +int __ide_pci_register_driver(struct pci_driver *driver, struct module *module, + const char *mod_name) { if(!pre_init) - return __pci_register_driver(driver, module); + return __pci_register_driver(driver, module, mod_name); driver->driver.owner = module; list_add_tail(&driver->node, &ide_pci_drivers); return 0; @@ -862,6 +863,6 @@ void __init ide_scan_pcibus (int scan_direction) { list_del(l); d = list_entry(l, struct pci_driver, node); - __pci_register_driver(d, d->driver.owner); + __pci_register_driver(d, d->driver.owner, d->driver.mod_name); } } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 92d5e8db0de7..358766885260 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -422,7 +422,8 @@ static struct kobj_type pci_driver_kobj_type = { * If no error occurred, the driver remains registered even if * no device was claimed during registration. */ -int __pci_register_driver(struct pci_driver *drv, struct module *owner) +int __pci_register_driver(struct pci_driver *drv, struct module *owner, + const char *mod_name) { int error; @@ -430,6 +431,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner) drv->driver.name = drv->name; drv->driver.bus = &pci_bus_type; drv->driver.owner = owner; + drv->driver.mod_name = mod_name; drv->driver.kobj.ktype = &pci_driver_kobj_type; if (pci_multithread_probe) diff --git a/include/linux/ide.h b/include/linux/ide.h index e26a03981a94..827688f41d6c 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1192,8 +1192,8 @@ void ide_init_disk(struct gendisk *, ide_drive_t *); extern int ideprobe_init(void); extern void ide_scan_pcibus(int scan_direction) __init; -extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner); -#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE) +extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name); +#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME) void ide_pci_setup_ports(struct pci_dev *, struct ide_pci_device_s *, int, ata_index_t *); extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d); diff --git a/include/linux/pci.h b/include/linux/pci.h index f3c617eabd8d..cb899eb95d31 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -573,10 +573,11 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus, void pci_enable_bridges(struct pci_bus *bus); /* Proper probing supporting hot-pluggable devices */ -int __must_check __pci_register_driver(struct pci_driver *, struct module *); +int __must_check __pci_register_driver(struct pci_driver *, struct module *, + const char *mod_name); static inline int __must_check pci_register_driver(struct pci_driver *driver) { - return __pci_register_driver(driver, THIS_MODULE); + return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME); } void pci_unregister_driver(struct pci_driver *); -- cgit v1.2.3 From 4b315627e6b894156e235ac905786e7d46aab2e6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Jan 2007 11:50:02 -0800 Subject: SERIO: add the sysfs driver name to all modules This adds the module name to all SERIO drivers, if they are built into the kernel or not. It will show up in /sys/modules/MODULE_NAME/drivers/ Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/serio.c | 6 ++++-- include/linux/serio.h | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index f0ce822c1028..17c8c63cbe1a 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -45,7 +45,7 @@ EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_child_port); -EXPORT_SYMBOL(serio_register_driver); +EXPORT_SYMBOL(__serio_register_driver); EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_close); @@ -789,12 +789,14 @@ static void serio_attach_driver(struct serio_driver *drv) drv->driver.name, error); } -int serio_register_driver(struct serio_driver *drv) +int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name) { int manual_bind = drv->manual_bind; int error; drv->driver.bus = &serio_bus; + drv->driver.owner = owner; + drv->driver.mod_name = mod_name; /* * Temporarily disable automatic binding because probing diff --git a/include/linux/serio.h b/include/linux/serio.h index 0f478a8791a2..ac2c70e7f760 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -86,6 +86,11 @@ static inline void serio_register_port(struct serio *serio) void serio_unregister_port(struct serio *serio); void serio_unregister_child_port(struct serio *serio); +int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name); +static inline int serio_register_driver(struct serio_driver *drv) +{ + return __serio_register_driver(drv, THIS_MODULE, KBUILD_MODNAME); +} int serio_register_driver(struct serio_driver *drv); void serio_unregister_driver(struct serio_driver *drv); -- cgit v1.2.3 From 80f745fb1b0fb11383cbb8df2c36aaaa0399b6e6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 15 Jan 2007 11:50:02 -0800 Subject: USB: add the sysfs driver name to all modules This adds the module name to all USB drivers, if they are built into the kernel or not. It will show up in /sys/modules/MODULE_NAME/drivers/ Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 4 +++- include/linux/usb.h | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d6eb5ce1dd1d..d505926aa9cc 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -750,7 +750,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver); * usb_register_dev() to enable that functionality. This function no longer * takes care of that. */ -int usb_register_driver(struct usb_driver *new_driver, struct module *owner) +int usb_register_driver(struct usb_driver *new_driver, struct module *owner, + const char *mod_name) { int retval = 0; @@ -763,6 +764,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner) new_driver->drvwrap.driver.probe = usb_probe_interface; new_driver->drvwrap.driver.remove = usb_unbind_interface; new_driver->drvwrap.driver.owner = owner; + new_driver->drvwrap.driver.mod_name = mod_name; spin_lock_init(&new_driver->dynids.lock); INIT_LIST_HEAD(&new_driver->dynids.list); diff --git a/include/linux/usb.h b/include/linux/usb.h index aab5b1b72021..733f38de4978 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -868,10 +868,11 @@ struct usb_class_driver { * use these in module_init()/module_exit() * and don't forget MODULE_DEVICE_TABLE(usb, ...) */ -extern int usb_register_driver(struct usb_driver *, struct module *); +extern int usb_register_driver(struct usb_driver *, struct module *, + const char *); static inline int usb_register(struct usb_driver *driver) { - return usb_register_driver(driver, THIS_MODULE); + return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME); } extern void usb_deregister(struct usb_driver *); -- cgit v1.2.3 From 270a6c4cad809e92d7b81adde92d0b3d94eeb8ee Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Thu, 18 Jan 2007 13:26:15 +0100 Subject: /sys/modules/*/holders /sys/module/usbcore/ |-- drivers | |-- usb:hub -> ../../../subsystem/usb/drivers/hub | |-- usb:usb -> ../../../subsystem/usb/drivers/usb | `-- usb:usbfs -> ../../../subsystem/usb/drivers/usbfs |-- holders | |-- ehci_hcd -> ../../../module/ehci_hcd | |-- uhci_hcd -> ../../../module/uhci_hcd | |-- usb_storage -> ../../../module/usb_storage | `-- usbhid -> ../../../module/usbhid |-- initstate Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- include/linux/module.h | 1 + kernel/module.c | 37 +++++++++++++++++++++++++++++++------ kernel/params.c | 17 ++++++++++++++++- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index 90dc2542978c..419d3ef293dd 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -264,6 +264,7 @@ struct module struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; + struct kobject *holders_dir; /* Exported symbols */ const struct kernel_symbol *syms; diff --git a/kernel/module.c b/kernel/module.c index 9de4209f6a67..8a94e054230c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -537,6 +537,8 @@ static int already_uses(struct module *a, struct module *b) static int use_module(struct module *a, struct module *b) { struct module_use *use; + int no_warn; + if (b == NULL || already_uses(a, b)) return 1; if (!strong_try_module_get(b)) @@ -552,6 +554,7 @@ static int use_module(struct module *a, struct module *b) use->module_which_uses = a; list_add(&use->list, &b->modules_which_use_me); + no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name); return 1; } @@ -569,6 +572,7 @@ static void module_unload_free(struct module *mod) module_put(i); list_del(&use->list); kfree(use); + sysfs_remove_link(i->holders_dir, mod->name); /* There can be at most one match. */ break; } @@ -1106,9 +1110,7 @@ static void module_remove_modinfo_attrs(struct module *mod) kfree(mod->modinfo_attrs); } -static int mod_sysfs_setup(struct module *mod, - struct kernel_param *kparam, - unsigned int num_params) +static int mod_sysfs_init(struct module *mod) { int err; @@ -1125,15 +1127,30 @@ static int mod_sysfs_setup(struct module *mod, kobj_set_kset_s(&mod->mkobj, module_subsys); mod->mkobj.mod = mod; - /* delay uevent until full sysfs population */ kobject_init(&mod->mkobj.kobj); + +out: + return err; +} + +static int mod_sysfs_setup(struct module *mod, + struct kernel_param *kparam, + unsigned int num_params) +{ + int err; + + /* delay uevent until full sysfs population */ err = kobject_add(&mod->mkobj.kobj); if (err) goto out; + mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders"); + if (!mod->holders_dir) + goto out_unreg; + err = module_param_sysfs_setup(mod, kparam, num_params); if (err) - goto out_unreg_drivers; + goto out_unreg_holders; err = module_add_modinfo_attrs(mod); if (err) @@ -1144,7 +1161,9 @@ static int mod_sysfs_setup(struct module *mod, out_unreg_param: module_param_sysfs_remove(mod); -out_unreg_drivers: +out_unreg_holders: + kobject_unregister(mod->holders_dir); +out_unreg: kobject_del(&mod->mkobj.kobj); kobject_put(&mod->mkobj.kobj); out: @@ -1157,6 +1176,8 @@ static void mod_kobject_remove(struct module *mod) module_param_sysfs_remove(mod); if (mod->mkobj.drivers_dir) kobject_unregister(mod->mkobj.drivers_dir); + if (mod->holders_dir) + kobject_unregister(mod->holders_dir); kobject_unregister(&mod->mkobj.kobj); } @@ -1761,6 +1782,10 @@ static struct module *load_module(void __user *umod, /* Now we've moved module, initialize linked lists, etc. */ module_unload_init(mod); + /* Initialize kobject, so we can reference it. */ + if (mod_sysfs_init(mod) != 0) + goto cleanup; + /* Set up license info based on the info section */ set_license(mod, get_modinfo(sechdrs, infoindex, "license")); diff --git a/kernel/params.c b/kernel/params.c index cbaac85942d5..553cf7d6a4be 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -30,6 +30,8 @@ #define DEBUGP(fmt, a...) #endif +static struct kobj_type module_ktype; + static inline char dash2underscore(char c) { if (c == '-') @@ -671,6 +673,19 @@ static struct sysfs_ops module_sysfs_ops = { .store = module_attr_store, }; +static int uevent_filter(struct kset *kset, struct kobject *kobj) +{ + struct kobj_type *ktype = get_ktype(kobj); + + if (ktype == &module_ktype) + return 1; + return 0; +} + +static struct kset_uevent_ops module_uevent_ops = { + .filter = uevent_filter, +}; + #else static struct sysfs_ops module_sysfs_ops = { .show = NULL, @@ -682,7 +697,7 @@ static struct kobj_type module_ktype = { .sysfs_ops = &module_sysfs_ops, }; -decl_subsys(module, &module_ktype, NULL); +decl_subsys(module, &module_ktype, &module_uevent_ops); /* * param_sysfs_init - wrapper for built-in params support -- cgit v1.2.3 From cb360bbf6352712310a7528137919c626a782744 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 27 Nov 2006 10:35:05 +0100 Subject: driver core fixes: make_class_name() retval checks Make make_class_name() return NULL on error and fixup callers in the driver core. Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 21 ++++++++++++++------- drivers/base/core.c | 17 +++++++++++------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/base/class.c b/drivers/base/class.c index 8bf2ca2e56b5..96def1ddba19 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -364,7 +364,7 @@ char *make_class_name(const char *name, struct kobject *kobj) class_name = kmalloc(size, GFP_KERNEL); if (!class_name) - return ERR_PTR(-ENOMEM); + return NULL; strcpy(class_name, name); strcat(class_name, ":"); @@ -411,8 +411,11 @@ static int make_deprecated_class_device_links(struct class_device *class_dev) return 0; class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, - class_name); + if (class_name) + error = sysfs_create_link(&class_dev->dev->kobj, + &class_dev->kobj, class_name); + else + error = -ENOMEM; kfree(class_name); return error; } @@ -425,7 +428,8 @@ static void remove_deprecated_class_device_links(struct class_device *class_dev) return; class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - sysfs_remove_link(&class_dev->dev->kobj, class_name); + if (class_name) + sysfs_remove_link(&class_dev->dev->kobj, class_name); kfree(class_name); } #else @@ -863,9 +867,12 @@ int class_device_rename(struct class_device *class_dev, char *new_name) if (class_dev->dev) { new_class_name = make_class_name(class_dev->class->name, &class_dev->kobj); - sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, - new_class_name); - sysfs_remove_link(&class_dev->dev->kobj, old_class_name); + if (new_class_name) + sysfs_create_link(&class_dev->dev->kobj, + &class_dev->kobj, new_class_name); + if (old_class_name) + sysfs_remove_link(&class_dev->dev->kobj, + old_class_name); } #endif class_device_put(class_dev); diff --git a/drivers/base/core.c b/drivers/base/core.c index c60114dbe5f5..6fee3e6b1ac2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -527,9 +527,13 @@ int device_add(struct device *dev) &dev->kobj, dev->bus_id); #ifdef CONFIG_SYSFS_DEPRECATED if (parent) { - sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); - class_name = make_class_name(dev->class->name, &dev->kobj); - sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name); + sysfs_create_link(&dev->kobj, &dev->parent->kobj, + "device"); + class_name = make_class_name(dev->class->name, + &dev->kobj); + if (class_name) + sysfs_create_link(&dev->parent->kobj, + &dev->kobj, class_name); } #endif } @@ -672,7 +676,9 @@ void device_del(struct device * dev) if (parent) { char *class_name = make_class_name(dev->class->name, &dev->kobj); - sysfs_remove_link(&dev->parent->kobj, class_name); + if (class_name) + sysfs_remove_link(&dev->parent->kobj, + class_name); kfree(class_name); sysfs_remove_link(&dev->kobj, "device"); } @@ -975,8 +981,7 @@ static int device_move_class_links(struct device *dev, class_name = make_class_name(dev->class->name, &dev->kobj); if (!class_name) { - error = PTR_ERR(class_name); - class_name = NULL; + error = -ENOMEM; goto out; } if (old_parent) { -- cgit v1.2.3 From fbfb14455391b89edcf37327526988dea7849532 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 27 Nov 2006 10:35:08 +0100 Subject: driver core fixes: device_register() retval check in platform.c Check the return value of device_register() in platform_bus_init(). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index f9c903ba9fcd..30480f6f2af2 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -611,8 +611,15 @@ EXPORT_SYMBOL_GPL(platform_bus_type); int __init platform_bus_init(void) { - device_register(&platform_bus); - return bus_register(&platform_bus_type); + int error; + + error = device_register(&platform_bus); + if (error) + return error; + error = bus_register(&platform_bus_type); + if (error) + device_unregister(&platform_bus); + return error; } #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK -- cgit v1.2.3 From c578abbc20762aa58e390e55252959853eeea17e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 27 Nov 2006 10:35:10 +0100 Subject: driver core: Don't stop probing on ->probe errors. Don't stop on the first ->probe error that is not -ENODEV/-ENXIO. There might be a driver registered returning an unresonable return code, and this stops probing completely even though it may make sense to try the next possible driver. At worst, we may end up with an unbound device. Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 510e7884975f..f70513748947 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -136,18 +136,17 @@ probe_failed: driver_sysfs_remove(dev); dev->driver = NULL; - if (ret == -ENODEV || ret == -ENXIO) { - /* Driver matched, but didn't support device - * or device not found. - * Not an error; keep going. - */ - ret = 0; - } else { + if (ret != -ENODEV && ret != -ENXIO) { /* driver matched but the probe failed */ printk(KERN_WARNING "%s: probe of %s failed with error %d\n", drv->name, dev->bus_id, ret); } + /* + * Ignore errors returned by ->probe so that the next driver can try + * its luck. + */ + ret = 0; done: kfree(data); atomic_dec(&probe_count); -- cgit v1.2.3 From cb986b749c7178422bfbc982cd30e04d5db54bbc Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 27 Nov 2006 10:35:12 +0100 Subject: driver core: Change function call order in device_bind_driver(). Change function call order in device_bind_driver(). If we create symlinks (which might fail) before adding the device to the list we don't have to clean up afterwards (which we didn't). Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index f70513748947..b5bf243d9cd6 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -86,8 +86,12 @@ static void driver_sysfs_remove(struct device *dev) */ int device_bind_driver(struct device *dev) { - driver_bound(dev); - return driver_sysfs_add(dev); + int ret; + + ret = driver_sysfs_add(dev); + if (!ret) + driver_bound(dev); + return ret; } struct stupid_thread_structure { -- cgit v1.2.3 From 94bebf4d1b8e7719f0f3944c037a21cfd99a4af7 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 20 Dec 2006 10:52:44 +0100 Subject: Driver core: fix race in sysfs between sysfs_remove_file() and read()/write() This patch prevents a race between IO and removing a file from sysfs. It introduces a list of sysfs_buffers associated with a file at the inode. Upon removal of a file the list is walked and the buffers marked orphaned. IO to orphaned buffers fails with -ENODEV. The driver can safely free associated data structures or be unloaded. Signed-off-by: Oliver Neukum Acked-by: Maneesh Soni Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/bin.c | 1 + fs/sysfs/dir.c | 1 + fs/sysfs/file.c | 67 ++++++++++++++++++++++++++++++++++++++++-------------- fs/sysfs/group.c | 1 + fs/sysfs/inode.c | 24 +++++++++++++++++++ fs/sysfs/mount.c | 9 ++++++++ fs/sysfs/symlink.c | 1 + fs/sysfs/sysfs.h | 16 +++++++++++++ 8 files changed, 103 insertions(+), 17 deletions(-) diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index e8f540d38d48..9ec1c8539a5d 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -16,6 +16,7 @@ #include #include +#include #include "sysfs.h" diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 2bab1b4ddf5a..9ff04491e3ea 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "sysfs.h" DECLARE_RWSEM(sysfs_rename_sem); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 9cfe53e1e00d..cba4c1c7383c 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -50,17 +51,29 @@ static struct sysfs_ops subsys_sysfs_ops = { .store = subsys_attr_store, }; +/** + * add_to_collection - add buffer to a collection + * @buffer: buffer to be added + * @node inode of set to add to + */ -struct sysfs_buffer { - size_t count; - loff_t pos; - char * page; - struct sysfs_ops * ops; - struct semaphore sem; - int needs_read_fill; - int event; -}; +static inline void +add_to_collection(struct sysfs_buffer *buffer, struct inode *node) +{ + struct sysfs_buffer_collection *set = node->i_private; + mutex_lock(&node->i_mutex); + list_add(&buffer->associates, &set->associates); + mutex_unlock(&node->i_mutex); +} + +static inline void +remove_from_collection(struct sysfs_buffer *buffer, struct inode *node) +{ + mutex_lock(&node->i_mutex); + list_del(&buffer->associates); + mutex_unlock(&node->i_mutex); +} /** * fill_read_buffer - allocate and fill buffer from object. @@ -153,6 +166,10 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) ssize_t retval = 0; down(&buffer->sem); + if (buffer->orphaned) { + retval = -ENODEV; + goto out; + } if (buffer->needs_read_fill) { if ((retval = fill_read_buffer(file->f_path.dentry,buffer))) goto out; @@ -165,7 +182,6 @@ out: return retval; } - /** * fill_write_buffer - copy buffer from userspace. * @buffer: data buffer for file. @@ -243,19 +259,25 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t ssize_t len; down(&buffer->sem); + if (buffer->orphaned) { + len = -ENODEV; + goto out; + } len = fill_write_buffer(buffer, buf, count); if (len > 0) len = flush_write_buffer(file->f_path.dentry, buffer, len); if (len > 0) *ppos += len; +out: up(&buffer->sem); return len; } -static int check_perm(struct inode * inode, struct file * file) +static int sysfs_open_file(struct inode *inode, struct file *file) { struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent); struct attribute * attr = to_attr(file->f_path.dentry); + struct sysfs_buffer_collection *set; struct sysfs_buffer * buffer; struct sysfs_ops * ops = NULL; int error = 0; @@ -285,6 +307,18 @@ static int check_perm(struct inode * inode, struct file * file) if (!ops) goto Eaccess; + /* make sure we have a collection to add our buffers to */ + mutex_lock(&inode->i_mutex); + if (!(set = inode->i_private)) { + if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) { + error = -ENOMEM; + goto Done; + } else { + INIT_LIST_HEAD(&set->associates); + } + } + mutex_unlock(&inode->i_mutex); + /* File needs write support. * The inode's perms must say it's ok, * and we must have a store method. @@ -310,9 +344,11 @@ static int check_perm(struct inode * inode, struct file * file) */ buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL); if (buffer) { + INIT_LIST_HEAD(&buffer->associates); init_MUTEX(&buffer->sem); buffer->needs_read_fill = 1; buffer->ops = ops; + add_to_collection(buffer, inode); file->private_data = buffer; } else error = -ENOMEM; @@ -330,11 +366,6 @@ static int check_perm(struct inode * inode, struct file * file) return error; } -static int sysfs_open_file(struct inode * inode, struct file * filp) -{ - return check_perm(inode,filp); -} - static int sysfs_release(struct inode * inode, struct file * filp) { struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent); @@ -342,6 +373,8 @@ static int sysfs_release(struct inode * inode, struct file * filp) struct module * owner = attr->owner; struct sysfs_buffer * buffer = filp->private_data; + if (buffer) + remove_from_collection(buffer, inode); if (kobj) kobject_put(kobj); /* After this point, attr should not be accessed. */ @@ -548,7 +581,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) { - sysfs_hash_and_remove(kobj->dentry,attr->name); + sysfs_hash_and_remove(kobj->dentry, attr->name); } diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 122145b0895c..46a277b0838e 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "sysfs.h" diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index e79e38d52c00..1a81ebce20e9 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "sysfs.h" extern struct super_block * sysfs_sb; @@ -209,6 +210,22 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd) return NULL; } +static inline void orphan_all_buffers(struct inode *node) +{ + struct sysfs_buffer_collection *set = node->i_private; + struct sysfs_buffer *buf; + + mutex_lock(&node->i_mutex); + if (node->i_private) { + list_for_each_entry(buf, &set->associates, associates) { + down(&buf->sem); + buf->orphaned = 1; + up(&buf->sem); + } + } + mutex_unlock(&node->i_mutex); +} + /* * Unhashes the dentry corresponding to given sysfs_dirent @@ -217,16 +234,23 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd) void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent) { struct dentry * dentry = sd->s_dentry; + struct inode *inode; if (dentry) { spin_lock(&dcache_lock); spin_lock(&dentry->d_lock); if (!(d_unhashed(dentry) && dentry->d_inode)) { + inode = dentry->d_inode; + spin_lock(&inode->i_lock); + __iget(inode); + spin_unlock(&inode->i_lock); dget_locked(dentry); __d_drop(dentry); spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); simple_unlink(parent->d_inode, dentry); + orphan_all_buffers(inode); + iput(inode); } else { spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index e503f858fba8..a1a58b97f322 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "sysfs.h" @@ -18,9 +19,12 @@ struct vfsmount *sysfs_mount; struct super_block * sysfs_sb = NULL; struct kmem_cache *sysfs_dir_cachep; +static void sysfs_clear_inode(struct inode *inode); + static struct super_operations sysfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, + .clear_inode = sysfs_clear_inode, }; static struct sysfs_dirent sysfs_root = { @@ -31,6 +35,11 @@ static struct sysfs_dirent sysfs_root = { .s_iattr = NULL, }; +static void sysfs_clear_inode(struct inode *inode) +{ + kfree(inode->i_private); +} + static int sysfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index f50e3cc2ded8..4869f611192f 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "sysfs.h" diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index bd7cec295dab..39c623fdc277 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -33,6 +33,22 @@ struct sysfs_symlink { struct kobject * target_kobj; }; +struct sysfs_buffer { + struct list_head associates; + size_t count; + loff_t pos; + char * page; + struct sysfs_ops * ops; + struct semaphore sem; + int orphaned; + int needs_read_fill; + int event; +}; + +struct sysfs_buffer_collection { + struct list_head associates; +}; + static inline struct kobject * to_kobj(struct dentry * dentry) { struct sysfs_dirent * sd = dentry->d_fsdata; -- cgit v1.2.3 From d3fc373ac5061cab7a654502b942e7d00e77f733 Mon Sep 17 00:00:00 2001 From: Frederik Deweerdt Date: Fri, 5 Jan 2007 12:04:33 -0800 Subject: sysfs: suppress lockdep warnings Lockdep issues the following warning: [ 9.064000] ============================================= [ 9.064000] [ INFO: possible recursive locking detected ] [ 9.064000] 2.6.20-rc3-mm1 #3 [ 9.064000] --------------------------------------------- [ 9.064000] init/1 is trying to acquire lock: [ 9.064000] (&sysfs_inode_imutex_key){--..}, at: [] mutex_lock+0x1c/0x1f [ 9.064000] [ 9.064000] but task is already holding lock: [ 9.064000] (&sysfs_inode_imutex_key){--..}, at: [] mutex_lock+0x1c/0x1f [ 9.065000] [ 9.065000] other info that might help us debug this: [ 9.065000] 2 locks held by init/1: [ 9.065000] #0: (tty_mutex){--..}, at: [] mutex_lock+0x1c/0x1f [ 9.065000] #1: (&sysfs_inode_imutex_key){--..}, at: [] mutex_lock+0x1c/0x1f [ 9.065000] [ 9.065000] stack backtrace: [ 9.065000] [] show_trace_log_lvl+0x1a/0x30 [ 9.066000] [] show_trace+0x12/0x14 [ 9.066000] [] dump_stack+0x16/0x18 [ 9.066000] [] print_deadlock_bug+0xb9/0xc3 [ 9.066000] [] check_deadlock+0x55/0x5a [ 9.066000] [] __lock_acquire+0x371/0xbf0 [ 9.066000] [] lock_acquire+0x69/0x83 [ 9.066000] [] __mutex_lock_slowpath+0x75/0x2d1 [ 9.066000] [] mutex_lock+0x1c/0x1f [ 9.066000] [] sysfs_drop_dentry+0xb1/0x133 [ 9.066000] [] sysfs_hash_and_remove+0xb3/0x142 [ 9.066000] [] sysfs_remove_file+0xd/0x10 [ 9.067000] [] device_remove_file+0x23/0x2e [ 9.067000] [] device_del+0x188/0x1e6 [ 9.067000] [] device_unregister+0xb/0x15 [ 9.067000] [] device_destroy+0x9c/0xa9 [ 9.067000] [] vcs_remove_sysfs+0x1c/0x3b [ 9.067000] [] con_close+0x5e/0x6b [ 9.067000] [] release_dev+0x4c4/0x6e5 [ 9.067000] [] tty_release+0x12/0x1c [ 9.067000] [] __fput+0x177/0x1a0 [ 9.067000] [] fput+0x3b/0x41 [ 9.068000] [] filp_close+0x36/0x65 [ 9.068000] [] sys_close+0x63/0xa4 [ 9.068000] [] sysenter_past_esp+0x5f/0x99 [ 9.068000] ======================= This is due to sysfs_hash_and_remove() holding dir->d_inode->i_mutex before calling sysfs_drop_dentry() which calls orphan_all_buffers() which in turn takes node->i_mutex. Signed-off-by: Frederik Deweerdt Cc: Oliver Neukum Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/inode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 1a81ebce20e9..dbd820f9aeed 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -215,7 +215,7 @@ static inline void orphan_all_buffers(struct inode *node) struct sysfs_buffer_collection *set = node->i_private; struct sysfs_buffer *buf; - mutex_lock(&node->i_mutex); + mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD); if (node->i_private) { list_for_each_entry(buf, &set->associates, associates) { down(&buf->sem); @@ -272,7 +272,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name) return -ENOENT; parent_sd = dir->d_fsdata; - mutex_lock(&dir->d_inode->i_mutex); + mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT); list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (!sd->s_element) continue; -- cgit v1.2.3 From f75065367077bd3b77842a5aa523ecd05d33e82d Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 2 Jan 2007 13:41:10 +0100 Subject: sysfs: kobject_put cleanup This patch removes redundant argument checks for kobject_put(). Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/bin.c | 5 ++--- fs/sysfs/file.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 9ec1c8539a5d..d3b9f5f07db1 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c @@ -147,7 +147,7 @@ static int open(struct inode * inode, struct file * file) Error: module_put(attr->attr.owner); Done: - if (error && kobj) + if (error) kobject_put(kobj); return error; } @@ -158,8 +158,7 @@ static int release(struct inode * inode, struct file * file) struct bin_attribute * attr = to_bin_attr(file->f_path.dentry); u8 * buffer = file->private_data; - if (kobj) - kobject_put(kobj); + kobject_put(kobj); module_put(attr->attr.owner); kfree(buffer); return 0; diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index cba4c1c7383c..46618f81ae48 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -361,7 +361,7 @@ static int sysfs_open_file(struct inode *inode, struct file *file) error = -EACCES; module_put(attr->owner); Done: - if (error && kobj) + if (error) kobject_put(kobj); return error; } @@ -375,8 +375,7 @@ static int sysfs_release(struct inode * inode, struct file * filp) if (buffer) remove_from_collection(buffer, inode); - if (kobj) - kobject_put(kobj); + kobject_put(kobj); /* After this point, attr should not be accessed. */ module_put(owner); -- cgit v1.2.3 From b067db49e1f4013ef02ef68845701b600e88a722 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Tue, 2 Jan 2007 13:44:44 +0100 Subject: kobject: kobject_put cleanup This patch removes redundant argument checks for kobject_put(). Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/kobject.c b/lib/kobject.c index c033dc8fa9af..74b8dbca150e 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -195,8 +195,7 @@ int kobject_add(struct kobject * kobj) if (error) { /* unlink does the kobject_put() for us */ unlink(kobj); - if (parent) - kobject_put(parent); + kobject_put(parent); /* be noisy on error issues */ if (error == -EEXIST) @@ -420,8 +419,7 @@ void kobject_cleanup(struct kobject * kobj) t->release(kobj); if (s) kset_put(s); - if (parent) - kobject_put(parent); + kobject_put(parent); } static void kobject_release(struct kref *kref) -- cgit v1.2.3 From 82244b169ed2eee1ef7f97a3a6693f5a6eff8a69 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 2 Jan 2007 08:48:08 +0100 Subject: sysfs: error handling in sysfs, fill_read_buffer() if a driver returns an error in fill_read_buffer(), the buffer will be marked as filled. Subsequent reads will return eof. But there is no data because of an error, not because it has been read. Not marking the buffer filled is the obvious fix. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 46618f81ae48..c0e117649a4d 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -83,7 +83,8 @@ remove_from_collection(struct sysfs_buffer *buffer, struct inode *node) * Allocate @buffer->page, if it hasn't been already, then call the * kobject's show() method to fill the buffer with this attribute's * data. - * This is called only once, on the file's first read. + * This is called only once, on the file's first read unless an error + * is returned. */ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer) { @@ -101,12 +102,13 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer buffer->event = atomic_read(&sd->s_event); count = ops->show(kobj,attr,buffer->page); - buffer->needs_read_fill = 0; BUG_ON(count > (ssize_t)PAGE_SIZE); - if (count >= 0) + if (count >= 0) { + buffer->needs_read_fill = 0; buffer->count = count; - else + } else { ret = count; + } return ret; } -- cgit v1.2.3 From 4de0ca8132861a4255d0a7a991bdfab38378267c Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Wed, 17 Jan 2007 04:54:07 -0500 Subject: HOWTO: Add a reference to Harbison and Steele Add a reference to Harbison and Steele's C book. Signed-off-by: Robert P. J. Day Signed-off-by: Greg Kroah-Hartman --- Documentation/HOWTO | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/HOWTO b/Documentation/HOWTO index 8d51c148f721..48123dba5e6a 100644 --- a/Documentation/HOWTO +++ b/Documentation/HOWTO @@ -30,6 +30,7 @@ are not a good substitute for a solid C education and/or years of experience, the following books are good for, if anything, reference: - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall] - "Practical C Programming" by Steve Oualline [O'Reilly] + - "C: A Reference Manual" by Harbison and Steele [Prentice Hall] The kernel is written using GNU C and the GNU toolchain. While it adheres to the ISO C89 standard, it uses a number of extensions that are -- cgit v1.2.3 From bf0acc330229554c695e4f95e5aa2d2c4f12de1f Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Wed, 17 Jan 2007 17:51:18 +0100 Subject: SYSFS: Fix missing include of list.h in sysfs.h Sysfs.h uses definitions (e.g. struct list_head s_sibling) from list.h but does not include it. Signed-off-by: Frank Haverkamp Signed-off-by: Greg Kroah-Hartman --- include/linux/sysfs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 2129d1b6c874..eee485957c0c 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -11,6 +11,7 @@ #define _SYSFS_H_ #include +#include #include struct kobject; -- cgit v1.2.3 From 239378f16aa1ab5c502e42a06359d2de4f88ebb4 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 7 Oct 2006 21:54:55 +0200 Subject: Driver core: add uevent vars for devices of a class Devices converted from class_device to device should have the same uevent keys as the original class_device had. We search up the parents until we find the first bus device and add the (already deprecated) PHYDEV* values. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 6fee3e6b1ac2..7a5336f7df89 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -154,25 +154,47 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, "MINOR=%u", MINOR(dev->devt)); } -#ifdef CONFIG_SYSFS_DEPRECATED - /* add bus name (same as SUBSYSTEM, deprecated) */ - if (dev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", dev->bus->name); -#endif - - /* add driver name (PHYSDEV* values are deprecated)*/ - if (dev->driver) { + if (dev->driver) add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, "DRIVER=%s", dev->driver->name); + #ifdef CONFIG_SYSFS_DEPRECATED + if (dev->class) { + struct device *parent = dev->parent; + + /* find first bus device in parent chain */ + while (parent && !parent->bus) + parent = parent->parent; + if (parent && parent->bus) { + const char *path; + + path = kobject_get_path(&parent->kobj, GFP_KERNEL); + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVPATH=%s", path); + kfree(path); + + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVBUS=%s", parent->bus->name); + + if (parent->driver) + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVDRIVER=%s", parent->driver->name); + } + } else if (dev->bus) { add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", dev->driver->name); -#endif + "PHYSDEVBUS=%s", dev->bus->name); + + if (dev->driver) + add_uevent_var(envp, num_envp, &i, + buffer, buffer_size, &length, + "PHYSDEVDRIVER=%s", dev->driver->name); } +#endif /* terminate, set to next free slot, shrink available space */ envp[i] = NULL; -- cgit v1.2.3 From f9f852df2faf76a2667949ddb4947d4b8f99f02f Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 7 Oct 2006 21:54:55 +0200 Subject: Driver core: add device_type to struct device This allows us to add type specific attributes, uevent vars and release funtions. A subsystem can carry different types of devices like the "block" subsys has disks and partitions. Both types create a different set of attributes, but belong to the same subsystem. This corresponds to the low level objects: kobject -> device (object/device data) kobj_type -> device_type (type of object/device we are embedded in) kset -> class/bus (list of objects/devices of a subsystem) Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 57 ++++++++++++++++++++++++++++++-------------- drivers/usb/input/hid-lgff.c | 4 ++-- include/linux/device.h | 8 +++++++ 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 7a5336f7df89..34ac18778d8a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -95,6 +95,8 @@ static void device_release(struct kobject * kobj) if (dev->release) dev->release(dev); + else if (dev->type && dev->type->release) + dev->type->release(dev); else if (dev->class && dev->class->dev_release) dev->class->dev_release(dev); else { @@ -206,19 +208,25 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, if (dev->bus && dev->bus->uevent) { /* have the bus specific function add its stuff */ retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); - if (retval) { - pr_debug ("%s - uevent() returned %d\n", + if (retval) + pr_debug ("%s: bus uevent() returned %d\n", __FUNCTION__, retval); - } } if (dev->class && dev->class->dev_uevent) { /* have the class specific function add its stuff */ retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); - if (retval) { - pr_debug("%s - dev_uevent() returned %d\n", - __FUNCTION__, retval); - } + if (retval) + pr_debug("%s: class uevent() returned %d\n", + __FUNCTION__, retval); + } + + if (dev->type && dev->type->uevent) { + /* have the device type specific fuction add its stuff */ + retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); + if (retval) + pr_debug("%s: dev_type uevent() returned %d\n", + __FUNCTION__, retval); } return retval; @@ -269,37 +277,50 @@ static void device_remove_groups(struct device *dev) static int device_add_attrs(struct device *dev) { struct class *class = dev->class; + struct device_type *type = dev->type; int error = 0; int i; - if (!class) - return 0; - - if (class->dev_attrs) { + if (class && class->dev_attrs) { for (i = 0; attr_name(class->dev_attrs[i]); i++) { error = device_create_file(dev, &class->dev_attrs[i]); if (error) break; } + if (error) + while (--i >= 0) + device_remove_file(dev, &class->dev_attrs[i]); } - if (error) - while (--i >= 0) - device_remove_file(dev, &class->dev_attrs[i]); + + if (type && type->attrs) { + for (i = 0; attr_name(type->attrs[i]); i++) { + error = device_create_file(dev, &type->attrs[i]); + if (error) + break; + } + if (error) + while (--i >= 0) + device_remove_file(dev, &type->attrs[i]); + } + return error; } static void device_remove_attrs(struct device *dev) { struct class *class = dev->class; + struct device_type *type = dev->type; int i; - if (!class) - return; - - if (class->dev_attrs) { + if (class && class->dev_attrs) { for (i = 0; attr_name(class->dev_attrs[i]); i++) device_remove_file(dev, &class->dev_attrs[i]); } + + if (type && type->attrs) { + for (i = 0; attr_name(type->attrs[i]); i++) + device_remove_file(dev, &type->attrs[i]); + } } diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index e47466268565..4f4fc3be192e 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -32,7 +32,7 @@ #include #include "usbhid.h" -struct device_type { +struct dev_type { u16 idVendor; u16 idProduct; const signed short *ff; @@ -48,7 +48,7 @@ static const signed short ff_joystick[] = { -1 }; -static const struct device_type devices[] = { +static const struct dev_type devices[] = { { 0x046d, 0xc211, ff_rumble }, { 0x046d, 0xc219, ff_rumble }, { 0x046d, 0xc283, ff_joystick }, diff --git a/include/linux/device.h b/include/linux/device.h index da7221913114..e1e164f81eea 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -328,6 +328,13 @@ extern struct class_device *class_device_create(struct class *cls, __attribute__((format(printf,5,6))); extern void class_device_destroy(struct class *cls, dev_t devt); +struct device_type { + struct device_attribute *attrs; + int (*uevent)(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size); + void (*release)(struct device *dev); +}; + /* interface for exporting device attributes */ struct device_attribute { struct attribute attr; @@ -356,6 +363,7 @@ struct device { struct kobject kobj; char bus_id[BUS_ID_SIZE]; /* position on parent bus */ + struct device_type *type; unsigned is_registered:1; struct device_attribute uevent_attr; struct device_attribute *devt_attr; -- cgit v1.2.3 From b7a3e813fb84624166f034e25234f98de5846bfc Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 7 Oct 2006 21:54:55 +0200 Subject: Driver core: allow to delay the uevent at device creation time For the block subsystem, we want to delay all uevents until the disk has been scanned and allpartitons are already created before the first event is sent out. Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 3 ++- include/linux/device.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 34ac18778d8a..e13614241c9e 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -589,7 +589,8 @@ int device_add(struct device *dev) goto PMError; if ((error = bus_add_device(dev))) goto BusError; - kobject_uevent(&dev->kobj, KOBJ_ADD); + if (!dev->uevent_suppress) + kobject_uevent(&dev->kobj, KOBJ_ADD); if ((error = bus_attach_device(dev))) goto AttachError; if (parent) diff --git a/include/linux/device.h b/include/linux/device.h index e1e164f81eea..5ca1cdba563a 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -399,9 +399,10 @@ struct device { /* class_device migration path */ struct list_head node; - struct class *class; /* optional*/ + struct class *class; dev_t devt; /* dev_t, creates the sysfs "dev" */ struct attribute_group **groups; /* optional groups */ + int uevent_suppress; void (*release)(struct device * dev); }; -- cgit v1.2.3 From 2f65168de7d68a5795e945e781d85b313bdc97b9 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 25 Jan 2007 15:56:15 -0500 Subject: Driver Core: Increase the default timeout value of the firmware subsystem https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=174589 The ipw driver sometimes takes a long time to load its firmware. Whilst the ipw driver should be using the async interface of the firmware loader to make this a non-issue, this is a minimal fix. Signed-off-by: Dave Jones Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 64558f45e6bc..c0a979a5074b 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -35,7 +35,7 @@ enum { FW_STATUS_READY_NOHOTPLUG, }; -static int loading_timeout = 10; /* In seconds */ +static int loading_timeout = 60; /* In seconds */ /* fw_lock could be moved to 'struct firmware_priv' but since it is just * guarding for corner cases a global lock should be OK */ -- cgit v1.2.3 From b592fcfe7f06c15ec11774b5be7ce0de3aa86e73 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 24 Jan 2007 12:35:52 -0700 Subject: sysfs: Shadow directory support The problem. When implementing a network namespace I need to be able to have multiple network devices with the same name. Currently this is a problem for /sys/class/net/*. What I want is a separate /sys/class/net directory in sysfs for each network namespace, and I want to name each of them /sys/class/net. I looked and the VFS actually allows that. All that is needed is for /sys/class/net to implement a follow link method to redirect lookups to the real directory you want. Implementing a follow link method that is sensitive to the current network namespace turns out to be 3 lines of code so it looks like a clean approach. Modifying sysfs so it doesn't get in my was is a bit trickier. I am calling the concept of multiple directories all at the same path in the filesystem shadow directories. With the directory entry really at that location the shadow master. The following patch modifies sysfs so it can handle a directory structure slightly different from the kobject tree so I can implement the shadow directories for handling /sys/class/net/. Signed-off-by: Eric W. Biederman Cc: Maneesh Soni Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 207 ++++++++++++++++++++++++++++++++++++++++-------- fs/sysfs/group.c | 1 + fs/sysfs/inode.c | 10 +++ fs/sysfs/mount.c | 2 +- fs/sysfs/sysfs.h | 5 ++ include/linux/kobject.h | 4 + include/linux/sysfs.h | 23 +++++- lib/kobject.c | 42 ++++++++-- 8 files changed, 249 insertions(+), 45 deletions(-) diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 9ff04491e3ea..9dcdf556c99c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -33,8 +33,7 @@ static struct dentry_operations sysfs_dentry_ops = { /* * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent */ -static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, - void * element) +static struct sysfs_dirent * __sysfs_new_dirent(void * element) { struct sysfs_dirent * sd; @@ -46,12 +45,28 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd, atomic_set(&sd->s_count, 1); atomic_set(&sd->s_event, 1); INIT_LIST_HEAD(&sd->s_children); - list_add(&sd->s_sibling, &parent_sd->s_children); + INIT_LIST_HEAD(&sd->s_sibling); sd->s_element = element; return sd; } +static void __sysfs_list_dirent(struct sysfs_dirent *parent_sd, + struct sysfs_dirent *sd) +{ + if (sd) + list_add(&sd->s_sibling, &parent_sd->s_children); +} + +static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent *parent_sd, + void * element) +{ + struct sysfs_dirent *sd; + sd = __sysfs_new_dirent(element); + __sysfs_list_dirent(parent_sd, sd); + return sd; +} + /* * * Return -EEXIST if there is already a sysfs element with the same name for @@ -78,14 +93,14 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd, } -int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, - void * element, umode_t mode, int type) +static struct sysfs_dirent * +__sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type) { struct sysfs_dirent * sd; - sd = sysfs_new_dirent(parent_sd, element); + sd = __sysfs_new_dirent(element); if (!sd) - return -ENOMEM; + goto out; sd->s_mode = mode; sd->s_type = type; @@ -95,7 +110,19 @@ int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, dentry->d_op = &sysfs_dentry_ops; } - return 0; +out: + return sd; +} + +int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry, + void * element, umode_t mode, int type) +{ + struct sysfs_dirent *sd; + + sd = __sysfs_make_dirent(dentry, element, mode, type); + __sysfs_list_dirent(parent_sd, sd); + + return sd ? 0 : -ENOMEM; } static int init_dir(struct inode * inode) @@ -166,11 +193,11 @@ int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d) /** * sysfs_create_dir - create a directory for an object. - * @parent: parent parent object. * @kobj: object we're creating directory for. + * @shadow_parent: parent parent object. */ -int sysfs_create_dir(struct kobject * kobj) +int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent) { struct dentry * dentry = NULL; struct dentry * parent; @@ -178,7 +205,9 @@ int sysfs_create_dir(struct kobject * kobj) BUG_ON(!kobj); - if (kobj->parent) + if (shadow_parent) + parent = shadow_parent; + else if (kobj->parent) parent = kobj->parent->dentry; else if (sysfs_mount && sysfs_mount->mnt_sb) parent = sysfs_mount->mnt_sb->s_root; @@ -299,21 +328,12 @@ void sysfs_remove_subdir(struct dentry * d) } -/** - * sysfs_remove_dir - remove an object's directory. - * @kobj: object. - * - * The only thing special about this is that we remove any files in - * the directory before we remove the directory, and we've inlined - * what used to be sysfs_rmdir() below, instead of calling separately. - */ - -void sysfs_remove_dir(struct kobject * kobj) +static void __sysfs_remove_dir(struct dentry *dentry) { - struct dentry * dentry = dget(kobj->dentry); struct sysfs_dirent * parent_sd; struct sysfs_dirent * sd, * tmp; + dget(dentry); if (!dentry) return; @@ -334,32 +354,60 @@ void sysfs_remove_dir(struct kobject * kobj) * Drop reference from dget() on entrance. */ dput(dentry); +} + +/** + * sysfs_remove_dir - remove an object's directory. + * @kobj: object. + * + * The only thing special about this is that we remove any files in + * the directory before we remove the directory, and we've inlined + * what used to be sysfs_rmdir() below, instead of calling separately. + */ + +void sysfs_remove_dir(struct kobject * kobj) +{ + __sysfs_remove_dir(kobj->dentry); kobj->dentry = NULL; } -int sysfs_rename_dir(struct kobject * kobj, const char *new_name) +int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent, + const char *new_name) { int error = 0; - struct dentry * new_dentry, * parent; + struct dentry * new_dentry; - if (!strcmp(kobject_name(kobj), new_name)) - return -EINVAL; - - if (!kobj->parent) - return -EINVAL; + if (!new_parent) + return -EFAULT; down_write(&sysfs_rename_sem); - parent = kobj->parent->dentry; + mutex_lock(&new_parent->d_inode->i_mutex); - mutex_lock(&parent->d_inode->i_mutex); - - new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); + new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name)); if (!IS_ERR(new_dentry)) { - if (!new_dentry->d_inode) { + /* By allowing two different directories with the + * same d_parent we allow this routine to move + * between different shadows of the same directory + */ + if (kobj->dentry->d_parent->d_inode != new_parent->d_inode) + return -EINVAL; + else if (new_dentry->d_parent->d_inode != new_parent->d_inode) + error = -EINVAL; + else if (new_dentry == kobj->dentry) + error = -EINVAL; + else if (!new_dentry->d_inode) { error = kobject_set_name(kobj, "%s", new_name); if (!error) { + struct sysfs_dirent *sd, *parent_sd; + d_add(new_dentry, NULL); d_move(kobj->dentry, new_dentry); + + sd = kobj->dentry->d_fsdata; + parent_sd = new_parent->d_fsdata; + + list_del_init(&sd->s_sibling); + list_add(&sd->s_sibling, &parent_sd->s_children); } else d_drop(new_dentry); @@ -367,7 +415,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name) error = -EEXIST; dput(new_dentry); } - mutex_unlock(&parent->d_inode->i_mutex); + mutex_unlock(&new_parent->d_inode->i_mutex); up_write(&sysfs_rename_sem); return error; @@ -546,6 +594,95 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin) return offset; } + +/** + * sysfs_make_shadowed_dir - Setup so a directory can be shadowed + * @kobj: object we're creating shadow of. + */ + +int sysfs_make_shadowed_dir(struct kobject *kobj, + void * (*follow_link)(struct dentry *, struct nameidata *)) +{ + struct inode *inode; + struct inode_operations *i_op; + + inode = kobj->dentry->d_inode; + if (inode->i_op != &sysfs_dir_inode_operations) + return -EINVAL; + + i_op = kmalloc(sizeof(*i_op), GFP_KERNEL); + if (!i_op) + return -ENOMEM; + + memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op)); + i_op->follow_link = follow_link; + + /* Locking of inode->i_op? + * Since setting i_op is a single word write and they + * are atomic we should be ok here. + */ + inode->i_op = i_op; + return 0; +} + +/** + * sysfs_create_shadow_dir - create a shadow directory for an object. + * @kobj: object we're creating directory for. + * + * sysfs_make_shadowed_dir must already have been called on this + * directory. + */ + +struct dentry *sysfs_create_shadow_dir(struct kobject *kobj) +{ + struct sysfs_dirent *sd; + struct dentry *parent, *dir, *shadow; + struct inode *inode; + + dir = kobj->dentry; + inode = dir->d_inode; + parent = dir->d_parent; + shadow = ERR_PTR(-EINVAL); + if (!sysfs_is_shadowed_inode(inode)) + goto out; + + shadow = d_alloc(parent, &dir->d_name); + if (!shadow) + goto nomem; + + sd = __sysfs_make_dirent(shadow, kobj, inode->i_mode, SYSFS_DIR); + if (!sd) + goto nomem; + + d_instantiate(shadow, igrab(inode)); + inc_nlink(inode); + inc_nlink(parent->d_inode); + shadow->d_op = &sysfs_dentry_ops; + + dget(shadow); /* Extra count - pin the dentry in core */ + +out: + return shadow; +nomem: + dput(shadow); + shadow = ERR_PTR(-ENOMEM); + goto out; +} + +/** + * sysfs_remove_shadow_dir - remove an object's directory. + * @shadow: dentry of shadow directory + * + * The only thing special about this is that we remove any files in + * the directory before we remove the directory, and we've inlined + * what used to be sysfs_rmdir() below, instead of calling separately. + */ + +void sysfs_remove_shadow_dir(struct dentry *shadow) +{ + __sysfs_remove_dir(shadow); +} + const struct file_operations sysfs_dir_operations = { .open = sysfs_dir_open, .release = sysfs_dir_close, diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 46a277b0838e..b20951c93761 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "sysfs.h" diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index dbd820f9aeed..542d2bcc73df 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -33,6 +33,16 @@ static struct inode_operations sysfs_inode_operations ={ .setattr = sysfs_setattr, }; +void sysfs_delete_inode(struct inode *inode) +{ + /* Free the shadowed directory inode operations */ + if (sysfs_is_shadowed_inode(inode)) { + kfree(inode->i_op); + inode->i_op = NULL; + } + return generic_delete_inode(inode); +} + int sysfs_setattr(struct dentry * dentry, struct iattr * iattr) { struct inode * inode = dentry->d_inode; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index a1a58b97f322..f6a87a824883 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -23,7 +23,7 @@ static void sysfs_clear_inode(struct inode *inode); static struct super_operations sysfs_ops = { .statfs = simple_statfs, - .drop_inode = generic_delete_inode, + .drop_inode = sysfs_delete_inode, .clear_inode = sysfs_clear_inode, }; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 39c623fdc277..fe1cbfd208ed 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -2,6 +2,7 @@ extern struct vfsmount * sysfs_mount; extern struct kmem_cache *sysfs_dir_cachep; +extern void sysfs_delete_inode(struct inode *inode); extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *); extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *)); @@ -112,3 +113,7 @@ static inline void sysfs_put(struct sysfs_dirent * sd) release_sysfs_dirent(sd); } +static inline int sysfs_is_shadowed_inode(struct inode *inode) +{ + return S_ISDIR(inode->i_mode) && inode->i_op->follow_link; +} diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 76538fcf2c4e..b850e0310538 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -74,9 +74,13 @@ extern void kobject_init(struct kobject *); extern void kobject_cleanup(struct kobject *); extern int __must_check kobject_add(struct kobject *); +extern int __must_check kobject_shadow_add(struct kobject *, struct dentry *); extern void kobject_del(struct kobject *); extern int __must_check kobject_rename(struct kobject *, const char *new_name); +extern int __must_check kobject_shadow_rename(struct kobject *kobj, + struct dentry *new_parent, + const char *new_name); extern int __must_check kobject_move(struct kobject *, struct kobject *); extern int __must_check kobject_register(struct kobject *); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index eee485957c0c..192de3afa96b 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -16,6 +16,7 @@ struct kobject; struct module; +struct nameidata; struct attribute { const char * name; @@ -89,13 +90,13 @@ struct sysfs_dirent { #ifdef CONFIG_SYSFS extern int __must_check -sysfs_create_dir(struct kobject *); +sysfs_create_dir(struct kobject *, struct dentry *); extern void sysfs_remove_dir(struct kobject *); extern int __must_check -sysfs_rename_dir(struct kobject *, const char *new_name); +sysfs_rename_dir(struct kobject *, struct dentry *, const char *new_name); extern int __must_check sysfs_move_dir(struct kobject *, struct kobject *); @@ -127,11 +128,17 @@ int __must_check sysfs_create_group(struct kobject *, void sysfs_remove_group(struct kobject *, const struct attribute_group *); void sysfs_notify(struct kobject * k, char *dir, char *attr); + +extern int sysfs_make_shadowed_dir(struct kobject *kobj, + void * (*follow_link)(struct dentry *, struct nameidata *)); +extern struct dentry *sysfs_create_shadow_dir(struct kobject *kobj); +extern void sysfs_remove_shadow_dir(struct dentry *dir); + extern int __must_check sysfs_init(void); #else /* CONFIG_SYSFS */ -static inline int sysfs_create_dir(struct kobject * k) +static inline int sysfs_create_dir(struct kobject * k, struct dentry *shadow) { return 0; } @@ -141,7 +148,9 @@ static inline void sysfs_remove_dir(struct kobject * k) ; } -static inline int sysfs_rename_dir(struct kobject * k, const char *new_name) +static inline int sysfs_rename_dir(struct kobject * k, + struct dentry *new_parent, + const char *new_name) { return 0; } @@ -205,6 +214,12 @@ static inline void sysfs_notify(struct kobject * k, char *dir, char *attr) { } +static inline int sysfs_make_shadowed_dir(struct kobject *kobj, + void * (*follow_link)(struct dentry *, struct nameidata *)) +{ + return 0; +} + static inline int __must_check sysfs_init(void) { return 0; diff --git a/lib/kobject.c b/lib/kobject.c index 74b8dbca150e..c2917ffe8bf1 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -44,11 +44,11 @@ static int populate_dir(struct kobject * kobj) return error; } -static int create_dir(struct kobject * kobj) +static int create_dir(struct kobject * kobj, struct dentry *shadow_parent) { int error = 0; if (kobject_name(kobj)) { - error = sysfs_create_dir(kobj); + error = sysfs_create_dir(kobj, shadow_parent); if (!error) { if ((error = populate_dir(kobj))) sysfs_remove_dir(kobj); @@ -158,9 +158,10 @@ static void unlink(struct kobject * kobj) /** * kobject_add - add an object to the hierarchy. * @kobj: object. + * @shadow_parent: sysfs directory to add to. */ -int kobject_add(struct kobject * kobj) +int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent) { int error = 0; struct kobject * parent; @@ -191,7 +192,7 @@ int kobject_add(struct kobject * kobj) } kobj->parent = parent; - error = create_dir(kobj); + error = create_dir(kobj, shadow_parent); if (error) { /* unlink does the kobject_put() for us */ unlink(kobj); @@ -212,6 +213,15 @@ int kobject_add(struct kobject * kobj) return error; } +/** + * kobject_add - add an object to the hierarchy. + * @kobj: object. + */ +int kobject_add(struct kobject * kobj) +{ + return kobject_shadow_add(kobj, NULL); +} + /** * kobject_register - initialize and add an object. @@ -304,7 +314,29 @@ int kobject_rename(struct kobject * kobj, const char *new_name) kobj = kobject_get(kobj); if (!kobj) return -EINVAL; - error = sysfs_rename_dir(kobj, new_name); + if (!kobj->parent) + return -EINVAL; + error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name); + kobject_put(kobj); + + return error; +} + +/** + * kobject_rename - change the name of an object + * @kobj: object in question. + * @new_name: object's new name + */ + +int kobject_shadow_rename(struct kobject * kobj, struct dentry *new_parent, + const char *new_name) +{ + int error = 0; + + kobj = kobject_get(kobj); + if (!kobj) + return -EINVAL; + error = sysfs_rename_dir(kobj, new_parent, new_name); kobject_put(kobj); return error; -- cgit v1.2.3