From d487858ebffaab9acd8945f19ef400ec6eda11f1 Mon Sep 17 00:00:00 2001 From: Kurt Borja Date: Thu, 27 Mar 2025 20:19:37 -0300 Subject: [PATCH 01/17] driver core: faux: Add sysfs groups after probing Manually add sysfs groups after the faux_device_ops's probe succeeds. Likewise remove these groups just before calling the faux_devices_ops's remove callback. This approach approximates the order in which the driver core adds and removes the driver's .dev_groups of a device to avoid lifetime issues. This is done specifically to avoid using the device's .groups member, which adds groups before the device is even registered to the bus. This lets consumers of this API, initialize resources on the .probe callback and then use them inside is_visible/show/store methods, through dev_get_drvdata() without races. Cc: Rafael J. Wysocki Cc: Danilo Krummrich Signed-off-by: Kurt Borja Link: https://lore.kernel.org/r/20250327-faux-groups-v2-1-745a3cf0bc16@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/faux.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/base/faux.c b/drivers/base/faux.c index 407c1d1aad50..9054d346bd7f 100644 --- a/drivers/base/faux.c +++ b/drivers/base/faux.c @@ -25,6 +25,7 @@ struct faux_object { struct faux_device faux_dev; const struct faux_device_ops *faux_ops; + const struct attribute_group **groups; }; #define to_faux_object(dev) container_of_const(dev, struct faux_object, faux_dev.dev) @@ -43,10 +44,21 @@ static int faux_probe(struct device *dev) struct faux_object *faux_obj = to_faux_object(dev); struct faux_device *faux_dev = &faux_obj->faux_dev; const struct faux_device_ops *faux_ops = faux_obj->faux_ops; - int ret = 0; + int ret; - if (faux_ops && faux_ops->probe) + if (faux_ops && faux_ops->probe) { ret = faux_ops->probe(faux_dev); + if (ret) + return ret; + } + + /* + * Add groups after the probe succeeds to ensure resources are + * initialized correctly + */ + ret = device_add_groups(dev, faux_obj->groups); + if (ret && faux_ops && faux_ops->remove) + faux_ops->remove(faux_dev); return ret; } @@ -57,6 +69,8 @@ static void faux_remove(struct device *dev) struct faux_device *faux_dev = &faux_obj->faux_dev; const struct faux_device_ops *faux_ops = faux_obj->faux_ops; + device_remove_groups(dev, faux_obj->groups); + if (faux_ops && faux_ops->remove) faux_ops->remove(faux_dev); } @@ -124,8 +138,9 @@ struct faux_device *faux_device_create_with_groups(const char *name, if (!faux_obj) return NULL; - /* Save off the callbacks so we can use them in the future */ + /* Save off the callbacks and groups so we can use them in the future */ faux_obj->faux_ops = faux_ops; + faux_obj->groups = groups; /* Initialize the device portion and register it with the driver core */ faux_dev = &faux_obj->faux_dev; @@ -138,7 +153,6 @@ struct faux_device *faux_device_create_with_groups(const char *name, else dev->parent = &faux_bus_root; dev->bus = &faux_bus_type; - dev->groups = groups; dev_set_name(dev, "%s", name); ret = device_add(dev); From eaa0d30216c1d54b157ea0ad7f35ba76f6e9a825 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 18 Feb 2025 20:29:46 +0100 Subject: [PATCH 02/17] driver core: auxiliary bus: add device creation helpers Add helper functions to create a device on the auxiliary bus. This is meant for fairly simple usage of the auxiliary bus, to avoid having the same code repeated in the different drivers. Suggested-by: Stephen Boyd Cc: Arnd Bergmann Signed-off-by: Jerome Brunet Reviewed-by: Greg Kroah-Hartman Reviewed-by: Ira Weiny Link: https://lore.kernel.org/r/20250218-aux-device-create-helper-v4-1-c3d7dfdea2e6@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/auxiliary.c | 108 ++++++++++++++++++++++++++++++++++ include/linux/auxiliary_bus.h | 17 ++++++ 2 files changed, 125 insertions(+) diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c index afa4df4c5a3f..a6d46c2759be 100644 --- a/drivers/base/auxiliary.c +++ b/drivers/base/auxiliary.c @@ -385,6 +385,114 @@ void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv) } EXPORT_SYMBOL_GPL(auxiliary_driver_unregister); +static void auxiliary_device_release(struct device *dev) +{ + struct auxiliary_device *auxdev = to_auxiliary_dev(dev); + + kfree(auxdev); +} + +/** + * auxiliary_device_create - create a device on the auxiliary bus + * @dev: parent device + * @modname: module name used to create the auxiliary driver name. + * @devname: auxiliary bus device name + * @platform_data: auxiliary bus device platform data + * @id: auxiliary bus device id + * + * Helper to create an auxiliary bus device. + * The device created matches driver 'modname.devname' on the auxiliary bus. + */ +struct auxiliary_device *auxiliary_device_create(struct device *dev, + const char *modname, + const char *devname, + void *platform_data, + int id) +{ + struct auxiliary_device *auxdev; + int ret; + + auxdev = kzalloc(sizeof(*auxdev), GFP_KERNEL); + if (!auxdev) + return NULL; + + auxdev->id = id; + auxdev->name = devname; + auxdev->dev.parent = dev; + auxdev->dev.platform_data = platform_data; + auxdev->dev.release = auxiliary_device_release; + device_set_of_node_from_dev(&auxdev->dev, dev); + + ret = auxiliary_device_init(auxdev); + if (ret) { + kfree(auxdev); + return NULL; + } + + ret = __auxiliary_device_add(auxdev, modname); + if (ret) { + /* + * It may look odd but auxdev should not be freed here. + * auxiliary_device_uninit() calls device_put() which call + * the device release function, freeing auxdev. + */ + auxiliary_device_uninit(auxdev); + return NULL; + } + + return auxdev; +} +EXPORT_SYMBOL_GPL(auxiliary_device_create); + +/** + * auxiliary_device_destroy - remove an auxiliary device + * @auxdev: pointer to the auxdev to be removed + * + * Helper to remove an auxiliary device created with + * auxiliary_device_create() + */ +void auxiliary_device_destroy(void *auxdev) +{ + struct auxiliary_device *_auxdev = auxdev; + + auxiliary_device_delete(_auxdev); + auxiliary_device_uninit(_auxdev); +} +EXPORT_SYMBOL_GPL(auxiliary_device_destroy); + +/** + * __devm_auxiliary_device_create - create a managed device on the auxiliary bus + * @dev: parent device + * @modname: module name used to create the auxiliary driver name. + * @devname: auxiliary bus device name + * @platform_data: auxiliary bus device platform data + * @id: auxiliary bus device id + * + * Device managed helper to create an auxiliary bus device. + * The device created matches driver 'modname.devname' on the auxiliary bus. + */ +struct auxiliary_device *__devm_auxiliary_device_create(struct device *dev, + const char *modname, + const char *devname, + void *platform_data, + int id) +{ + struct auxiliary_device *auxdev; + int ret; + + auxdev = auxiliary_device_create(dev, modname, devname, platform_data, id); + if (IS_ERR(auxdev)) + return auxdev; + + ret = devm_add_action_or_reset(dev, auxiliary_device_destroy, + auxdev); + if (ret) + return ERR_PTR(ret); + + return auxdev; +} +EXPORT_SYMBOL_GPL(__devm_auxiliary_device_create); + void __init auxiliary_bus_init(void) { WARN_ON(bus_register(&auxiliary_bus_type)); diff --git a/include/linux/auxiliary_bus.h b/include/linux/auxiliary_bus.h index 65dd7f154374..4086afd0cc6b 100644 --- a/include/linux/auxiliary_bus.h +++ b/include/linux/auxiliary_bus.h @@ -254,6 +254,23 @@ int __auxiliary_driver_register(struct auxiliary_driver *auxdrv, struct module * void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv); +struct auxiliary_device *auxiliary_device_create(struct device *dev, + const char *modname, + const char *devname, + void *platform_data, + int id); +void auxiliary_device_destroy(void *auxdev); + +struct auxiliary_device *__devm_auxiliary_device_create(struct device *dev, + const char *modname, + const char *devname, + void *platform_data, + int id); + +#define devm_auxiliary_device_create(dev, devname, platform_data) \ + __devm_auxiliary_device_create(dev, KBUILD_MODNAME, devname, \ + platform_data, 0) + /** * module_auxiliary_driver() - Helper macro for registering an auxiliary driver * @__auxiliary_driver: auxiliary driver struct From 5bcca36898aab843eb259984c29de7ff9e0d8723 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 28 Feb 2025 09:18:24 +0100 Subject: [PATCH 03/17] component: do not try to unbind unbound components Error handling is apparently hard and driver authors often get it wrong. Continue to warn but do not try to unbind components that have never been bound in order to avoid crashing systems where such a buggy teardown path is hit. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20250228081824.4640-1-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/component.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/base/component.c b/drivers/base/component.c index abe60eb45c55..024ad9471b8a 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -586,7 +586,8 @@ EXPORT_SYMBOL_GPL(component_master_is_bound); static void component_unbind(struct component *component, struct aggregate_device *adev, void *data) { - WARN_ON(!component->bound); + if (WARN_ON(!component->bound)) + return; dev_dbg(adev->parent, "unbinding %s component %p (ops %ps)\n", dev_name(component->dev), component, component->ops); From 8c016bc3063fa344f5cb74f06ec07d37136229ca Mon Sep 17 00:00:00 2001 From: Woody Zhang Date: Sun, 30 Mar 2025 18:36:27 +0800 Subject: [PATCH 04/17] platform: replace magic number with macro PLATFORM_DEVID_NONE Replace magic number with PLATFORM_DEVID_NONE to make it more informative. Signed-off-by: Woody Zhang Link: https://lore.kernel.org/r/20250330103627.2370771-2-woodyzhang666@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 1813cfd0c4bd..63dfa41f0904 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -982,7 +982,7 @@ struct platform_device * __init_or_module __platform_create_bundle( struct platform_device *pdev; int error; - pdev = platform_device_alloc(driver->driver.name, -1); + pdev = platform_device_alloc(driver->driver.name, PLATFORM_DEVID_NONE); if (!pdev) { error = -ENOMEM; goto err_out; From f407a8a28a294dd3201e55b6a63b9225c489fd95 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Wed, 9 Apr 2025 16:24:32 +0530 Subject: [PATCH 05/17] devres: simplify devm_kstrdup() using devm_kmemdup() devm_kstrdup() logic pretty much reflects devm_kmemdup() for strings, so just reuse it. Signed-off-by: Raag Jadav Link: https://lore.kernel.org/r/20250409105432.1852355-1-raag.jadav@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/devres.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/base/devres.c b/drivers/base/devres.c index d8a733ea5e1a..eee63bc1f062 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -976,17 +976,10 @@ EXPORT_SYMBOL_GPL(devm_krealloc); */ char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) { - size_t size; - char *buf; - if (!s) return NULL; - size = strlen(s) + 1; - buf = devm_kmalloc(dev, size, gfp); - if (buf) - memcpy(buf, s, size); - return buf; + return devm_kmemdup(dev, s, strlen(s) + 1, gfp); } EXPORT_SYMBOL_GPL(devm_kstrdup); From 31e4e12e0e9609850cefd4b2e1adf782f56337d6 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Mon, 14 Apr 2025 19:36:52 +0800 Subject: [PATCH 06/17] software node: Correct a OOB check in software_node_get_reference_args() software_node_get_reference_args() wants to get @index-th element, so the property value requires at least '(index + 1) * sizeof(*ref)' bytes but that can not be guaranteed by current OOB check, and may cause OOB for malformed property. Fix by using as OOB check '((index + 1) * sizeof(*ref) > prop->length)'. Reviewed-by: Sakari Ailus Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20250414-fix_swnode-v2-1-9c9e6ae11eab@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/swnode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index b1726a3515f6..22bed2d35b2e 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -529,7 +529,7 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode, if (prop->is_inline) return -EINVAL; - if (index * sizeof(*ref) >= prop->length) + if ((index + 1) * sizeof(*ref) > prop->length) return -ENOENT; ref_array = prop->pointer; From 97d06802d10a2827ef46fd31789a26117ce7f3d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 13 Mar 2025 16:57:45 +0100 Subject: [PATCH 07/17] sysfs: constify bin_attribute argument of bin_attribute::read/write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All callback implementers have been moved to the const variant of the callbacks. The signature of the original callbacks can now be changed. Also remove the now unnecessary transition machinery inside __BIN_ATTR(). Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250313-sysfs-const-bin_attr-final-v2-1-96284e1e88ce@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- include/linux/sysfs.h | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 18f7e1fd093c..576b8b3c60af 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -306,11 +306,11 @@ struct bin_attribute { size_t size; void *private; struct address_space *(*f_mapping)(void); - ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *, + ssize_t (*read)(struct file *, struct kobject *, const struct bin_attribute *, char *, loff_t, size_t); ssize_t (*read_new)(struct file *, struct kobject *, const struct bin_attribute *, char *, loff_t, size_t); - ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *, + ssize_t (*write)(struct file *, struct kobject *, const struct bin_attribute *, char *, loff_t, size_t); ssize_t (*write_new)(struct file *, struct kobject *, const struct bin_attribute *, char *, loff_t, size_t); @@ -332,28 +332,11 @@ struct bin_attribute { */ #define sysfs_bin_attr_init(bin_attr) sysfs_attr_init(&(bin_attr)->attr) -typedef ssize_t __sysfs_bin_rw_handler_new(struct file *, struct kobject *, - const struct bin_attribute *, char *, loff_t, size_t); - /* macros to create static binary attributes easier */ #define __BIN_ATTR(_name, _mode, _read, _write, _size) { \ .attr = { .name = __stringify(_name), .mode = _mode }, \ - .read = _Generic(_read, \ - __sysfs_bin_rw_handler_new * : NULL, \ - default : _read \ - ), \ - .read_new = _Generic(_read, \ - __sysfs_bin_rw_handler_new * : _read, \ - default : NULL \ - ), \ - .write = _Generic(_write, \ - __sysfs_bin_rw_handler_new * : NULL, \ - default : _write \ - ), \ - .write_new = _Generic(_write, \ - __sysfs_bin_rw_handler_new * : _write, \ - default : NULL \ - ), \ + .read = _read, \ + .write = _write, \ .size = _size, \ } From 9bec944506faf10d6274c75e3a55bc107b75cea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 13 Mar 2025 16:57:46 +0100 Subject: [PATCH 08/17] sysfs: constify attribute_group::bin_attrs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All users of this field have been migrated to bin_attrs_new. It can now be constified. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20250313-sysfs-const-bin_attr-final-v2-2-96284e1e88ce@weissschuh.net Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/group.c | 6 +++--- include/linux/sysfs.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 8b01a7eda5fb..2d78e94072a0 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -21,7 +21,7 @@ static void remove_files(struct kernfs_node *parent, const struct attribute_group *grp) { struct attribute *const *attr; - struct bin_attribute *const *bin_attr; + const struct bin_attribute *const *bin_attr; if (grp->attrs) for (attr = grp->attrs; *attr; attr++) @@ -47,7 +47,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj, const struct attribute_group *grp, int update) { struct attribute *const *attr; - struct bin_attribute *const *bin_attr; + const struct bin_attribute *const *bin_attr; int error = 0, i; if (grp->attrs) { @@ -521,7 +521,7 @@ static int sysfs_group_attrs_change_owner(struct kernfs_node *grp_kn, } if (grp->bin_attrs) { - struct bin_attribute *const *bin_attr; + const struct bin_attribute *const *bin_attr; for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) { kn = kernfs_find_and_get(grp_kn, (*bin_attr)->attr.name); diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 576b8b3c60af..f418aae4f113 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -107,7 +107,7 @@ struct attribute_group { int); struct attribute **attrs; union { - struct bin_attribute **bin_attrs; + const struct bin_attribute *const *bin_attrs; const struct bin_attribute *const *bin_attrs_new; }; }; From 2806c6b8f3d1e406f2b7e3266ddd21100fbe7151 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 23 Apr 2025 13:04:26 +0300 Subject: [PATCH 09/17] driver core: auxiliary bus: Fix IS_ERR() vs NULL mixup in __devm_auxiliary_device_create() This code was originally going to use error pointers but we decided it should return NULL instead. The error pointer code in __devm_auxiliary_device_create() was left over from the first version. Update it to use NULL. No callers have been merged yet, so that makes this change simple and self contained. Fixes: eaa0d30216c1 ("driver core: auxiliary bus: add device creation helpers") Signed-off-by: Dan Carpenter Reviewed-by: Jerome Brunet Reviewed-by: Leon Romanovsky Link: https://lore.kernel.org/r/aAi7Kg3aTguFD0fU@stanley.mountain Signed-off-by: Greg Kroah-Hartman --- drivers/base/auxiliary.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c index a6d46c2759be..fd7efd2c94e1 100644 --- a/drivers/base/auxiliary.c +++ b/drivers/base/auxiliary.c @@ -481,13 +481,13 @@ struct auxiliary_device *__devm_auxiliary_device_create(struct device *dev, int ret; auxdev = auxiliary_device_create(dev, modname, devname, platform_data, id); - if (IS_ERR(auxdev)) - return auxdev; + if (!auxdev) + return NULL; ret = devm_add_action_or_reset(dev, auxiliary_device_destroy, auxdev); if (ret) - return ERR_PTR(ret); + return NULL; return auxdev; } From cec59c440a05c241846e8fe9d2575a2dafb56fd9 Mon Sep 17 00:00:00 2001 From: Jinliang Zheng Date: Tue, 15 Apr 2025 23:36:58 +0800 Subject: [PATCH 10/17] kernfs: switch global kernfs_idr_lock to per-fs lock The kernfs implementation has big lock granularity(kernfs_idr_lock) so every kernfs-based(e.g., sysfs, cgroup) fs are able to compete the lock. This patch switches the global kernfs_idr_lock to per-fs lock, which put the spinlock into kernfs_root. Signed-off-by: Jinliang Zheng Acked-by: Tejun Heo Link: https://lore.kernel.org/r/20250415153659.14950-2-alexjlzheng@tencent.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 14 +++++++------- fs/kernfs/kernfs-internal.h | 1 + 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index fc70d72c3fe8..355d943ffe27 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -27,7 +27,6 @@ DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */ */ static DEFINE_SPINLOCK(kernfs_pr_cont_lock); static char kernfs_pr_cont_buf[PATH_MAX]; /* protected by pr_cont_lock */ -static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */ #define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb) @@ -584,9 +583,9 @@ void kernfs_put(struct kernfs_node *kn) if (kernfs_type(kn) == KERNFS_LINK) kernfs_put(kn->symlink.target_kn); - spin_lock(&kernfs_idr_lock); + spin_lock(&root->kernfs_idr_lock); idr_remove(&root->ino_idr, (u32)kernfs_ino(kn)); - spin_unlock(&kernfs_idr_lock); + spin_unlock(&root->kernfs_idr_lock); call_rcu(&kn->rcu, kernfs_free_rcu); @@ -639,13 +638,13 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, goto err_out1; idr_preload(GFP_KERNEL); - spin_lock(&kernfs_idr_lock); + spin_lock(&root->kernfs_idr_lock); ret = idr_alloc_cyclic(&root->ino_idr, kn, 1, 0, GFP_ATOMIC); if (ret >= 0 && ret < root->last_id_lowbits) root->id_highbits++; id_highbits = root->id_highbits; root->last_id_lowbits = ret; - spin_unlock(&kernfs_idr_lock); + spin_unlock(&root->kernfs_idr_lock); idr_preload_end(); if (ret < 0) goto err_out2; @@ -681,9 +680,9 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, return kn; err_out3: - spin_lock(&kernfs_idr_lock); + spin_lock(&root->kernfs_idr_lock); idr_remove(&root->ino_idr, (u32)kernfs_ino(kn)); - spin_unlock(&kernfs_idr_lock); + spin_unlock(&root->kernfs_idr_lock); err_out2: kmem_cache_free(kernfs_node_cache, kn); err_out1: @@ -989,6 +988,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, return ERR_PTR(-ENOMEM); idr_init(&root->ino_idr); + spin_lock_init(&root->kernfs_idr_lock); init_rwsem(&root->kernfs_rwsem); init_rwsem(&root->kernfs_iattr_rwsem); init_rwsem(&root->kernfs_supers_rwsem); diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 40a2a9cd819d..24e9514565ac 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -40,6 +40,7 @@ struct kernfs_root { /* private fields, do not use outside kernfs proper */ struct idr ino_idr; + spinlock_t kernfs_idr_lock; /* root->ino_idr */ u32 last_id_lowbits; u32 id_highbits; struct kernfs_syscall_ops *syscall_ops; From 93b27a845ec1355459e6aa539dd203a2f5136d8f Mon Sep 17 00:00:00 2001 From: Jinliang Zheng Date: Tue, 15 Apr 2025 23:36:59 +0800 Subject: [PATCH 11/17] kernfs: switch global kernfs_rename_lock to per-fs lock The kernfs implementation has big lock granularity(kernfs_rename_lock) so every kernfs-based(e.g., sysfs, cgroup) fs are able to compete the lock. This patch switches the global kernfs_rename_lock to per-fs lock, which put the rwlock into kernfs_root. Signed-off-by: Jinliang Zheng Acked-by: Tejun Heo Link: https://lore.kernel.org/r/20250415153659.14950-3-alexjlzheng@tencent.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 14 ++++++++------ fs/kernfs/kernfs-internal.h | 15 +++++++++++---- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 355d943ffe27..d63a96786c9b 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -17,7 +17,6 @@ #include "kernfs-internal.h" -DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */ /* * Don't use rename_lock to piggy back on pr_cont_buf. We don't want to * call pr_cont() while holding rename_lock. Because sometimes pr_cont() @@ -228,7 +227,7 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, if (to) { root = kernfs_root(to); if (!(root->flags & KERNFS_ROOT_INVARIANT_PARENT)) { - guard(read_lock_irqsave)(&kernfs_rename_lock); + guard(read_lock_irqsave)(&root->kernfs_rename_lock); return kernfs_path_from_node_locked(to, from, buf, buflen); } } @@ -295,12 +294,14 @@ out: struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) { struct kernfs_node *parent; + struct kernfs_root *root; unsigned long flags; - read_lock_irqsave(&kernfs_rename_lock, flags); + root = kernfs_root(kn); + read_lock_irqsave(&root->kernfs_rename_lock, flags); parent = kernfs_parent(kn); kernfs_get(parent); - read_unlock_irqrestore(&kernfs_rename_lock, flags); + read_unlock_irqrestore(&root->kernfs_rename_lock, flags); return parent; } @@ -993,6 +994,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, init_rwsem(&root->kernfs_iattr_rwsem); init_rwsem(&root->kernfs_supers_rwsem); INIT_LIST_HEAD(&root->supers); + rwlock_init(&root->kernfs_rename_lock); /* * On 64bit ino setups, id is ino. On 32bit, low 32bits are ino. @@ -1789,7 +1791,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, /* rename_lock protects ->parent accessors */ if (old_parent != new_parent) { kernfs_get(new_parent); - write_lock_irq(&kernfs_rename_lock); + write_lock_irq(&root->kernfs_rename_lock); rcu_assign_pointer(kn->__parent, new_parent); @@ -1797,7 +1799,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, if (new_name) rcu_assign_pointer(kn->name, new_name); - write_unlock_irq(&kernfs_rename_lock); + write_unlock_irq(&root->kernfs_rename_lock); kernfs_put(old_parent); } else { /* name assignment is RCU protected, parent is the same */ diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 24e9514565ac..6061b6f70d2a 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -19,8 +19,6 @@ #include #include -extern rwlock_t kernfs_rename_lock; - struct kernfs_iattrs { kuid_t ia_uid; kgid_t ia_gid; @@ -53,6 +51,9 @@ struct kernfs_root { struct rw_semaphore kernfs_iattr_rwsem; struct rw_semaphore kernfs_supers_rwsem; + /* kn->parent and kn->name */ + rwlock_t kernfs_rename_lock; + struct rcu_head rcu; }; @@ -108,6 +109,11 @@ static inline bool kernfs_root_is_locked(const struct kernfs_node *kn) return lockdep_is_held(&kernfs_root(kn)->kernfs_rwsem); } +static inline bool kernfs_rename_is_locked(const struct kernfs_node *kn) +{ + return lockdep_is_held(&kernfs_root(kn)->kernfs_rename_lock); +} + static inline const char *kernfs_rcu_name(const struct kernfs_node *kn) { return rcu_dereference_check(kn->name, kernfs_root_is_locked(kn)); @@ -118,14 +124,15 @@ static inline struct kernfs_node *kernfs_parent(const struct kernfs_node *kn) /* * The kernfs_node::__parent remains valid within a RCU section. The kn * can be reparented (and renamed) which changes the entry. This can be - * avoided by locking kernfs_root::kernfs_rwsem or kernfs_rename_lock. + * avoided by locking kernfs_root::kernfs_rwsem or + * kernfs_root::kernfs_rename_lock. * Both locks can be used to obtain a reference on __parent. Once the * reference count reaches 0 then the node is about to be freed * and can not be renamed (or become a different parent) anymore. */ return rcu_dereference_check(kn->__parent, kernfs_root_is_locked(kn) || - lockdep_is_held(&kernfs_rename_lock) || + kernfs_rename_is_locked(kn) || !atomic_read(&kn->count)); } From 142ba31d8b4aff086c4f080bd97d437232922177 Mon Sep 17 00:00:00 2001 From: Zijun Hu Date: Sun, 20 Apr 2025 12:19:09 +0800 Subject: [PATCH 12/17] PM: wakeup: Do not expose 4 device wakeup source APIs The following 4 APIs are only used by drivers/base/power/wakeup.c internally. - wakeup_source_create() - wakeup_source_destroy() - wakeup_source_add() - wakeup_source_remove() Do not expose them by making them as static functions. Signed-off-by: Zijun Hu Link: https://lore.kernel.org/r/20250420-fix_power-v2-1-9b938d2283aa@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/wakeup.c | 12 ++++-------- include/linux/pm_wakeup.h | 15 --------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 63bf914a4d44..27505dea7c1b 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -77,7 +77,7 @@ static DEFINE_IDA(wakeup_ida); * wakeup_source_create - Create a struct wakeup_source object. * @name: Name of the new wakeup source. */ -struct wakeup_source *wakeup_source_create(const char *name) +static struct wakeup_source *wakeup_source_create(const char *name) { struct wakeup_source *ws; const char *ws_name; @@ -106,7 +106,6 @@ err_name: err_ws: return NULL; } -EXPORT_SYMBOL_GPL(wakeup_source_create); /* * Record wakeup_source statistics being deleted into a dummy wakeup_source. @@ -149,7 +148,7 @@ static void wakeup_source_free(struct wakeup_source *ws) * * Use only for wakeup source objects created with wakeup_source_create(). */ -void wakeup_source_destroy(struct wakeup_source *ws) +static void wakeup_source_destroy(struct wakeup_source *ws) { if (!ws) return; @@ -158,13 +157,12 @@ void wakeup_source_destroy(struct wakeup_source *ws) wakeup_source_record(ws); wakeup_source_free(ws); } -EXPORT_SYMBOL_GPL(wakeup_source_destroy); /** * wakeup_source_add - Add given object to the list of wakeup sources. * @ws: Wakeup source object to add to the list. */ -void wakeup_source_add(struct wakeup_source *ws) +static void wakeup_source_add(struct wakeup_source *ws) { unsigned long flags; @@ -179,13 +177,12 @@ void wakeup_source_add(struct wakeup_source *ws) list_add_rcu(&ws->entry, &wakeup_sources); raw_spin_unlock_irqrestore(&events_lock, flags); } -EXPORT_SYMBOL_GPL(wakeup_source_add); /** * wakeup_source_remove - Remove given object from the wakeup sources list. * @ws: Wakeup source object to remove from the list. */ -void wakeup_source_remove(struct wakeup_source *ws) +static void wakeup_source_remove(struct wakeup_source *ws) { unsigned long flags; @@ -204,7 +201,6 @@ void wakeup_source_remove(struct wakeup_source *ws) */ ws->timer.function = NULL; } -EXPORT_SYMBOL_GPL(wakeup_source_remove); /** * wakeup_source_register - Create wakeup source and add it to the list. diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h index 51e0e8dd5f9e..c838b4a30f87 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -95,10 +95,6 @@ static inline void device_set_wakeup_path(struct device *dev) } /* drivers/base/power/wakeup.c */ -extern struct wakeup_source *wakeup_source_create(const char *name); -extern void wakeup_source_destroy(struct wakeup_source *ws); -extern void wakeup_source_add(struct wakeup_source *ws); -extern void wakeup_source_remove(struct wakeup_source *ws); extern struct wakeup_source *wakeup_source_register(struct device *dev, const char *name); extern void wakeup_source_unregister(struct wakeup_source *ws); @@ -129,17 +125,6 @@ static inline bool device_can_wakeup(struct device *dev) return dev->power.can_wakeup; } -static inline struct wakeup_source *wakeup_source_create(const char *name) -{ - return NULL; -} - -static inline void wakeup_source_destroy(struct wakeup_source *ws) {} - -static inline void wakeup_source_add(struct wakeup_source *ws) {} - -static inline void wakeup_source_remove(struct wakeup_source *ws) {} - static inline struct wakeup_source *wakeup_source_register(struct device *dev, const char *name) { From e99efa8ac8fd9cebca99652cb55b277b7200455e Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 29 Apr 2025 12:39:58 -0500 Subject: [PATCH 13/17] docs: debugfs: do not recommend debugfs_remove_recursive Update the debugfs documentation to indicate that debugfs_remove() should be used to clean up debugfs entries. In commit a3d1e7eb5abe ("simple_recursive_removal(): kernel-side rm -rf for ramfs-style filesystems"), function debugfs_remove_recursive() was made into an alias for debugfs_remove(): #define debugfs_remove_recursive debugfs_remove Therefore, drivers should just use debugfs_remove() going forward. Signed-off-by: Timur Tabi Link: https://lore.kernel.org/r/20250429173958.3973958-1-ttabi@nvidia.com Signed-off-by: Greg Kroah-Hartman --- Documentation/filesystems/debugfs.rst | 19 ++++++------------- .../driver_development_debugging_guide.rst | 2 +- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Documentation/filesystems/debugfs.rst b/Documentation/filesystems/debugfs.rst index 610f718ef8b5..55f807293924 100644 --- a/Documentation/filesystems/debugfs.rst +++ b/Documentation/filesystems/debugfs.rst @@ -229,22 +229,15 @@ module is unloaded without explicitly removing debugfs entries, the result will be a lot of stale pointers and no end of highly antisocial behavior. So all debugfs users - at least those which can be built as modules - must be prepared to remove all files and directories they create there. A file -can be removed with:: +or directory can be removed with:: void debugfs_remove(struct dentry *dentry); The dentry value can be NULL or an error value, in which case nothing will -be removed. - -Once upon a time, debugfs users were required to remember the dentry -pointer for every debugfs file they created so that all files could be -cleaned up. We live in more civilized times now, though, and debugfs users -can call:: - - void debugfs_remove_recursive(struct dentry *dentry); - -If this function is passed a pointer for the dentry corresponding to the -top-level directory, the entire hierarchy below that directory will be -removed. +be removed. Note that this function will recursively remove all files and +directories underneath it. Previously, debugfs_remove_recursive() was used +to perform that task, but this function is now just an alias to +debugfs_remove(). debugfs_remove_recursive() should be considered +deprecated. .. [1] http://lwn.net/Articles/309298/ diff --git a/Documentation/process/debugging/driver_development_debugging_guide.rst b/Documentation/process/debugging/driver_development_debugging_guide.rst index 46becda8764b..aca08f457793 100644 --- a/Documentation/process/debugging/driver_development_debugging_guide.rst +++ b/Documentation/process/debugging/driver_development_debugging_guide.rst @@ -155,7 +155,7 @@ The general idea is: ``my_variable`` - Clean up the directory when removing the device - (``debugfs_remove_recursive(parent);``) + (``debugfs_remove(parent);``) For the full documentation see :doc:`/filesystems/debugfs`. From 4f894483c902a49d428348f6ec8874fce59c63cb Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 28 Apr 2025 12:09:09 -0700 Subject: [PATCH 14/17] firmware_loader: use SHA-256 library API instead of crypto_shash API This user of SHA-256 does not support any other algorithm, so the crypto_shash abstraction provides no value. Just use the SHA-256 library API instead, which is much simpler and easier to use. Also take advantage of printk's built-in hex conversion using %*phN. Signed-off-by: Eric Biggers Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20250428190909.852705-1-ebiggers@kernel.org Signed-off-by: Danilo Krummrich --- drivers/base/firmware_loader/Kconfig | 4 +--- drivers/base/firmware_loader/main.c | 34 ++++------------------------ 2 files changed, 5 insertions(+), 33 deletions(-) diff --git a/drivers/base/firmware_loader/Kconfig b/drivers/base/firmware_loader/Kconfig index a03701674265..752b9a9bea03 100644 --- a/drivers/base/firmware_loader/Kconfig +++ b/drivers/base/firmware_loader/Kconfig @@ -3,8 +3,7 @@ menu "Firmware loader" config FW_LOADER tristate "Firmware loading facility" if EXPERT - select CRYPTO_HASH if FW_LOADER_DEBUG - select CRYPTO_SHA256 if FW_LOADER_DEBUG + select CRYPTO_LIB_SHA256 if FW_LOADER_DEBUG default y help This enables the firmware loading facility in the kernel. The kernel @@ -28,7 +27,6 @@ config FW_LOADER config FW_LOADER_DEBUG bool "Log filenames and checksums for loaded firmware" - depends on CRYPTO = FW_LOADER || CRYPTO=y depends on DYNAMIC_DEBUG depends on FW_LOADER default FW_LOADER diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index cb0912ea3e62..44486b2c7172 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -806,41 +806,15 @@ static void fw_abort_batch_reqs(struct firmware *fw) } #if defined(CONFIG_FW_LOADER_DEBUG) -#include #include static void fw_log_firmware_info(const struct firmware *fw, const char *name, struct device *device) { - struct shash_desc *shash; - struct crypto_shash *alg; - u8 *sha256buf; - char *outbuf; + u8 digest[SHA256_DIGEST_SIZE]; - alg = crypto_alloc_shash("sha256", 0, 0); - if (IS_ERR(alg)) - return; - - sha256buf = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL); - outbuf = kmalloc(SHA256_BLOCK_SIZE + 1, GFP_KERNEL); - shash = kmalloc(sizeof(*shash) + crypto_shash_descsize(alg), GFP_KERNEL); - if (!sha256buf || !outbuf || !shash) - goto out_free; - - shash->tfm = alg; - - if (crypto_shash_digest(shash, fw->data, fw->size, sha256buf) < 0) - goto out_free; - - for (int i = 0; i < SHA256_DIGEST_SIZE; i++) - sprintf(&outbuf[i * 2], "%02x", sha256buf[i]); - outbuf[SHA256_BLOCK_SIZE] = 0; - dev_dbg(device, "Loaded FW: %s, sha256: %s\n", name, outbuf); - -out_free: - kfree(shash); - kfree(outbuf); - kfree(sha256buf); - crypto_free_shash(alg); + sha256(fw->data, fw->size, digest); + dev_dbg(device, "Loaded FW: %s, sha256: %*phN\n", + name, SHA256_DIGEST_SIZE, digest); } #else static void fw_log_firmware_info(const struct firmware *fw, const char *name, From ec18d5c41e01c9833cf12ad97be76981301bb956 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 21 May 2025 11:29:34 +0200 Subject: [PATCH 15/17] drivers: hv: fix up const issue with vmbus_chan_bin_attrs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 9bec944506fa ("sysfs: constify attribute_group::bin_attrs"), the bin_attributes are now required to be const. Due to merge issues, the original commit could not modify this structure (it came in through a different branch.) Fix this up now by setting the variable properly. Cc: Thomas Weißschuh Cc: Naman Jain Fixes: 9bec944506fa ("sysfs: constify attribute_group::bin_attrs") Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index e3d51a316316..d74adb5bba44 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1841,7 +1841,7 @@ static struct attribute *vmbus_chan_attrs[] = { NULL }; -static struct bin_attribute *vmbus_chan_bin_attrs[] = { +static const struct bin_attribute *vmbus_chan_bin_attrs[] = { &chan_attr_ring_buffer, NULL }; From 282582820ed7f60addd15223674fd6b99251e233 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 20 May 2025 20:28:55 +1000 Subject: [PATCH 16/17] Documentation: embargoed-hardware-issues.rst: Remove myself I'm no longer able to perform this role since I left IBM. Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/8734czh8yg.fsf@mpe.ellerman.id.au Signed-off-by: Greg Kroah-Hartman --- Documentation/process/embargoed-hardware-issues.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/process/embargoed-hardware-issues.rst b/Documentation/process/embargoed-hardware-issues.rst index 0e19d2f0d6bb..da6bf0f6d01e 100644 --- a/Documentation/process/embargoed-hardware-issues.rst +++ b/Documentation/process/embargoed-hardware-issues.rst @@ -290,7 +290,6 @@ an involved disclosed party. The current ambassadors list: AMD Tom Lendacky Ampere Darren Hart ARM Catalin Marinas - IBM Power Michael Ellerman IBM Z Christian Borntraeger Intel Tony Luck Qualcomm Trilok Soni From 071d8e4c2a3b0999a9b822e2eb8854784a350f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Koutn=C3=BD?= Date: Mon, 5 May 2025 14:12:00 +0200 Subject: [PATCH 17/17] kernfs: Relax constraint in draining guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The active reference lifecycle provides the break/unbreak mechanism but the active reference is not truly active after unbreak -- callers don't use it afterwards but it's important for proper pairing of kn->active counting. Assuming this mechanism is in place, the WARN check in kernfs_should_drain_open_files() is too sensitive -- it may transiently catch those (rightful) callers between kernfs_unbreak_active_protection() and kernfs_put_active() as found out by Chen Ridong: kernfs_remove_by_name_ns kernfs_get_active // active=1 __kernfs_remove // active=0x80000002 kernfs_drain ... wait_event //waiting (active == 0x80000001) kernfs_break_active_protection // active = 0x80000001 // continue kernfs_unbreak_active_protection // active = 0x80000002 ... kernfs_should_drain_open_files // warning occurs kernfs_put_active To avoid the false positives (mind panic_on_warn) remove the check altogether. (This is meant as quick fix, I think active reference break/unbreak may be simplified with larger rework.) Fixes: bdb2fd7fc56e1 ("kernfs: Skip kernfs_drain_open_files() more aggressively") Link: https://lore.kernel.org/r/kmmrseckjctb4gxcx2rdminrjnq2b4ipf7562nvfd432ld5v5m@2byj5eedkb2o/ Cc: Chen Ridong Signed-off-by: Michal Koutný Acked-by: Tejun Heo Link: https://lore.kernel.org/r/20250505121201.879823-1-mkoutny@suse.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 5 +++-- fs/kernfs/file.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index d63a96786c9b..a670ba3e565e 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -1582,8 +1582,9 @@ void kernfs_break_active_protection(struct kernfs_node *kn) * invoked before finishing the kernfs operation. Note that while this * function restores the active reference, it doesn't and can't actually * restore the active protection - @kn may already or be in the process of - * being removed. Once kernfs_break_active_protection() is invoked, that - * protection is irreversibly gone for the kernfs operation instance. + * being drained and removed. Once kernfs_break_active_protection() is + * invoked, that protection is irreversibly gone for the kernfs operation + * instance. * * While this function may be called at any point after * kernfs_break_active_protection() is invoked, its most useful location diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 66fe8fe41f06..a6c692cac616 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -778,8 +778,9 @@ bool kernfs_should_drain_open_files(struct kernfs_node *kn) /* * @kn being deactivated guarantees that @kn->attr.open can't change * beneath us making the lockless test below safe. + * Callers post kernfs_unbreak_active_protection may be counted in + * kn->active by now, do not WARN_ON because of them. */ - WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS); rcu_read_lock(); on = rcu_dereference(kn->attr.open);