diff mbox

[RFC] drivers/base: Add bus_register_notifier_alldev() variant

Message ID 20090306160818.404.92700.stgit@localhost.localdomain (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Grant Likely March 6, 2009, 4:10 p.m. UTC
From: Grant Likely <grant.likely@secretlab.ca>

bus_register_notifier_alldev() is a variation on bus_register_notifier()
which also triggers the notifier callback for devices already on the bus
and already bound to drivers.

This function is useful for the case where a driver needs to get a
reference to a struct device other than the one it is bound to and
it is not known if the device will be bound before or after this
function is called.  For example, an Ethernet device connected to
a PHY that is probed separately.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
CC: linux-kernel@vger.kernel.org
CC: linuxppc-dev@ozlabs.org
CC: Greg Kroah-Hartman <gregkh@suse.de>
---

I'm using this as part of some changes to phylib to make it easier for
Ethernet drivers to find their PHY device.  Before I'm completely committed
to this approach I'd like some feedback on this change to drivers core.

Thanks,
g.


 drivers/base/bus.c     |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/device.h |    2 ++
 2 files changed, 49 insertions(+), 0 deletions(-)

Comments

gregkh@suse.de March 11, 2009, 4:26 p.m. UTC | #1
On Fri, Mar 06, 2009 at 09:10:19AM -0700, Grant Likely wrote:
> From: Grant Likely <grant.likely@secretlab.ca>
> 
> bus_register_notifier_alldev() is a variation on bus_register_notifier()
> which also triggers the notifier callback for devices already on the bus
> and already bound to drivers.
> 
> This function is useful for the case where a driver needs to get a
> reference to a struct device other than the one it is bound to and
> it is not known if the device will be bound before or after this
> function is called.  For example, an Ethernet device connected to
> a PHY that is probed separately.

Can't you just walk the list of all devices already on the bus to get
"notified" of them, and then register your notifier handler as well (or
register it first, and then walk the list, which is pretty much what
your patch does)?

I see this api addition as just confusing people as to which one they
should register for :)

thanks,

greg k-h
Grant Likely March 11, 2009, 4:35 p.m. UTC | #2
On Wed, Mar 11, 2009 at 10:26 AM, Greg KH <gregkh@suse.de> wrote:
> On Fri, Mar 06, 2009 at 09:10:19AM -0700, Grant Likely wrote:
>> From: Grant Likely <grant.likely@secretlab.ca>
>>
>> bus_register_notifier_alldev() is a variation on bus_register_notifier()
>> which also triggers the notifier callback for devices already on the bus
>> and already bound to drivers.
>>
>> This function is useful for the case where a driver needs to get a
>> reference to a struct device other than the one it is bound to and
>> it is not known if the device will be bound before or after this
>> function is called.  For example, an Ethernet device connected to
>> a PHY that is probed separately.
>
> Can't you just walk the list of all devices already on the bus to get
> "notified" of them, and then register your notifier handler as well (or
> register it first, and then walk the list, which is pretty much what
> your patch does)?

Yes, and I originally did, but it looks to me like a useful common
pattern that is less error prone than open coding it.

g.
gregkh@suse.de March 11, 2009, 5 p.m. UTC | #3
On Wed, Mar 11, 2009 at 10:35:29AM -0600, Grant Likely wrote:
> On Wed, Mar 11, 2009 at 10:26 AM, Greg KH <gregkh@suse.de> wrote:
> > On Fri, Mar 06, 2009 at 09:10:19AM -0700, Grant Likely wrote:
> >> From: Grant Likely <grant.likely@secretlab.ca>
> >>
> >> bus_register_notifier_alldev() is a variation on bus_register_notifier()
> >> which also triggers the notifier callback for devices already on the bus
> >> and already bound to drivers.
> >>
> >> This function is useful for the case where a driver needs to get a
> >> reference to a struct device other than the one it is bound to and
> >> it is not known if the device will be bound before or after this
> >> function is called.  For example, an Ethernet device connected to
> >> a PHY that is probed separately.
> >
> > Can't you just walk the list of all devices already on the bus to get
> > "notified" of them, and then register your notifier handler as well (or
> > register it first, and then walk the list, which is pretty much what
> > your patch does)?
> 
> Yes, and I originally did, but it looks to me like a useful common
> pattern that is less error prone than open coding it.

How about we wait, and if someone else does the same thing, we then add
it to the core like this?

Actually, wouldn't it make more sense to just change the default
"bus_register_notifier" to do this?  Is there some reason that the
caller would not want this kind of thing to happen?

thanks,

