diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-02-08 14:13:11 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-02-09 12:43:07 +0300 |
commit | 273afac615adccf97bd4e70ebfb27074f1ff22b9 (patch) | |
tree | 1625597d52c9e18ac1570579f22a8b973215f711 /drivers/base/bus.c | |
parent | 789be03a600842ef461968cc5a2d458f51f319b2 (diff) | |
download | linux-273afac615adccf97bd4e70ebfb27074f1ff22b9.tar.xz |
driver core: bus: implement bus_get/put() without the private pointer
In the quest to make 'struct bus_type' constant and in read-only memory,
we need to stop using the private pointer to the subsys_private
structure. First step in doing this is to create a helper function that
turns a 'struct bus_type' into 'struct subsys_private' called
bus_to_subsys().
bus_to_subsys() walks the list of registered busses in the system and
finds the matching one based on the pointer to the bus_type itself. As
this is a short list, and this function is not on any fast path, it
should not be noticable.
Implement bus_get() and bus_put() using this new helper function.
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
Link: https://lore.kernel.org/r/20230208111330.439504-3-gregkh@linuxfoundation.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/base/bus.c')
-rw-r--r-- | drivers/base/bus.c | 61 |
1 files changed, 53 insertions, 8 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index d6b4a5d5a43c..8f46ab84e81a 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -24,6 +24,9 @@ /* /sys/devices/system */ static struct kset *system_kset; +/* /sys/bus */ +static struct kset *bus_kset; + #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) /* @@ -39,19 +42,63 @@ static struct kset *system_kset; static int __must_check bus_rescan_devices_helper(struct device *dev, void *data); +/** + * bus_to_subsys - Turn a struct bus_type into a struct subsys_private + * + * @bus: pointer to the struct bus_type to look up + * + * The driver core internals needs to work on the subsys_private structure, not + * the external struct bus_type pointer. This function walks the list of + * registered busses in the system and finds the matching one and returns the + * internal struct subsys_private that relates to that bus. + * + * Note, the reference count of the return value is INCREMENTED if it is not + * NULL. A call to subsys_put() must be done when finished with the pointer in + * order for it to be properly freed. + */ +static struct subsys_private *bus_to_subsys(const struct bus_type *bus) +{ + struct subsys_private *sp = NULL; + struct kobject *kobj; + + if (!bus) + return NULL; + + spin_lock(&bus_kset->list_lock); + + if (list_empty(&bus_kset->list)) + goto done; + + list_for_each_entry(kobj, &bus_kset->list, entry) { + struct kset *kset = container_of(kobj, struct kset, kobj); + + sp = container_of_const(kset, struct subsys_private, subsys); + if (sp->bus == bus) + goto done; + } + sp = NULL; +done: + sp = subsys_get(sp); + spin_unlock(&bus_kset->list_lock); + return sp; +} + static struct bus_type *bus_get(struct bus_type *bus) { - if (bus) { - kset_get(&bus->p->subsys); + struct subsys_private *sp = bus_to_subsys(bus); + + if (sp) return bus; - } return NULL; } -static void bus_put(struct bus_type *bus) +static void bus_put(const struct bus_type *bus) { - if (bus) - kset_put(&bus->p->subsys); + struct subsys_private *sp = bus_to_subsys(bus); + + /* two puts are required as the call to bus_to_subsys incremented it again */ + subsys_put(sp); + subsys_put(sp); } static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr, @@ -177,8 +224,6 @@ static const struct kset_uevent_ops bus_uevent_ops = { .filter = bus_uevent_filter, }; -static struct kset *bus_kset; - /* Manually detach a device from its associated driver. */ static ssize_t unbind_store(struct device_driver *drv, const char *buf, size_t count) |