From a3500b9e955d47891e57587c30006de83a3591f5 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 11 Feb 2004 21:00:34 -0800 Subject: [PATCH] Fix "bus_for_each_dev()" and "bus_for_each_drv()", which did not correctly handle the "restart from this device/driver" case, and caused oopses with ieee1394. This just uses "list_for_each_entry_continue()" instead. Add helper macro to make usage of "list_for_each_entry_continue()" a bit more readable. --- drivers/base/bus.c | 20 ++++++++++++-------- include/linux/list.h | 10 ++++++++++ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 28982a1c4371..5a2b6b74daf1 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -158,17 +158,19 @@ decl_subsys(bus,&ktype_bus,NULL); int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, int (*fn)(struct device *, void *)) { - struct list_head * head, * entry; + struct device *dev; + struct list_head * head; int error = 0; if (!(bus = get_bus(bus))) return -EINVAL; - head = start ? &start->bus_list : &bus->devices.list; + head = &bus->devices.list; + dev = list_prepare_entry(start, head, bus_list); down_read(&bus->subsys.rwsem); - list_for_each(entry,head) { - struct device * dev = get_device(to_dev(entry)); + list_for_each_entry_continue(dev, head, bus_list) { + get_device(dev); error = fn(dev,data); put_device(dev); if (error) @@ -202,17 +204,19 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start, int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, void * data, int (*fn)(struct device_driver *, void *)) { - struct list_head * head, * entry; + struct list_head * head; + struct device_driver *drv; int error = 0; if(!(bus = get_bus(bus))) return -EINVAL; - head = start ? &start->kobj.entry : &bus->drivers.list; + head = &bus->drivers.list; + drv = list_prepare_entry(start, head, kobj.entry); down_read(&bus->subsys.rwsem); - list_for_each(entry,head) { - struct device_driver * drv = get_driver(to_drv(entry)); + list_for_each_entry_continue(drv, head, kobj.entry) { + get_driver(drv); error = fn(drv,data); put_driver(drv); if(error) diff --git a/include/linux/list.h b/include/linux/list.h index 9a5df31af22e..5388098449cc 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -343,6 +343,16 @@ static inline void list_splice_init(struct list_head *list, pos = list_entry(pos->member.prev, typeof(*pos), member), \ prefetch(pos->member.prev)) +/** + * list_prepare_entry - prepare a pos entry for use as a start point in + * list_for_each_entry_continue + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_struct within the struct. + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + /** * list_for_each_entry_continue - iterate over list of given type * continuing after existing point -- 2.39.5