From 393c3714081a53795bbff0e985d24146def6f57f Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Thu, 18 Nov 2021 15:00:08 -0800 Subject: kernfs: switch global kernfs_rwsem lock to per-fs lock The kernfs implementation has big lock granularity(kernfs_rwsem) so every kernfs-based(e.g., sysfs, cgroup) fs are able to compete the lock. It makes trouble for some cases to wait the global lock for a long time even though they are totally independent contexts each other. A general example is process A goes under direct reclaim with holding the lock when it accessed the file in sysfs and process B is waiting the lock with exclusive mode and then process C is waiting the lock until process B could finish the job after it gets the lock from process A. This patch switches the global kernfs_rwsem to per-fs lock, which put the rwsem into kernfs_root. Suggested-by: Tejun Heo Acked-by: Tejun Heo Signed-off-by: Minchan Kim Link: https://lore.kernel.org/r/20211118230008.2679780-1-minchan@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 3ccce6f24548..9f650986a81b 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -16,6 +16,7 @@ #include #include #include +#include struct file; struct dentry; @@ -197,6 +198,7 @@ struct kernfs_root { struct list_head supers; wait_queue_head_t deactivate_waitq; + struct rw_semaphore kernfs_rwsem; }; struct kernfs_open_file { -- cgit v1.2.3 From a6914afcdf0e3fb853fce0e0c04710be7427b62f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 10 Nov 2021 12:31:28 +0200 Subject: kobject: Replace kernel.h with the necessary inclusions When kernel.h is used in the headers it adds a lot into dependency hell, especially when there are circular dependencies are involved. Replace kernel.h inclusion with the list of what is really being used. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211110103128.59888-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- include/linux/kobject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/kobject.h b/include/linux/kobject.h index efd56f990a46..c740062b4b1a 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -19,10 +19,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include -- cgit v1.2.3 From 2c4dcd7fd57b20a21b65da04d89c38a7217d79cf Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 29 Nov 2021 14:03:07 +0100 Subject: topology/sysfs: export die attributes only if an architectures has support The die_id and die_cpus topology sysfs attributes have been added with commit 0e344d8c709f ("cpu/topology: Export die_id") and commit 2e4c54dac7b3 ("topology: Create core_cpus and die_cpus sysfs attributes"). While they are currently only used and useful for x86 they are still present with bogus default values for all architectures. Instead of enforcing such new sysfs attributes to all architectures, make them only optional visible if an architecture opts in by defining both the topology_die_id and topology_die_cpumask attributes. This is similar to what was done when the book and drawer topology levels were introduced: avoid useless and therefore confusing sysfs attributes for architectures which cannot make use of them. This should not break any existing applications, since this is a rather new interface and applications should be able to handle also older kernel versions without such attributes - besides that they contain only useful information for x86. Acked-by: Peter Zijlstra (Intel) Signed-off-by: Heiko Carstens Link: https://lore.kernel.org/r/20211129130309.3256168-2-hca@linux.ibm.com Signed-off-by: Greg Kroah-Hartman --- Documentation/admin-guide/cputopology.rst | 3 +++ drivers/base/topology.c | 8 ++++++++ include/linux/topology.h | 4 ++++ 3 files changed, 15 insertions(+) (limited to 'include/linux') diff --git a/Documentation/admin-guide/cputopology.rst b/Documentation/admin-guide/cputopology.rst index 6b62e182baf4..c68d07533c45 100644 --- a/Documentation/admin-guide/cputopology.rst +++ b/Documentation/admin-guide/cputopology.rst @@ -11,6 +11,9 @@ Architecture-neutral, drivers/base/topology.c, exports these attributes. However, the book and drawer related sysfs files will only be created if CONFIG_SCHED_BOOK and CONFIG_SCHED_DRAWER are selected, respectively. +The die hierarchy related sysfs files will only be created if an architecture +provides the related macros as described below. + CONFIG_SCHED_BOOK and CONFIG_SCHED_DRAWER are currently only used on s390, where they reflect the cpu and cache hierarchy. diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 8f2b641d0b8c..f079a55793ec 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -45,8 +45,10 @@ static ssize_t name##_list_read(struct file *file, struct kobject *kobj, \ define_id_show_func(physical_package_id); static DEVICE_ATTR_RO(physical_package_id); +#ifdef TOPOLOGY_DIE_SYSFS define_id_show_func(die_id); static DEVICE_ATTR_RO(die_id); +#endif define_id_show_func(cluster_id); static DEVICE_ATTR_RO(cluster_id); @@ -70,9 +72,11 @@ define_siblings_read_func(cluster_cpus, cluster_cpumask); static BIN_ATTR_RO(cluster_cpus, 0); static BIN_ATTR_RO(cluster_cpus_list, 0); +#ifdef TOPOLOGY_DIE_SYSFS define_siblings_read_func(die_cpus, die_cpumask); static BIN_ATTR_RO(die_cpus, 0); static BIN_ATTR_RO(die_cpus_list, 0); +#endif define_siblings_read_func(package_cpus, core_cpumask); static BIN_ATTR_RO(package_cpus, 0); @@ -103,8 +107,10 @@ static struct bin_attribute *bin_attrs[] = { &bin_attr_core_siblings_list, &bin_attr_cluster_cpus, &bin_attr_cluster_cpus_list, +#ifdef TOPOLOGY_DIE_SYSFS &bin_attr_die_cpus, &bin_attr_die_cpus_list, +#endif &bin_attr_package_cpus, &bin_attr_package_cpus_list, #ifdef CONFIG_SCHED_BOOK @@ -120,7 +126,9 @@ static struct bin_attribute *bin_attrs[] = { static struct attribute *default_attrs[] = { &dev_attr_physical_package_id.attr, +#ifdef TOPOLOGY_DIE_SYSFS &dev_attr_die_id.attr, +#endif &dev_attr_cluster_id.attr, &dev_attr_core_id.attr, #ifdef CONFIG_SCHED_BOOK diff --git a/include/linux/topology.h b/include/linux/topology.h index 0b3704ad13c8..8d1bdae76230 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -180,6 +180,10 @@ static inline int cpu_to_mem(int cpu) #endif /* [!]CONFIG_HAVE_MEMORYLESS_NODES */ +#if defined(topology_die_id) && defined(topology_die_cpumask) +#define TOPOLOGY_DIE_SYSFS +#endif + #ifndef topology_physical_package_id #define topology_physical_package_id(cpu) ((void)(cpu), -1) #endif -- cgit v1.2.3 From e795707703b32fecdd7467afcc33ff1e92416c05 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 29 Nov 2021 14:03:08 +0100 Subject: topology/sysfs: export cluster attributes only if an architectures has support The cluster_id and cluster_cpus topology sysfs attributes have been added with commit c5e22feffdd7 ("topology: Represent clusters of CPUs within a die"). They are currently only used for x86, arm64, and riscv (via generic arch topology), however they are still present with bogus default values for all other architectures. Instead of enforcing such new sysfs attributes to all architectures, make them only optional visible if an architecture opts in by defining both the topology_cluster_id and topology_cluster_cpumask attributes. This is similar to what was done when the book and drawer topology levels were introduced: avoid useless and therefore confusing sysfs attributes for architectures which cannot make use of them. This should not break any existing applications, since this is a new interface introduced with the v5.16 merge window. Acked-by: Peter Zijlstra (Intel) Signed-off-by: Heiko Carstens Link: https://lore.kernel.org/r/20211129130309.3256168-3-hca@linux.ibm.com Signed-off-by: Greg Kroah-Hartman --- Documentation/admin-guide/cputopology.rst | 4 ++-- drivers/base/topology.c | 8 ++++++++ include/linux/topology.h | 3 +++ 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/Documentation/admin-guide/cputopology.rst b/Documentation/admin-guide/cputopology.rst index c68d07533c45..ad2238b41439 100644 --- a/Documentation/admin-guide/cputopology.rst +++ b/Documentation/admin-guide/cputopology.rst @@ -11,8 +11,8 @@ Architecture-neutral, drivers/base/topology.c, exports these attributes. However, the book and drawer related sysfs files will only be created if CONFIG_SCHED_BOOK and CONFIG_SCHED_DRAWER are selected, respectively. -The die hierarchy related sysfs files will only be created if an architecture -provides the related macros as described below. +The die and cluster hierarchy related sysfs files will only be created if an +architecture provides the related macros as described below. CONFIG_SCHED_BOOK and CONFIG_SCHED_DRAWER are currently only used on s390, where they reflect the cpu and cache hierarchy. diff --git a/drivers/base/topology.c b/drivers/base/topology.c index f079a55793ec..9d049724e4b4 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -50,8 +50,10 @@ define_id_show_func(die_id); static DEVICE_ATTR_RO(die_id); #endif +#ifdef TOPOLOGY_CLUSTER_SYSFS define_id_show_func(cluster_id); static DEVICE_ATTR_RO(cluster_id); +#endif define_id_show_func(core_id); static DEVICE_ATTR_RO(core_id); @@ -68,9 +70,11 @@ define_siblings_read_func(core_siblings, core_cpumask); static BIN_ATTR_RO(core_siblings, 0); static BIN_ATTR_RO(core_siblings_list, 0); +#ifdef TOPOLOGY_CLUSTER_SYSFS define_siblings_read_func(cluster_cpus, cluster_cpumask); static BIN_ATTR_RO(cluster_cpus, 0); static BIN_ATTR_RO(cluster_cpus_list, 0); +#endif #ifdef TOPOLOGY_DIE_SYSFS define_siblings_read_func(die_cpus, die_cpumask); @@ -105,8 +109,10 @@ static struct bin_attribute *bin_attrs[] = { &bin_attr_thread_siblings_list, &bin_attr_core_siblings, &bin_attr_core_siblings_list, +#ifdef TOPOLOGY_CLUSTER_SYSFS &bin_attr_cluster_cpus, &bin_attr_cluster_cpus_list, +#endif #ifdef TOPOLOGY_DIE_SYSFS &bin_attr_die_cpus, &bin_attr_die_cpus_list, @@ -129,7 +135,9 @@ static struct attribute *default_attrs[] = { #ifdef TOPOLOGY_DIE_SYSFS &dev_attr_die_id.attr, #endif +#ifdef TOPOLOGY_CLUSTER_SYSFS &dev_attr_cluster_id.attr, +#endif &dev_attr_core_id.attr, #ifdef CONFIG_SCHED_BOOK &dev_attr_book_id.attr, diff --git a/include/linux/topology.h b/include/linux/topology.h index 8d1bdae76230..d52be69037db 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -183,6 +183,9 @@ static inline int cpu_to_mem(int cpu) #if defined(topology_die_id) && defined(topology_die_cpumask) #define TOPOLOGY_DIE_SYSFS #endif +#if defined(topology_cluster_id) && defined(topology_cluster_cpumask) +#define TOPOLOGY_CLUSTER_SYSFS +#endif #ifndef topology_physical_package_id #define topology_physical_package_id(cpu) ((void)(cpu), -1) -- cgit v1.2.3 From f1045056c726440469d89d23c13734bcd6c0d15b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 29 Nov 2021 14:03:09 +0100 Subject: topology/sysfs: rework book and drawer topology ifdefery Provide default defines for the topology_book_[id|cpumask] and topology_drawer_[id|cpumask] macros just like for each other topology level. This way all topology levels are handled in a similar way. Still the the book and drawer levels are only used on s390, and also the sysfs attributes are only created on s390. However other architectures may opt in if wanted. Acked-by: Peter Zijlstra (Intel) Signed-off-by: Heiko Carstens Link: https://lore.kernel.org/r/20211129130309.3256168-4-hca@linux.ibm.com Signed-off-by: Greg Kroah-Hartman --- Documentation/admin-guide/cputopology.rst | 36 +++++++++++++------------------ drivers/base/topology.c | 12 +++++------ include/linux/topology.h | 18 ++++++++++++++++ 3 files changed, 39 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/Documentation/admin-guide/cputopology.rst b/Documentation/admin-guide/cputopology.rst index ad2238b41439..677ba1c2c820 100644 --- a/Documentation/admin-guide/cputopology.rst +++ b/Documentation/admin-guide/cputopology.rst @@ -8,14 +8,9 @@ to /proc/cpuinfo output of some architectures. They reside in Documentation/ABI/stable/sysfs-devices-system-cpu. Architecture-neutral, drivers/base/topology.c, exports these attributes. -However, the book and drawer related sysfs files will only be created if -CONFIG_SCHED_BOOK and CONFIG_SCHED_DRAWER are selected, respectively. - -The die and cluster hierarchy related sysfs files will only be created if an -architecture provides the related macros as described below. - -CONFIG_SCHED_BOOK and CONFIG_SCHED_DRAWER are currently only used on s390, -where they reflect the cpu and cache hierarchy. +However the die, cluster, book, and drawer hierarchy related sysfs files will +only be created if an architecture provides the related macros as described +below. For an architecture to support this feature, it must define some of these macros in include/asm-XXX/topology.h:: @@ -42,19 +37,18 @@ To be consistent on all architectures, include/linux/topology.h provides default definitions for any of the above macros that are not defined by include/asm-XXX/topology.h: -1) topology_physical_package_id: -1 -2) topology_die_id: -1 -3) topology_cluster_id: -1 -4) topology_core_id: 0 -5) topology_sibling_cpumask: just the given CPU -6) topology_core_cpumask: just the given CPU -7) topology_cluster_cpumask: just the given CPU -8) topology_die_cpumask: just the given CPU - -For architectures that don't support books (CONFIG_SCHED_BOOK) there are no -default definitions for topology_book_id() and topology_book_cpumask(). -For architectures that don't support drawers (CONFIG_SCHED_DRAWER) there are -no default definitions for topology_drawer_id() and topology_drawer_cpumask(). + 1) topology_physical_package_id: -1 + 2) topology_die_id: -1 + 3) topology_cluster_id: -1 + 4) topology_core_id: 0 + 5) topology_book_id: -1 + 6) topology_drawer_id: -1 + 7) topology_sibling_cpumask: just the given CPU + 8) topology_core_cpumask: just the given CPU + 9) topology_cluster_cpumask: just the given CPU +10) topology_die_cpumask: just the given CPU +11) topology_book_cpumask: just the given CPU +12) topology_drawer_cpumask: just the given CPU Additionally, CPU topology information is provided under /sys/devices/system/cpu and includes these files. The internal diff --git a/drivers/base/topology.c b/drivers/base/topology.c index 9d049724e4b4..fc24e89f9592 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -86,7 +86,7 @@ define_siblings_read_func(package_cpus, core_cpumask); static BIN_ATTR_RO(package_cpus, 0); static BIN_ATTR_RO(package_cpus_list, 0); -#ifdef CONFIG_SCHED_BOOK +#ifdef TOPOLOGY_BOOK_SYSFS define_id_show_func(book_id); static DEVICE_ATTR_RO(book_id); define_siblings_read_func(book_siblings, book_cpumask); @@ -94,7 +94,7 @@ static BIN_ATTR_RO(book_siblings, 0); static BIN_ATTR_RO(book_siblings_list, 0); #endif -#ifdef CONFIG_SCHED_DRAWER +#ifdef TOPOLOGY_DRAWER_SYSFS define_id_show_func(drawer_id); static DEVICE_ATTR_RO(drawer_id); define_siblings_read_func(drawer_siblings, drawer_cpumask); @@ -119,11 +119,11 @@ static struct bin_attribute *bin_attrs[] = { #endif &bin_attr_package_cpus, &bin_attr_package_cpus_list, -#ifdef CONFIG_SCHED_BOOK +#ifdef TOPOLOGY_BOOK_SYSFS &bin_attr_book_siblings, &bin_attr_book_siblings_list, #endif -#ifdef CONFIG_SCHED_DRAWER +#ifdef TOPOLOGY_DRAWER_SYSFS &bin_attr_drawer_siblings, &bin_attr_drawer_siblings_list, #endif @@ -139,10 +139,10 @@ static struct attribute *default_attrs[] = { &dev_attr_cluster_id.attr, #endif &dev_attr_core_id.attr, -#ifdef CONFIG_SCHED_BOOK +#ifdef TOPOLOGY_BOOK_SYSFS &dev_attr_book_id.attr, #endif -#ifdef CONFIG_SCHED_DRAWER +#ifdef TOPOLOGY_DRAWER_SYSFS &dev_attr_drawer_id.attr, #endif NULL diff --git a/include/linux/topology.h b/include/linux/topology.h index d52be69037db..a6e201758ae9 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -186,6 +186,12 @@ static inline int cpu_to_mem(int cpu) #if defined(topology_cluster_id) && defined(topology_cluster_cpumask) #define TOPOLOGY_CLUSTER_SYSFS #endif +#if defined(topology_book_id) && defined(topology_book_cpumask) +#define TOPOLOGY_BOOK_SYSFS +#endif +#if defined(topology_drawer_id) && defined(topology_drawer_cpumask) +#define TOPOLOGY_DRAWER_SYSFS +#endif #ifndef topology_physical_package_id #define topology_physical_package_id(cpu) ((void)(cpu), -1) @@ -199,6 +205,12 @@ static inline int cpu_to_mem(int cpu) #ifndef topology_core_id #define topology_core_id(cpu) ((void)(cpu), 0) #endif +#ifndef topology_book_id +#define topology_book_id(cpu) ((void)(cpu), -1) +#endif +#ifndef topology_drawer_id +#define topology_drawer_id(cpu) ((void)(cpu), -1) +#endif #ifndef topology_sibling_cpumask #define topology_sibling_cpumask(cpu) cpumask_of(cpu) #endif @@ -211,6 +223,12 @@ static inline int cpu_to_mem(int cpu) #ifndef topology_die_cpumask #define topology_die_cpumask(cpu) cpumask_of(cpu) #endif +#ifndef topology_book_cpumask +#define topology_book_cpumask(cpu) cpumask_of(cpu) +#endif +#ifndef topology_drawer_cpumask +#define topology_drawer_cpumask(cpu) cpumask_of(cpu) +#endif #if defined(CONFIG_SCHED_SMT) && !defined(cpu_smt_mask) static inline const struct cpumask *cpu_smt_mask(int cpu) -- cgit v1.2.3 From 14866a7db8da1f61fb6135c461b733694eea9580 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Wed, 1 Dec 2021 20:43:03 -0800 Subject: Documentation/auxiliary_bus: Add example code for module_auxiliary_driver() Add an example code snipit to the module_auxiliary_driver() documentation which is consistent with the other example code in the elsewhere in the documentation. Signed-off-by: Ira Weiny Link: https://lore.kernel.org/r/20211202044305.4006853-6-ira.weiny@intel.com Signed-off-by: Greg Kroah-Hartman --- include/linux/auxiliary_bus.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux') diff --git a/include/linux/auxiliary_bus.h b/include/linux/auxiliary_bus.h index fc51d45f106b..605b27aab693 100644 --- a/include/linux/auxiliary_bus.h +++ b/include/linux/auxiliary_bus.h @@ -66,6 +66,10 @@ void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv); * Helper macro for auxiliary drivers which do not do anything special in * module init/exit. This eliminates a lot of boilerplate. Each module may only * use this macro once, and calling it replaces module_init() and module_exit() + * + * .. code-block:: c + * + * module_auxiliary_driver(my_drv); */ #define module_auxiliary_driver(__auxiliary_driver) \ module_driver(__auxiliary_driver, auxiliary_driver_register, auxiliary_driver_unregister) -- cgit v1.2.3 From e1b5186810cc7d4ec60447032636b8e6772dbbc6 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Wed, 1 Dec 2021 20:43:05 -0800 Subject: Documentation/auxiliary_bus: Move the text into the code The code and documentation are more difficult to maintain when kept separately. This is further compounded when the standard structure documentation infrastructure is not used. Move the documentation into the code, use the standard documentation infrastructure, add current documented functions, and reference the text in the rst file. Suggested-by: Greg Kroah-Hartman Signed-off-by: Ira Weiny Link: https://lore.kernel.org/r/20211202044305.4006853-8-ira.weiny@intel.com Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/auxiliary_bus.rst | 298 ++--------------------------- drivers/base/auxiliary.c | 141 ++++++++++++++ include/linux/auxiliary_bus.h | 160 ++++++++++++++++ 3 files changed, 318 insertions(+), 281 deletions(-) (limited to 'include/linux') diff --git a/Documentation/driver-api/auxiliary_bus.rst b/Documentation/driver-api/auxiliary_bus.rst index 3786e4664a1e..cec84908fbc0 100644 --- a/Documentation/driver-api/auxiliary_bus.rst +++ b/Documentation/driver-api/auxiliary_bus.rst @@ -6,309 +6,45 @@ Auxiliary Bus ============= -In some subsystems, the functionality of the core device (PCI/ACPI/other) is -too complex for a single device to be managed by a monolithic driver -(e.g. Sound Open Firmware), multiple devices might implement a common -intersection of functionality (e.g. NICs + RDMA), or a driver may want to -export an interface for another subsystem to drive (e.g. SIOV Physical Function -export Virtual Function management). A split of the functionality into child- -devices representing sub-domains of functionality makes it possible to -compartmentalize, layer, and distribute domain-specific concerns via a Linux -device-driver model. - -An example for this kind of requirement is the audio subsystem where a single -IP is handling multiple entities such as HDMI, Soundwire, local devices such as -mics/speakers etc. The split for the core's functionality can be arbitrary or -be defined by the DSP firmware topology and include hooks for test/debug. This -allows for the audio core device to be minimal and focused on hardware-specific -control and communication. - -Each auxiliary_device represents a part of its parent functionality. The -generic behavior can be extended and specialized as needed by encapsulating an -auxiliary_device within other domain-specific structures and the use of .ops -callbacks. Devices on the auxiliary bus do not share any structures and the use -of a communication channel with the parent is domain-specific. - -Note that ops are intended as a way to augment instance behavior within a class -of auxiliary devices, it is not the mechanism for exporting common -infrastructure from the parent. Consider EXPORT_SYMBOL_NS() to convey -infrastructure from the parent module to the auxiliary module(s). - +.. kernel-doc:: drivers/base/auxiliary.c + :doc: PURPOSE When Should the Auxiliary Bus Be Used ===================================== -The auxiliary bus is to be used when a driver and one or more kernel modules, -who share a common header file with the driver, need a mechanism to connect and -provide access to a shared object allocated by the auxiliary_device's -registering driver. The registering driver for the auxiliary_device(s) and the -kernel module(s) registering auxiliary_drivers can be from the same subsystem, -or from multiple subsystems. - -The emphasis here is on a common generic interface that keeps subsystem -customization out of the bus infrastructure. - -One example is a PCI network device that is RDMA-capable and exports a child -device to be driven by an auxiliary_driver in the RDMA subsystem. The PCI -driver allocates and registers an auxiliary_device for each physical -function on the NIC. The RDMA driver registers an auxiliary_driver that claims -each of these auxiliary_devices. This conveys data/ops published by the parent -PCI device/driver to the RDMA auxiliary_driver. - -Another use case is for the PCI device to be split out into multiple sub -functions. For each sub function an auxiliary_device is created. A PCI sub -function driver binds to such devices that creates its own one or more class -devices. A PCI sub function auxiliary device is likely to be contained in a -struct with additional attributes such as user defined sub function number and -optional attributes such as resources and a link to the parent device. These -attributes could be used by systemd/udev; and hence should be initialized -before a driver binds to an auxiliary_device. +.. kernel-doc:: drivers/base/auxiliary.c + :doc: USAGE -A key requirement for utilizing the auxiliary bus is that there is no -dependency on a physical bus, device, register accesses or regmap support. -These individual devices split from the core cannot live on the platform bus as -they are not physical devices that are controlled by DT/ACPI. The same -argument applies for not using MFD in this scenario as MFD relies on individual -function devices being physical devices. Auxiliary Device Creation ========================= -An auxiliary_device represents a part of its parent device's functionality. It -is given a name that, combined with the registering drivers KBUILD_MODNAME, -creates a match_name that is used for driver binding, and an id that combined -with the match_name provide a unique name to register with the bus subsystem. -For example, a driver registering an auxiliary device is named 'foo_mod.ko' and -the subdevice is named 'foo_dev'. The match name is therefore -'foo_mod.foo_dev'. - -.. code-block:: c - - struct auxiliary_device { - struct device dev; - const char *name; - u32 id; - }; - -Registering an auxiliary_device is a three-step process. - -First, a 'struct auxiliary_device' needs to be defined or allocated for each -sub-device desired. The name, id, dev.release, and dev.parent fields of this -structure must be filled in as follows. - -The 'name' field is to be given a name that is recognized by the auxiliary -driver. If two auxiliary_devices with the same match_name, eg -"foo_mod.foo_dev", are registered onto the bus, they must have unique id -values (e.g. "x" and "y") so that the registered devices names are "foo_mod.foo_dev.x" -and "foo_mod.foo_dev.y". If match_name + id are not unique, then the device_add fails -and generates an error message. - -The auxiliary_device.dev.type.release or auxiliary_device.dev.release must be -populated with a non-NULL pointer to successfully register the -auxiliary_device. This release call is where resources associated with the -auxiliary device must be free'ed. Because once the device is placed on the bus -the parent driver can not tell what other code may have a reference to this -data. - -The auxiliary_device.dev.parent should be set. Typically to the registering -drivers device. - -Second, call auxiliary_device_init(), which checks several aspects of the -auxiliary_device struct and performs a device_initialize(). After this step -completes, any error state must have a call to auxiliary_device_uninit() in its -resolution path. - -The third and final step in registering an auxiliary_device is to perform a -call to auxiliary_device_add(), which sets the name of the device and adds the -device to the bus. - -.. code-block:: c - - #define MY_DEVICE_NAME "foo_dev" - - ... - - struct auxiliary_device *my_aux_dev = my_aux_dev_alloc(xxx); - - /* Step 1: */ - my_aux_dev->name = MY_DEVICE_NAME; - my_aux_dev->id = my_unique_id_alloc(xxx); - my_aux_dev->dev.release = my_aux_dev_release; - my_aux_dev->dev.parent = my_dev; - - /* Step 2: */ - if (auxiliary_device_init(my_aux_dev)) - goto fail; - - /* Step 3: */ - if (auxiliary_device_add(my_aux_dev)) { - auxiliary_device_uninit(my_aux_dev); - goto fail; - } - - ... - - -Unregistering an auxiliary_device is a two-step process to mirror the register -process. First call auxiliary_device_delete(), then call -auxiliary_device_uninit(). - - -.. code-block:: c - - auxiliary_device_delete(my_dev->my_aux_dev); - auxiliary_device_uninit(my_dev->my_aux_dev); +.. kernel-doc:: include/linux/auxiliary_bus.h + :identifiers: auxiliary_device +.. kernel-doc:: drivers/base/auxiliary.c + :identifiers: auxiliary_device_init __auxiliary_device_add + auxiliary_find_device Auxiliary Device Memory Model and Lifespan ------------------------------------------ -The registering driver is the entity that allocates memory for the -auxiliary_device and registers it on the auxiliary bus. It is important to note -that, as opposed to the platform bus, the registering driver is wholly -responsible for the management of the memory used for the device object. - -To be clear the memory for the auxiliary_device is freed in the release() -callback defined by the registering driver. The registering driver should only -call auxiliary_device_delete() and then auxiliary_device_uninit() when it is -done with the device. The release() function is then automatically called if -and when other code releases their reference to the devices. - -A parent object, defined in the shared header file, contains the -auxiliary_device. It also contains a pointer to the shared object(s), which -also is defined in the shared header. Both the parent object and the shared -object(s) are allocated by the registering driver. This layout allows the -auxiliary_driver's registering module to perform a container_of() call to go -from the pointer to the auxiliary_device, that is passed during the call to the -auxiliary_driver's probe function, up to the parent object, and then have -access to the shared object(s). - -The memory for the shared object(s) must have a lifespan equal to, or greater -than, the lifespan of the memory for the auxiliary_device. The -auxiliary_driver should only consider that the shared object is valid as long -as the auxiliary_device is still registered on the auxiliary bus. It is up to -the registering driver to manage (e.g. free or keep available) the memory for -the shared object beyond the life of the auxiliary_device. - -The registering driver must unregister all auxiliary devices before its own -driver.remove() is completed. An easy way to ensure this is to use the -devm_add_action_or_reset() call to register a function against the parent device -which unregisters the auxiliary device object(s). - -Finally, any operations which operate on the auxiliary devices must continue to -function (if only to return an error) after the registering driver unregisters -the auxiliary device. +.. kernel-doc:: include/linux/auxiliary_bus.h + :doc: DEVICE_LIFESPAN Auxiliary Drivers ================= -Auxiliary drivers follow the standard driver model convention, where -discovery/enumeration is handled by the core, and drivers -provide probe() and remove() methods. They support power management -and shutdown notifications using the standard conventions. - -.. code-block:: c - - struct auxiliary_driver { - int (*probe)(struct auxiliary_device *, - const struct auxiliary_device_id *id); - void (*remove)(struct auxiliary_device *); - void (*shutdown)(struct auxiliary_device *); - int (*suspend)(struct auxiliary_device *, pm_message_t); - int (*resume)(struct auxiliary_device *); - struct device_driver driver; - const struct auxiliary_device_id *id_table; - }; - -Auxiliary drivers register themselves with the bus by calling -auxiliary_driver_register(). The id_table contains the match_names of auxiliary -devices that a driver can bind with. - -.. code-block:: c - - static const struct auxiliary_device_id my_auxiliary_id_table[] = { - { .name = "foo_mod.foo_dev" }, - {}, - }; - - MODULE_DEVICE_TABLE(auxiliary, my_auxiliary_id_table); - - struct auxiliary_driver my_drv = { - .name = "myauxiliarydrv", - .id_table = my_auxiliary_id_table, - .probe = my_drv_probe, - .remove = my_drv_remove - }; +.. kernel-doc:: include/linux/auxiliary_bus.h + :identifiers: auxiliary_driver module_auxiliary_driver +.. kernel-doc:: drivers/base/auxiliary.c + :identifiers: __auxiliary_driver_register auxiliary_driver_unregister Example Usage ============= -Auxiliary devices are created and registered by a subsystem-level core device -that needs to break up its functionality into smaller fragments. One way to -extend the scope of an auxiliary_device is to encapsulate it within a domain- -pecific structure defined by the parent device. This structure contains the -auxiliary_device and any associated shared data/callbacks needed to establish -the connection with the parent. - -An example is: - -.. code-block:: c - - struct foo { - struct auxiliary_device auxdev; - void (*connect)(struct auxiliary_device *auxdev); - void (*disconnect)(struct auxiliary_device *auxdev); - void *data; - }; - -The parent device then registers the auxiliary_device by calling -auxiliary_device_init(), and then auxiliary_device_add(), with the pointer to -the auxdev member of the above structure. The parent provides a name for the -auxiliary_device that, combined with the parent's KBUILD_MODNAME, creates a -match_name that is be used for matching and binding with a driver. - -Whenever an auxiliary_driver is registered, based on the match_name, the -auxiliary_driver's probe() is invoked for the matching devices. The -auxiliary_driver can also be encapsulated inside custom drivers that make the -core device's functionality extensible by adding additional domain-specific ops -as follows: - -.. code-block:: c - - struct my_ops { - void (*send)(struct auxiliary_device *auxdev); - void (*receive)(struct auxiliary_device *auxdev); - }; - - - struct my_driver { - struct auxiliary_driver auxiliary_drv; - const struct my_ops ops; - }; - -An example of this type of usage is: - -.. code-block:: c - - const struct auxiliary_device_id my_auxiliary_id_table[] = { - { .name = "foo_mod.foo_dev" }, - { }, - }; - - const struct my_ops my_custom_ops = { - .send = my_tx, - .receive = my_rx, - }; +.. kernel-doc:: drivers/base/auxiliary.c + :doc: EXAMPLE - const struct my_driver my_drv = { - .auxiliary_drv = { - .name = "myauxiliarydrv", - .id_table = my_auxiliary_id_table, - .probe = my_probe, - .remove = my_remove, - .shutdown = my_shutdown, - }, - .ops = my_custom_ops, - }; diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c index ab5315681a42..8c5e65930617 100644 --- a/drivers/base/auxiliary.c +++ b/drivers/base/auxiliary.c @@ -17,6 +17,147 @@ #include #include "base.h" +/** + * DOC: PURPOSE + * + * In some subsystems, the functionality of the core device (PCI/ACPI/other) is + * too complex for a single device to be managed by a monolithic driver (e.g. + * Sound Open Firmware), multiple devices might implement a common intersection + * of functionality (e.g. NICs + RDMA), or a driver may want to export an + * interface for another subsystem to drive (e.g. SIOV Physical Function export + * Virtual Function management). A split of the functionality into child- + * devices representing sub-domains of functionality makes it possible to + * compartmentalize, layer, and distribute domain-specific concerns via a Linux + * device-driver model. + * + * An example for this kind of requirement is the audio subsystem where a + * single IP is handling multiple entities such as HDMI, Soundwire, local + * devices such as mics/speakers etc. The split for the core's functionality + * can be arbitrary or be defined by the DSP firmware topology and include + * hooks for test/debug. This allows for the audio core device to be minimal + * and focused on hardware-specific control and communication. + * + * Each auxiliary_device represents a part of its parent functionality. The + * generic behavior can be extended and specialized as needed by encapsulating + * an auxiliary_device within other domain-specific structures and the use of + * .ops callbacks. Devices on the auxiliary bus do not share any structures and + * the use of a communication channel with the parent is domain-specific. + * + * Note that ops are intended as a way to augment instance behavior within a + * class of auxiliary devices, it is not the mechanism for exporting common + * infrastructure from the parent. Consider EXPORT_SYMBOL_NS() to convey + * infrastructure from the parent module to the auxiliary module(s). + */ + +/** + * DOC: USAGE + * + * The auxiliary bus is to be used when a driver and one or more kernel + * modules, who share a common header file with the driver, need a mechanism to + * connect and provide access to a shared object allocated by the + * auxiliary_device's registering driver. The registering driver for the + * auxiliary_device(s) and the kernel module(s) registering auxiliary_drivers + * can be from the same subsystem, or from multiple subsystems. + * + * The emphasis here is on a common generic interface that keeps subsystem + * customization out of the bus infrastructure. + * + * One example is a PCI network device that is RDMA-capable and exports a child + * device to be driven by an auxiliary_driver in the RDMA subsystem. The PCI + * driver allocates and registers an auxiliary_device for each physical + * function on the NIC. The RDMA driver registers an auxiliary_driver that + * claims each of these auxiliary_devices. This conveys data/ops published by + * the parent PCI device/driver to the RDMA auxiliary_driver. + * + * Another use case is for the PCI device to be split out into multiple sub + * functions. For each sub function an auxiliary_device is created. A PCI sub + * function driver binds to such devices that creates its own one or more class + * devices. A PCI sub function auxiliary device is likely to be contained in a + * struct with additional attributes such as user defined sub function number + * and optional attributes such as resources and a link to the parent device. + * These attributes could be used by systemd/udev; and hence should be + * initialized before a driver binds to an auxiliary_device. + * + * A key requirement for utilizing the auxiliary bus is that there is no + * dependency on a physical bus, device, register accesses or regmap support. + * These individual devices split from the core cannot live on the platform bus + * as they are not physical devices that are controlled by DT/ACPI. The same + * argument applies for not using MFD in this scenario as MFD relies on + * individual function devices being physical devices. + */ + +/** + * DOC: EXAMPLE + * + * Auxiliary devices are created and registered by a subsystem-level core + * device that needs to break up its functionality into smaller fragments. One + * way to extend the scope of an auxiliary_device is to encapsulate it within a + * domain- pecific structure defined by the parent device. This structure + * contains the auxiliary_device and any associated shared data/callbacks + * needed to establish the connection with the parent. + * + * An example is: + * + * .. code-block:: c + * + * struct foo { + * struct auxiliary_device auxdev; + * void (*connect)(struct auxiliary_device *auxdev); + * void (*disconnect)(struct auxiliary_device *auxdev); + * void *data; + * }; + * + * The parent device then registers the auxiliary_device by calling + * auxiliary_device_init(), and then auxiliary_device_add(), with the pointer + * to the auxdev member of the above structure. The parent provides a name for + * the auxiliary_device that, combined with the parent's KBUILD_MODNAME, + * creates a match_name that is be used for matching and binding with a driver. + * + * Whenever an auxiliary_driver is registered, based on the match_name, the + * auxiliary_driver's probe() is invoked for the matching devices. The + * auxiliary_driver can also be encapsulated inside custom drivers that make + * the core device's functionality extensible by adding additional + * domain-specific ops as follows: + * + * .. code-block:: c + * + * struct my_ops { + * void (*send)(struct auxiliary_device *auxdev); + * void (*receive)(struct auxiliary_device *auxdev); + * }; + * + * + * struct my_driver { + * struct auxiliary_driver auxiliary_drv; + * const struct my_ops ops; + * }; + * + * An example of this type of usage is: + * + * .. code-block:: c + * + * const struct auxiliary_device_id my_auxiliary_id_table[] = { + * { .name = "foo_mod.foo_dev" }, + * { }, + * }; + * + * const struct my_ops my_custom_ops = { + * .send = my_tx, + * .receive = my_rx, + * }; + * + * const struct my_driver my_drv = { + * .auxiliary_drv = { + * .name = "myauxiliarydrv", + * .id_table = my_auxiliary_id_table, + * .probe = my_probe, + * .remove = my_remove, + * .shutdown = my_shutdown, + * }, + * .ops = my_custom_ops, + * }; + */ + static const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id, const struct auxiliary_device *auxdev) { diff --git a/include/linux/auxiliary_bus.h b/include/linux/auxiliary_bus.h index 605b27aab693..e6d8b5c16226 100644 --- a/include/linux/auxiliary_bus.h +++ b/include/linux/auxiliary_bus.h @@ -11,12 +11,172 @@ #include #include +/** + * DOC: DEVICE_LIFESPAN + * + * The registering driver is the entity that allocates memory for the + * auxiliary_device and registers it on the auxiliary bus. It is important to + * note that, as opposed to the platform bus, the registering driver is wholly + * responsible for the management of the memory used for the device object. + * + * To be clear the memory for the auxiliary_device is freed in the release() + * callback defined by the registering driver. The registering driver should + * only call auxiliary_device_delete() and then auxiliary_device_uninit() when + * it is done with the device. The release() function is then automatically + * called if and when other code releases their reference to the devices. + * + * A parent object, defined in the shared header file, contains the + * auxiliary_device. It also contains a pointer to the shared object(s), which + * also is defined in the shared header. Both the parent object and the shared + * object(s) are allocated by the registering driver. This layout allows the + * auxiliary_driver's registering module to perform a container_of() call to go + * from the pointer to the auxiliary_device, that is passed during the call to + * the auxiliary_driver's probe function, up to the parent object, and then + * have access to the shared object(s). + * + * The memory for the shared object(s) must have a lifespan equal to, or + * greater than, the lifespan of the memory for the auxiliary_device. The + * auxiliary_driver should only consider that the shared object is valid as + * long as the auxiliary_device is still registered on the auxiliary bus. It + * is up to the registering driver to manage (e.g. free or keep available) the + * memory for the shared object beyond the life of the auxiliary_device. + * + * The registering driver must unregister all auxiliary devices before its own + * driver.remove() is completed. An easy way to ensure this is to use the + * devm_add_action_or_reset() call to register a function against the parent + * device which unregisters the auxiliary device object(s). + * + * Finally, any operations which operate on the auxiliary devices must continue + * to function (if only to return an error) after the registering driver + * unregisters the auxiliary device. + */ + +/** + * struct auxiliary_device - auxiliary device object. + * @dev: Device, + * The release and parent fields of the device structure must be filled + * in + * @name: Match name found by the auxiliary device driver, + * @id: unique identitier if multiple devices of the same name are exported, + * + * An auxiliary_device represents a part of its parent device's functionality. + * It is given a name that, combined with the registering drivers + * KBUILD_MODNAME, creates a match_name that is used for driver binding, and an + * id that combined with the match_name provide a unique name to register with + * the bus subsystem. For example, a driver registering an auxiliary device is + * named 'foo_mod.ko' and the subdevice is named 'foo_dev'. The match name is + * therefore 'foo_mod.foo_dev'. + * + * Registering an auxiliary_device is a three-step process. + * + * First, a 'struct auxiliary_device' needs to be defined or allocated for each + * sub-device desired. The name, id, dev.release, and dev.parent fields of + * this structure must be filled in as follows. + * + * The 'name' field is to be given a name that is recognized by the auxiliary + * driver. If two auxiliary_devices with the same match_name, eg + * "foo_mod.foo_dev", are registered onto the bus, they must have unique id + * values (e.g. "x" and "y") so that the registered devices names are + * "foo_mod.foo_dev.x" and "foo_mod.foo_dev.y". If match_name + id are not + * unique, then the device_add fails and generates an error message. + * + * The auxiliary_device.dev.type.release or auxiliary_device.dev.release must + * be populated with a non-NULL pointer to successfully register the + * auxiliary_device. This release call is where resources associated with the + * auxiliary device must be free'ed. Because once the device is placed on the + * bus the parent driver can not tell what other code may have a reference to + * this data. + * + * The auxiliary_device.dev.parent should be set. Typically to the registering + * drivers device. + * + * Second, call auxiliary_device_init(), which checks several aspects of the + * auxiliary_device struct and performs a device_initialize(). After this step + * completes, any error state must have a call to auxiliary_device_uninit() in + * its resolution path. + * + * The third and final step in registering an auxiliary_device is to perform a + * call to auxiliary_device_add(), which sets the name of the device and adds + * the device to the bus. + * + * .. code-block:: c + * + * #define MY_DEVICE_NAME "foo_dev" + * + * ... + * + * struct auxiliary_device *my_aux_dev = my_aux_dev_alloc(xxx); + * + * // Step 1: + * my_aux_dev->name = MY_DEVICE_NAME; + * my_aux_dev->id = my_unique_id_alloc(xxx); + * my_aux_dev->dev.release = my_aux_dev_release; + * my_aux_dev->dev.parent = my_dev; + * + * // Step 2: + * if (auxiliary_device_init(my_aux_dev)) + * goto fail; + * + * // Step 3: + * if (auxiliary_device_add(my_aux_dev)) { + * auxiliary_device_uninit(my_aux_dev); + * goto fail; + * } + * + * ... + * + * + * Unregistering an auxiliary_device is a two-step process to mirror the + * register process. First call auxiliary_device_delete(), then call + * auxiliary_device_uninit(). + * + * .. code-block:: c + * + * auxiliary_device_delete(my_dev->my_aux_dev); + * auxiliary_device_uninit(my_dev->my_aux_dev); + */ struct auxiliary_device { struct device dev; const char *name; u32 id; }; +/** + * struct auxiliary_driver - Definition of an auxiliary bus driver + * @probe: Called when a matching device is added to the bus. + * @remove: Called when device is removed from the bus. + * @shutdown: Called at shut-down time to quiesce the device. + * @suspend: Called to put the device to sleep mode. Usually to a power state. + * @resume: Called to bring a device from sleep mode. + * @name: Driver name. + * @driver: Core driver structure. + * @id_table: Table of devices this driver should match on the bus. + * + * Auxiliary drivers follow the standard driver model convention, where + * discovery/enumeration is handled by the core, and drivers provide probe() + * and remove() methods. They support power management and shutdown + * notifications using the standard conventions. + * + * Auxiliary drivers register themselves with the bus by calling + * auxiliary_driver_register(). The id_table contains the match_names of + * auxiliary devices that a driver can bind with. + * + * .. code-block:: c + * + * static const struct auxiliary_device_id my_auxiliary_id_table[] = { + * { .name = "foo_mod.foo_dev" }, + * {}, + * }; + * + * MODULE_DEVICE_TABLE(auxiliary, my_auxiliary_id_table); + * + * struct auxiliary_driver my_drv = { + * .name = "myauxiliarydrv", + * .id_table = my_auxiliary_id_table, + * .probe = my_drv_probe, + * .remove = my_drv_remove + * }; + */ struct auxiliary_driver { int (*probe)(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id); void (*remove)(struct auxiliary_device *auxdev); -- cgit v1.2.3 From 79f1c7304295bbbc611bc53cfd5425b777b3e840 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 9 Dec 2021 14:30:08 +0200 Subject: kernfs: Replace kernel.h with the necessary inclusions When kernel.h is used in the headers it adds a lot into dependency hell, especially when there are circular dependencies are involved. Replace kernel.h inclusion with the list of what is really being used. Acked-by: Tejun Heo Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20211209123008.3391-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 9f650986a81b..861c4f0f8a29 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -6,7 +6,6 @@ #ifndef __LINUX_KERNFS_H #define __LINUX_KERNFS_H -#include #include #include #include @@ -14,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -23,6 +24,7 @@ struct dentry; struct iattr; struct seq_file; struct vm_area_struct; +struct vm_operations_struct; struct super_block; struct file_system_type; struct poll_table_struct; -- cgit v1.2.3 From 365481e42a8a95c55e43e8cc236138718e762e7b Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Tue, 7 Dec 2021 17:50:11 -0800 Subject: driver core: auxiliary bus: Add driver data helpers Adds get/set driver data helpers for auxiliary devices. Reviewed-by: Mark Gross Reviewed-by: Andy Shevchenko Signed-off-by: David E. Box Link: https://lore.kernel.org/r/20211208015015.891275-3-david.e.box@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- include/linux/auxiliary_bus.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include/linux') diff --git a/include/linux/auxiliary_bus.h b/include/linux/auxiliary_bus.h index e6d8b5c16226..de21d9d24a95 100644 --- a/include/linux/auxiliary_bus.h +++ b/include/linux/auxiliary_bus.h @@ -188,6 +188,16 @@ struct auxiliary_driver { const struct auxiliary_device_id *id_table; }; +static inline void *auxiliary_get_drvdata(struct auxiliary_device *auxdev) +{ + return dev_get_drvdata(&auxdev->dev); +} + +static inline void auxiliary_set_drvdata(struct auxiliary_device *auxdev, void *data) +{ + dev_set_drvdata(&auxdev->dev, data); +} + static inline struct auxiliary_device *to_auxiliary_dev(struct device *dev) { return container_of(dev, struct auxiliary_device, dev); -- cgit v1.2.3 From ee6d3dd4ed48ab24b74bab3c3977b8218518247d Mon Sep 17 00:00:00 2001 From: Wedson Almeida Filho Date: Fri, 24 Dec 2021 23:13:45 +0000 Subject: driver core: make kobj_type constant. This way instances of kobj_type (which contain function pointers) can be stored in .rodata, which means that they cannot be [easily/accidentally] modified at runtime. Signed-off-by: Wedson Almeida Filho Link: https://lore.kernel.org/r/20211224231345.777370-1-wedsonaf@google.com Signed-off-by: Greg Kroah-Hartman --- Documentation/core-api/kobject.rst | 4 ++-- drivers/base/bus.c | 2 +- drivers/base/core.c | 2 +- include/linux/kobject.h | 8 ++++---- kernel/params.c | 2 +- lib/kobject.c | 8 ++++---- 6 files changed, 13 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/Documentation/core-api/kobject.rst b/Documentation/core-api/kobject.rst index 2739f8b72575..d3b5bf9f643a 100644 --- a/Documentation/core-api/kobject.rst +++ b/Documentation/core-api/kobject.rst @@ -118,7 +118,7 @@ Initialization of kobjects Code which creates a kobject must, of course, initialize that object. Some of the internal fields are setup with a (mandatory) call to kobject_init():: - void kobject_init(struct kobject *kobj, struct kobj_type *ktype); + void kobject_init(struct kobject *kobj, const struct kobj_type *ktype); The ktype is required for a kobject to be created properly, as every kobject must have an associated kobj_type. After calling kobject_init(), to @@ -156,7 +156,7 @@ kobject_name():: There is a helper function to both initialize and add the kobject to the kernel at the same time, called surprisingly enough kobject_init_and_add():: - int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, + int kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...); The arguments are the same as the individual kobject_init() and diff --git a/drivers/base/bus.c b/drivers/base/bus.c index bdc98c5713d5..a64454f5f8c0 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -165,7 +165,7 @@ static struct kobj_type bus_ktype = { static int bus_uevent_filter(struct kset *kset, struct kobject *kobj) { - struct kobj_type *ktype = get_ktype(kobj); + const struct kobj_type *ktype = get_ktype(kobj); if (ktype == &bus_ktype) return 1; diff --git a/drivers/base/core.c b/drivers/base/core.c index fd034d742447..d712ea11066b 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -2263,7 +2263,7 @@ static struct kobj_type device_ktype = { static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) { - struct kobj_type *ktype = get_ktype(kobj); + const struct kobj_type *ktype = get_ktype(kobj); if (ktype == &device_ktype) { struct device *dev = kobj_to_dev(kobj); diff --git a/include/linux/kobject.h b/include/linux/kobject.h index c740062b4b1a..683172b2e094 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -66,7 +66,7 @@ struct kobject { struct list_head entry; struct kobject *parent; struct kset *kset; - struct kobj_type *ktype; + const struct kobj_type *ktype; struct kernfs_node *sd; /* sysfs directory entry */ struct kref kref; #ifdef CONFIG_DEBUG_KOBJECT_RELEASE @@ -90,13 +90,13 @@ static inline const char *kobject_name(const struct kobject *kobj) return kobj->name; } -extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype); +extern void kobject_init(struct kobject *kobj, const struct kobj_type *ktype); extern __printf(3, 4) __must_check int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...); extern __printf(4, 5) __must_check int kobject_init_and_add(struct kobject *kobj, - struct kobj_type *ktype, struct kobject *parent, + const struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...); extern void kobject_del(struct kobject *kobj); @@ -217,7 +217,7 @@ static inline void kset_put(struct kset *k) kobject_put(&k->kobj); } -static inline struct kobj_type *get_ktype(struct kobject *kobj) +static inline const struct kobj_type *get_ktype(struct kobject *kobj) { return kobj->ktype; } diff --git a/kernel/params.c b/kernel/params.c index 8299bd764e42..9b90e3c4d3c0 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -928,7 +928,7 @@ static const struct sysfs_ops module_sysfs_ops = { static int uevent_filter(struct kset *kset, struct kobject *kobj) { - struct kobj_type *ktype = get_ktype(kobj); + const struct kobj_type *ktype = get_ktype(kobj); if (ktype == &module_ktype) return 1; diff --git a/lib/kobject.c b/lib/kobject.c index 4a56f519139d..56fa037501b5 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -65,7 +65,7 @@ void kobject_get_ownership(struct kobject *kobj, kuid_t *uid, kgid_t *gid) */ static int populate_dir(struct kobject *kobj) { - struct kobj_type *t = get_ktype(kobj); + const struct kobj_type *t = get_ktype(kobj); struct attribute *attr; int error = 0; int i; @@ -346,7 +346,7 @@ EXPORT_SYMBOL(kobject_set_name); * to kobject_put(), not by a call to kfree directly to ensure that all of * the memory is cleaned up properly. */ -void kobject_init(struct kobject *kobj, struct kobj_type *ktype) +void kobject_init(struct kobject *kobj, const struct kobj_type *ktype) { char *err_str; @@ -461,7 +461,7 @@ EXPORT_SYMBOL(kobject_add); * same type of error handling after a call to kobject_add() and kobject * lifetime rules are the same here. */ -int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, +int kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...) { va_list args; @@ -679,7 +679,7 @@ EXPORT_SYMBOL(kobject_get_unless_zero); static void kobject_cleanup(struct kobject *kobj) { struct kobject *parent = kobj->parent; - struct kobj_type *t = get_ktype(kobj); + const struct kobj_type *t = get_ktype(kobj); const char *name = kobj->name; pr_debug("kobject: '%s' (%p): %s, parent %p\n", -- cgit v1.2.3 From cf6299b6101903c31bddb0065804b2121ed510c7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 27 Dec 2021 17:39:24 +0100 Subject: kobject: remove kset from struct kset_uevent_ops callbacks There is no need to pass the pointer to the kset in the struct kset_uevent_ops callbacks as no one uses it, so just remove that pointer entirely. Reviewed-by: Rafael J. Wysocki Reviewed-by: Wedson Almeida Filho Link: https://lore.kernel.org/r/20211227163924.3970661-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- Documentation/core-api/kobject.rst | 7 +++---- Documentation/translations/zh_CN/core-api/kobject.rst | 7 +++---- drivers/base/bus.c | 2 +- drivers/base/core.c | 11 +++++------ drivers/dma-buf/dma-buf-sysfs-stats.c | 2 +- fs/dlm/lockspace.c | 3 +-- fs/gfs2/sys.c | 3 +-- include/linux/kobject.h | 7 +++---- kernel/params.c | 2 +- lib/kobject_uevent.c | 6 +++--- 10 files changed, 22 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/Documentation/core-api/kobject.rst b/Documentation/core-api/kobject.rst index d3b5bf9f643a..3d6e3107315d 100644 --- a/Documentation/core-api/kobject.rst +++ b/Documentation/core-api/kobject.rst @@ -373,10 +373,9 @@ If a kset wishes to control the uevent operations of the kobjects associated with it, it can use the struct kset_uevent_ops to handle it:: struct kset_uevent_ops { - int (* const filter)(struct kset *kset, struct kobject *kobj); - const char *(* const name)(struct kset *kset, struct kobject *kobj); - int (* const uevent)(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env); + int (* const filter)(struct kobject *kobj); + const char *(* const name)(struct kobject *kobj); + int (* const uevent)(struct kobject *kobj, struct kobj_uevent_env *env); }; diff --git a/Documentation/translations/zh_CN/core-api/kobject.rst b/Documentation/translations/zh_CN/core-api/kobject.rst index b7c37794cc7f..95634083dca0 100644 --- a/Documentation/translations/zh_CN/core-api/kobject.rst +++ b/Documentation/translations/zh_CN/core-api/kobject.rst @@ -325,10 +325,9 @@ ksets 结构体kset_uevent_ops来处理它:: struct kset_uevent_ops { - int (* const filter)(struct kset *kset, struct kobject *kobj); - const char *(* const name)(struct kset *kset, struct kobject *kobj); - int (* const uevent)(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env); + int (* const filter)(struct kobject *kobj); + const char *(* const name)(struct kobject *kobj); + int (* const uevent)(struct kobject *kobj, struct kobj_uevent_env *env); }; diff --git a/drivers/base/bus.c b/drivers/base/bus.c index a64454f5f8c0..97936ec49bde 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -163,7 +163,7 @@ static struct kobj_type bus_ktype = { .release = bus_release, }; -static int bus_uevent_filter(struct kset *kset, struct kobject *kobj) +static int bus_uevent_filter(struct kobject *kobj) { const struct kobj_type *ktype = get_ktype(kobj); diff --git a/drivers/base/core.c b/drivers/base/core.c index d712ea11066b..60d703ebd123 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -2261,7 +2261,7 @@ static struct kobj_type device_ktype = { }; -static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) +static int dev_uevent_filter(struct kobject *kobj) { const struct kobj_type *ktype = get_ktype(kobj); @@ -2275,7 +2275,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) return 0; } -static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) +static const char *dev_uevent_name(struct kobject *kobj) { struct device *dev = kobj_to_dev(kobj); @@ -2286,8 +2286,7 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) return NULL; } -static int dev_uevent(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env) +static int dev_uevent(struct kobject *kobj, struct kobj_uevent_env *env) { struct device *dev = kobj_to_dev(kobj); int retval = 0; @@ -2382,7 +2381,7 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, /* respect filter */ if (kset->uevent_ops && kset->uevent_ops->filter) - if (!kset->uevent_ops->filter(kset, &dev->kobj)) + if (!kset->uevent_ops->filter(&dev->kobj)) goto out; env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); @@ -2390,7 +2389,7 @@ static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, return -ENOMEM; /* let the kset specific function add its keys */ - retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); + retval = kset->uevent_ops->uevent(&dev->kobj, env); if (retval) goto out; diff --git a/drivers/dma-buf/dma-buf-sysfs-stats.c b/drivers/dma-buf/dma-buf-sysfs-stats.c index 053baadcada9..2bba0babcb62 100644 --- a/drivers/dma-buf/dma-buf-sysfs-stats.c +++ b/drivers/dma-buf/dma-buf-sysfs-stats.c @@ -132,7 +132,7 @@ void dma_buf_stats_teardown(struct dma_buf *dmabuf) /* Statistics files do not need to send uevents. */ -static int dmabuf_sysfs_uevent_filter(struct kset *kset, struct kobject *kobj) +static int dmabuf_sysfs_uevent_filter(struct kobject *kobj) { return 0; } diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c index 10eddfa6c3d7..0bbb346cb892 100644 --- a/fs/dlm/lockspace.c +++ b/fs/dlm/lockspace.c @@ -216,8 +216,7 @@ static int do_uevent(struct dlm_ls *ls, int in) return ls->ls_uevent_result; } -static int dlm_uevent(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env) +static int dlm_uevent(struct kobject *kobj, struct kobj_uevent_env *env) { struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj); diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index c0a34d9ddee4..a6002b2d146d 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -767,8 +767,7 @@ void gfs2_sys_fs_del(struct gfs2_sbd *sdp) wait_for_completion(&sdp->sd_kobj_unregister); } -static int gfs2_uevent(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env) +static int gfs2_uevent(struct kobject *kobj, struct kobj_uevent_env *env) { struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); struct super_block *s = sdp->sd_vfs; diff --git a/include/linux/kobject.h b/include/linux/kobject.h index 683172b2e094..ad90b49824dc 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -153,10 +153,9 @@ struct kobj_uevent_env { }; struct kset_uevent_ops { - int (* const filter)(struct kset *kset, struct kobject *kobj); - const char *(* const name)(struct kset *kset, struct kobject *kobj); - int (* const uevent)(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env); + int (* const filter)(struct kobject *kobj); + const char *(* const name)(struct kobject *kobj); + int (* const uevent)(struct kobject *kobj, struct kobj_uevent_env *env); }; struct kobj_attribute { diff --git a/kernel/params.c b/kernel/params.c index 9b90e3c4d3c0..5b92310425c5 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -926,7 +926,7 @@ static const struct sysfs_ops module_sysfs_ops = { .store = module_attr_store, }; -static int uevent_filter(struct kset *kset, struct kobject *kobj) +static int uevent_filter(struct kobject *kobj) { const struct kobj_type *ktype = get_ktype(kobj); diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index c87d5b6a8a55..7c44b7ae4c5c 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -501,7 +501,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, } /* skip the event, if the filter returns zero. */ if (uevent_ops && uevent_ops->filter) - if (!uevent_ops->filter(kset, kobj)) { + if (!uevent_ops->filter(kobj)) { pr_debug("kobject: '%s' (%p): %s: filter function " "caused the event to drop!\n", kobject_name(kobj), kobj, __func__); @@ -510,7 +510,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* originating subsystem */ if (uevent_ops && uevent_ops->name) - subsystem = uevent_ops->name(kset, kobj); + subsystem = uevent_ops->name(kobj); else subsystem = kobject_name(&kset->kobj); if (!subsystem) { @@ -554,7 +554,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* let the kset specific function add its stuff */ if (uevent_ops && uevent_ops->uevent) { - retval = uevent_ops->uevent(kset, kobj, env); + retval = uevent_ops->uevent(kobj, env); if (retval) { pr_debug("kobject: '%s' (%p): %s: uevent() returned " "%d\n", kobject_name(kobj), kobj, -- cgit v1.2.3 From f083266487690124481eac0869da850406fb3ed3 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 29 Aug 2021 09:18:53 +0200 Subject: headers/uninline: Uninline single-use function: kobject_has_children() This was the only usage of in , so we'll able to decouple the two after this change. Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 17 +++++++++++++++++ include/linux/kobject.h | 17 ----------------- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/core.c b/drivers/base/core.c index 60d703ebd123..603941b00988 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -3028,6 +3028,23 @@ static inline struct kobject *get_glue_dir(struct device *dev) return dev->kobj.parent; } +/** + * kobject_has_children - Returns whether a kobject has children. + * @kobj: the object to test + * + * This will return whether a kobject has other kobjects as children. + * + * It does NOT account for the presence of attribute files, only sub + * directories. It also assumes there is no concurrent addition or + * removal of such children, and thus relies on external locking. + */ +static inline bool kobject_has_children(struct kobject *kobj) +{ + WARN_ON_ONCE(kref_read(&kobj->kref) == 0); + + return kobj->sd && kobj->sd->dir.subdirs; +} + /* * make sure cleaning up dir as the last step, we need to make * sure .release handler of kobject is run with holding the diff --git a/include/linux/kobject.h b/include/linux/kobject.h index ad90b49824dc..c7b47399b36a 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -117,23 +117,6 @@ extern void kobject_get_ownership(struct kobject *kobj, kuid_t *uid, kgid_t *gid); extern char *kobject_get_path(struct kobject *kobj, gfp_t flag); -/** - * kobject_has_children - Returns whether a kobject has children. - * @kobj: the object to test - * - * This will return whether a kobject has other kobjects as children. - * - * It does NOT account for the presence of attribute files, only sub - * directories. It also assumes there is no concurrent addition or - * removal of such children, and thus relies on external locking. - */ -static inline bool kobject_has_children(struct kobject *kobj) -{ - WARN_ON_ONCE(kref_read(&kobj->kref) == 0); - - return kobj->sd && kobj->sd->dir.subdirs; -} - struct kobj_type { void (*release)(struct kobject *kobj); const struct sysfs_ops *sysfs_ops; -- cgit v1.2.3