greg k-h
Grant Likely March 16, 2009, 9:22 p.m. UTC | #4
On Wed, Mar 11, 2009 at 11:00 AM, Greg KH <gregkh@suse.de> wrote:
> On Wed, Mar 11, 2009 at 10:35:29AM -0600, Grant Likely wrote:
>> On Wed, Mar 11, 2009 at 10:26 AM, Greg KH <gregkh@suse.de> wrote:
>> > On Fri, Mar 06, 2009 at 09:10:19AM -0700, Grant Likely wrote:
>> >> From: Grant Likely <grant.likely@secretlab.ca>
>> >>
>> >> bus_register_notifier_alldev() is a variation on bus_register_notifier()
>> >> which also triggers the notifier callback for devices already on the bus
>> >> and already bound to drivers.
>> >>
>> >> This function is useful for the case where a driver needs to get a
>> >> reference to a struct device other than the one it is bound to and
>> >> it is not known if the device will be bound before or after this
>> >> function is called.  For example, an Ethernet device connected to
>> >> a PHY that is probed separately.
>> >
>> > Can't you just walk the list of all devices already on the bus to get
>> > "notified" of them, and then register your notifier handler as well (or
>> > register it first, and then walk the list, which is pretty much what
>> > your patch does)?
>>
>> Yes, and I originally did, but it looks to me like a useful common
>> pattern that is less error prone than open coding it.
>
> How about we wait, and if someone else does the same thing, we then add
> it to the core like this?

I'm okay with that.  Actually, I had two drivers that were using this,
but that need has gone away because I've learned that I can defer
locating the other device to open() time.  I still think that it may
be useful, but I agree that simply theoretical usage is not a good
reason to add the API.

> Actually, wouldn't it make more sense to just change the default
> "bus_register_notifier" to do this?  Is there some reason that the
> caller would not want this kind of thing to happen?

It doesn't look like there are many users of this facility, and from
looking at them it appears that adding the reporting of already
registered & bound devices would make sense.  However, to do this my
patch would need to be fixed to eliminate the race condition where an
add or bind event could get reported more than once on a single
device.  It looks like the existing users expect never to be called
more than once for each device.  Unfortunately, I don't know how to
fix the race.  I need to research more.

g.
diff mbox

Patch

diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 83f32b8..6edde85 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -962,6 +962,53 @@  int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(bus_register_notifier);
 
+/**
+ * bus_register_notifier_alldev_helper - internal support function
+ * Used by bus_register_notifier_alldev() to create ADD and BOUND events
+ * for devices.
+ */
+static int bus_register_notifier_alldev_helper(struct device *dev, void *data)
+{
+	struct notifier_block *nb = data;
+	nb->notifier_call(nb, BUS_NOTIFY_ADD_DEVICE, dev);
+	if (dev->driver)
+		nb->notifier_call(nb, BUS_NOTIFY_BOUND_DRIVER, dev);
+	return 0;
+}
+
+/**
+ * bus_register_notifier_alldev - Register for bus events; include existing devs
+ * @bus: pointer to bus_type
+ * @nb: pointer to notifier block to register with the bus
+ *
+ * Similar to bus_register_notifier() except it also generates events for
+ * devices already on the bus when the notifier is registered.  When this
+ * function is called the notifier is called once for each device with
+ * the BUS_NOTIFY_ADD_DEVICE event, and once for each device registered to
+ * a driver * with the BUS_NOTIFY_BOUND_DRIVER event.
+ *
+ * There is a small chance that the notifier could be called more than once
+ * for a device.  This would happen if a new device was registered on the bus
+ * or bound to a driver between the call to bus_register_notifier() and the
+ * call to bus_for_each_dev().  The only way I can see to protect against
+ * this would be to take the klist_devices spinlock while calling the
+ * notifier; but that would be a Very Bad Thing (tm).  Caller needs to be
+ * aware that a notifier called before this function returns might get
+ * called a second time on the same device.
+ */
+int bus_register_notifier_alldev(struct bus_type *b, struct notifier_block *nb)
+{
+	int ret;
+
+	ret = bus_register_notifier(b, nb);
+	if (ret == 0) {
+		bus_for_each_dev(b, NULL, nb,
+				 bus_register_notifier_alldev_helper);
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(bus_register_notifier_alldev);
+
 int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb)
 {
 	return blocking_notifier_chain_unregister(&bus->p->bus_notifier, nb);
diff --git a/include/linux/device.h b/include/linux/device.h
index 45e5b19..05c7d5b 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -103,6 +103,8 @@  struct notifier_block;
 
 extern int bus_register_notifier(struct bus_type *bus,
 				 struct notifier_block *nb);
+extern int bus_register_notifier_alldev(struct bus_type *b,
+					struct notifier_block *nb);
 extern int bus_unregister_notifier(struct bus_type *bus,
 				   struct notifier_block *nb);