Commit e5f0e38e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'driver-core-6.12-rc1' of...

Merge tag 'driver-core-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core

Pull driver core updates from Greg KH:
 "Here is a small set of patches for the driver core code for 6.12-rc1.

  This set is the one that caused the most delay on my side, due to lots
  of last-minute reports of problems in the async shutdown feature that
  was added. In the end, I've reverted all of the patches in that series
  so we are back to "normal" and the patch set is being reworked for the
  next merge window.

  Other than the async shutdown patches that were reverted, included in
  here are:

   - minor driver core cleanups

   - minor driver core bus and class api cleanups and simplifications
     for some callbacks

   - some const markings of structures

   - other even more minor cleanups

  All of these, including the last minute reverts, have been in
  linux-next, but all of the reports of problems in linux-next were
  before the reverts happened. After the reverts, all is good"

* tag 'driver-core-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (32 commits)
  Revert "driver core: don't always lock parent in shutdown"
  Revert "driver core: separate function to shutdown one device"
  Revert "driver core: shut down devices asynchronously"
  Revert "nvme-pci: Make driver prefer asynchronous shutdown"
  Revert "driver core: fix async device shutdown hang"
  driver core: fix async device shutdown hang
  driver core: attribute_container: Remove unused functions
  driver core: Trivially simplify ((struct device_private *)curr)->device->p to @curr
  devres: Correclty strip percpu address space of devm_free_percpu() argument
  driver core: Make parameter check consistent for API cluster device_(for_each|find)_child()
  bus: fsl-mc: make fsl_mc_bus_type const
  nvme-pci: Make driver prefer asynchronous shutdown
  driver core: shut down devices asynchronously
  driver core: separate function to shutdown one device
  driver core: don't always lock parent in shutdown
  platform: Make platform_bus_type constant
  driver core: class: Check namespace relevant parameters in class_register()
  driver:base:core: Adding a "Return:" line in comment for device_link_add()
  drivers/base: Introduce device_match_t for device finding APIs
  firmware_loader: Block path traversal
  ...
parents cb787f4a eb46cb32
...@@ -346,8 +346,7 @@ attribute_container_device_trigger_safe(struct device *dev, ...@@ -346,8 +346,7 @@ attribute_container_device_trigger_safe(struct device *dev,
* @fn: the function to execute for each classdev. * @fn: the function to execute for each classdev.
* *
* This function is for executing a trigger when you need to know both * This function is for executing a trigger when you need to know both
* the container and the classdev. If you only care about the * the container and the classdev.
* container, then use attribute_container_trigger() instead.
*/ */
void void
attribute_container_device_trigger(struct device *dev, attribute_container_device_trigger(struct device *dev,
...@@ -378,33 +377,6 @@ attribute_container_device_trigger(struct device *dev, ...@@ -378,33 +377,6 @@ attribute_container_device_trigger(struct device *dev,
mutex_unlock(&attribute_container_mutex); mutex_unlock(&attribute_container_mutex);
} }
/**
* attribute_container_trigger - trigger a function for each matching container
*
* @dev: The generic device to activate the trigger for
* @fn: the function to trigger
*
* This routine triggers a function that only needs to know the
* matching containers (not the classdev) associated with a device.
* It is more lightweight than attribute_container_device_trigger, so
* should be used in preference unless the triggering function
* actually needs to know the classdev.
*/
void
attribute_container_trigger(struct device *dev,
int (*fn)(struct attribute_container *,
struct device *))
{
struct attribute_container *cont;
mutex_lock(&attribute_container_mutex);
list_for_each_entry(cont, &attribute_container_list, node) {
if (cont->match(cont, dev))
fn(cont, dev);
}
mutex_unlock(&attribute_container_mutex);
}
/** /**
* attribute_container_add_attrs - add attributes * attribute_container_add_attrs - add attributes
* *
...@@ -458,24 +430,6 @@ attribute_container_add_class_device(struct device *classdev) ...@@ -458,24 +430,6 @@ attribute_container_add_class_device(struct device *classdev)
return attribute_container_add_attrs(classdev); return attribute_container_add_attrs(classdev);
} }
/**
* attribute_container_add_class_device_adapter - simple adapter for triggers
*
* @cont: the container to register.
* @dev: the generic device to activate the trigger for
* @classdev: the class device to add
*
* This function is identical to attribute_container_add_class_device except
* that it is designed to be called from the triggers
*/
int
attribute_container_add_class_device_adapter(struct attribute_container *cont,
struct device *dev,
struct device *classdev)
{
return attribute_container_add_class_device(classdev);
}
/** /**
* attribute_container_remove_attrs - remove any attribute files * attribute_container_remove_attrs - remove any attribute files
* *
......
...@@ -352,7 +352,7 @@ EXPORT_SYMBOL_GPL(__auxiliary_device_add); ...@@ -352,7 +352,7 @@ EXPORT_SYMBOL_GPL(__auxiliary_device_add);
*/ */
struct auxiliary_device *auxiliary_find_device(struct device *start, struct auxiliary_device *auxiliary_find_device(struct device *start,
const void *data, const void *data,
int (*match)(struct device *dev, const void *data)) device_match_t match)
{ {
struct device *dev; struct device *dev;
......
...@@ -145,7 +145,7 @@ void auxiliary_bus_init(void); ...@@ -145,7 +145,7 @@ void auxiliary_bus_init(void);
static inline void auxiliary_bus_init(void) { } static inline void auxiliary_bus_init(void) { }
#endif #endif
struct kobject *virtual_device_parent(struct device *dev); struct kobject *virtual_device_parent(void);
int bus_add_device(struct device *dev); int bus_add_device(struct device *dev);
void bus_probe_device(struct device *dev); void bus_probe_device(struct device *dev);
......
...@@ -152,7 +152,8 @@ static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr, ...@@ -152,7 +152,8 @@ static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,
{ {
struct bus_attribute *bus_attr = to_bus_attr(attr); struct bus_attribute *bus_attr = to_bus_attr(attr);
struct subsys_private *subsys_priv = to_subsys_private(kobj); struct subsys_private *subsys_priv = to_subsys_private(kobj);
ssize_t ret = 0; /* return -EIO for reading a bus attribute without show() */
ssize_t ret = -EIO;
if (bus_attr->show) if (bus_attr->show)
ret = bus_attr->show(subsys_priv->bus, buf); ret = bus_attr->show(subsys_priv->bus, buf);
...@@ -164,7 +165,8 @@ static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr, ...@@ -164,7 +165,8 @@ static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
{ {
struct bus_attribute *bus_attr = to_bus_attr(attr); struct bus_attribute *bus_attr = to_bus_attr(attr);
struct subsys_private *subsys_priv = to_subsys_private(kobj); struct subsys_private *subsys_priv = to_subsys_private(kobj);
ssize_t ret = 0; /* return -EIO for writing a bus attribute without store() */
ssize_t ret = -EIO;
if (bus_attr->store) if (bus_attr->store)
ret = bus_attr->store(subsys_priv->bus, buf, count); ret = bus_attr->store(subsys_priv->bus, buf, count);
...@@ -389,7 +391,7 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev); ...@@ -389,7 +391,7 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev);
*/ */
struct device *bus_find_device(const struct bus_type *bus, struct device *bus_find_device(const struct bus_type *bus,
struct device *start, const void *data, struct device *start, const void *data,
int (*match)(struct device *dev, const void *data)) device_match_t match)
{ {
struct subsys_private *sp = bus_to_subsys(bus); struct subsys_private *sp = bus_to_subsys(bus);
struct klist_iter i; struct klist_iter i;
...@@ -920,6 +922,8 @@ int bus_register(const struct bus_type *bus) ...@@ -920,6 +922,8 @@ int bus_register(const struct bus_type *bus)
bus_remove_file(bus, &bus_attr_uevent); bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail: bus_uevent_fail:
kset_unregister(&priv->subsys); kset_unregister(&priv->subsys);
/* Above kset_unregister() will kfree @priv */
priv = NULL;
out: out:
kfree(priv); kfree(priv);
return retval; return retval;
...@@ -1294,7 +1298,7 @@ int subsys_virtual_register(const struct bus_type *subsys, ...@@ -1294,7 +1298,7 @@ int subsys_virtual_register(const struct bus_type *subsys,
{ {
struct kobject *virtual_dir; struct kobject *virtual_dir;
virtual_dir = virtual_device_parent(NULL); virtual_dir = virtual_device_parent();
if (!virtual_dir) if (!virtual_dir)
return -ENOMEM; return -ENOMEM;
...@@ -1385,8 +1389,13 @@ int __init buses_init(void) ...@@ -1385,8 +1389,13 @@ int __init buses_init(void)
return -ENOMEM; return -ENOMEM;
system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
if (!system_kset) if (!system_kset) {
/* Do error handling here as devices_init() do */
kset_unregister(bus_kset);
bus_kset = NULL;
pr_err("%s: failed to create and add kset 'bus'\n", __func__);
return -ENOMEM; return -ENOMEM;
}
return 0; return 0;
} }
...@@ -183,6 +183,17 @@ int class_register(const struct class *cls) ...@@ -183,6 +183,17 @@ int class_register(const struct class *cls)
pr_debug("device class '%s': registering\n", cls->name); pr_debug("device class '%s': registering\n", cls->name);
if (cls->ns_type && !cls->namespace) {
pr_err("%s: class '%s' does not have namespace\n",
__func__, cls->name);
return -EINVAL;
}
if (!cls->ns_type && cls->namespace) {
pr_err("%s: class '%s' does not have ns_type\n",
__func__, cls->name);
return -EINVAL;
}
cp = kzalloc(sizeof(*cp), GFP_KERNEL); cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp) if (!cp)
return -ENOMEM; return -ENOMEM;
...@@ -433,8 +444,7 @@ EXPORT_SYMBOL_GPL(class_for_each_device); ...@@ -433,8 +444,7 @@ EXPORT_SYMBOL_GPL(class_for_each_device);
* code. There's no locking restriction. * code. There's no locking restriction.
*/ */
struct device *class_find_device(const struct class *class, const struct device *start, struct device *class_find_device(const struct class *class, const struct device *start,
const void *data, const void *data, device_match_t match)
int (*match)(struct device *, const void *))
{ {
struct subsys_private *sp = class_to_subsys(class); struct subsys_private *sp = class_to_subsys(class);
struct class_dev_iter iter; struct class_dev_iter iter;
......
...@@ -9,29 +9,30 @@ ...@@ -9,29 +9,30 @@
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/blkdev.h>
#include <linux/cleanup.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-map-ops.h> /* for dma_default_coherent */
#include <linux/err.h> #include <linux/err.h>
#include <linux/fwnode.h> #include <linux/fwnode.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kdev_t.h>
#include <linux/kstrtox.h> #include <linux/kstrtox.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/mutex.h>
#include <linux/kdev_t.h> #include <linux/netdevice.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/netdevice.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/sched/signal.h>
#include <linux/sched/mm.h> #include <linux/sched/mm.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/string_helpers.h> #include <linux/string_helpers.h>
#include <linux/swiotlb.h> #include <linux/swiotlb.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/dma-map-ops.h> /* for dma_default_coherent */
#include "base.h" #include "base.h"
#include "physical_location.h" #include "physical_location.h"
...@@ -97,12 +98,9 @@ static int __fwnode_link_add(struct fwnode_handle *con, ...@@ -97,12 +98,9 @@ static int __fwnode_link_add(struct fwnode_handle *con,
int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup, int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup,
u8 flags) u8 flags)
{ {
int ret; guard(mutex)(&fwnode_link_lock);
mutex_lock(&fwnode_link_lock); return __fwnode_link_add(con, sup, flags);
ret = __fwnode_link_add(con, sup, flags);
mutex_unlock(&fwnode_link_lock);
return ret;
} }
/** /**
...@@ -143,10 +141,10 @@ static void fwnode_links_purge_suppliers(struct fwnode_handle *fwnode) ...@@ -143,10 +141,10 @@ static void fwnode_links_purge_suppliers(struct fwnode_handle *fwnode)
{ {
struct fwnode_link *link, *tmp; struct fwnode_link *link, *tmp;
mutex_lock(&fwnode_link_lock); guard(mutex)(&fwnode_link_lock);
list_for_each_entry_safe(link, tmp, &fwnode->suppliers, c_hook) list_for_each_entry_safe(link, tmp, &fwnode->suppliers, c_hook)
__fwnode_link_del(link); __fwnode_link_del(link);
mutex_unlock(&fwnode_link_lock);
} }
/** /**
...@@ -159,10 +157,10 @@ static void fwnode_links_purge_consumers(struct fwnode_handle *fwnode) ...@@ -159,10 +157,10 @@ static void fwnode_links_purge_consumers(struct fwnode_handle *fwnode)
{ {
struct fwnode_link *link, *tmp; struct fwnode_link *link, *tmp;
mutex_lock(&fwnode_link_lock); guard(mutex)(&fwnode_link_lock);
list_for_each_entry_safe(link, tmp, &fwnode->consumers, s_hook) list_for_each_entry_safe(link, tmp, &fwnode->consumers, s_hook)
__fwnode_link_del(link); __fwnode_link_del(link);
mutex_unlock(&fwnode_link_lock);
} }
/** /**
...@@ -563,20 +561,11 @@ static struct class devlink_class = { ...@@ -563,20 +561,11 @@ static struct class devlink_class = {
static int devlink_add_symlinks(struct device *dev) static int devlink_add_symlinks(struct device *dev)
{ {
char *buf_con __free(kfree) = NULL, *buf_sup __free(kfree) = NULL;
int ret; int ret;
size_t len;
struct device_link *link = to_devlink(dev); struct device_link *link = to_devlink(dev);
struct device *sup = link->supplier; struct device *sup = link->supplier;
struct device *con = link->consumer; struct device *con = link->consumer;
char *buf;
len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)),
strlen(dev_bus_name(con)) + strlen(dev_name(con)));
len += strlen(":");
len += strlen("supplier:") + 1;
buf = kzalloc(len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = sysfs_create_link(&link->link_dev.kobj, &sup->kobj, "supplier"); ret = sysfs_create_link(&link->link_dev.kobj, &sup->kobj, "supplier");
if (ret) if (ret)
...@@ -586,58 +575,64 @@ static int devlink_add_symlinks(struct device *dev) ...@@ -586,58 +575,64 @@ static int devlink_add_symlinks(struct device *dev)
if (ret) if (ret)
goto err_con; goto err_con;
snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con)); buf_con = kasprintf(GFP_KERNEL, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf); if (!buf_con) {
ret = -ENOMEM;
goto err_con_dev;
}
ret = sysfs_create_link(&sup->kobj, &link->link_dev.kobj, buf_con);
if (ret) if (ret)
goto err_con_dev; goto err_con_dev;
snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup)); buf_sup = kasprintf(GFP_KERNEL, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup));
ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf); if (!buf_sup) {
ret = -ENOMEM;
goto err_sup_dev;
}
ret = sysfs_create_link(&con->kobj, &link->link_dev.kobj, buf_sup);
if (ret) if (ret)
goto err_sup_dev; goto err_sup_dev;
goto out; goto out;
err_sup_dev: err_sup_dev:
snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con)); sysfs_remove_link(&sup->kobj, buf_con);
sysfs_remove_link(&sup->kobj, buf);
err_con_dev: err_con_dev:
sysfs_remove_link(&link->link_dev.kobj, "consumer"); sysfs_remove_link(&link->link_dev.kobj, "consumer");
err_con: err_con:
sysfs_remove_link(&link->link_dev.kobj, "supplier"); sysfs_remove_link(&link->link_dev.kobj, "supplier");
out: out:
kfree(buf);
return ret; return ret;
} }
static void devlink_remove_symlinks(struct device *dev) static void devlink_remove_symlinks(struct device *dev)
{ {
char *buf_con __free(kfree) = NULL, *buf_sup __free(kfree) = NULL;
struct device_link *link = to_devlink(dev); struct device_link *link = to_devlink(dev);
size_t len;
struct device *sup = link->supplier; struct device *sup = link->supplier;
struct device *con = link->consumer; struct device *con = link->consumer;
char *buf;
sysfs_remove_link(&link->link_dev.kobj, "consumer"); sysfs_remove_link(&link->link_dev.kobj, "consumer");
sysfs_remove_link(&link->link_dev.kobj, "supplier"); sysfs_remove_link(&link->link_dev.kobj, "supplier");
len = max(strlen(dev_bus_name(sup)) + strlen(dev_name(sup)),
strlen(dev_bus_name(con)) + strlen(dev_name(con)));
len += strlen(":");
len += strlen("supplier:") + 1;
buf = kzalloc(len, GFP_KERNEL);
if (!buf) {
WARN(1, "Unable to properly free device link symlinks!\n");
return;
}
if (device_is_registered(con)) { if (device_is_registered(con)) {
snprintf(buf, len, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup)); buf_sup = kasprintf(GFP_KERNEL, "supplier:%s:%s", dev_bus_name(sup), dev_name(sup));
sysfs_remove_link(&con->kobj, buf); if (!buf_sup)
goto out;
sysfs_remove_link(&con->kobj, buf_sup);
} }
snprintf(buf, len, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
sysfs_remove_link(&sup->kobj, buf); buf_con = kasprintf(GFP_KERNEL, "consumer:%s:%s", dev_bus_name(con), dev_name(con));
kfree(buf); if (!buf_con)
goto out;
sysfs_remove_link(&sup->kobj, buf_con);
return;
out:
WARN(1, "Unable to properly free device link symlinks!\n");
} }
static struct class_interface devlink_class_intf = { static struct class_interface devlink_class_intf = {
...@@ -678,6 +673,9 @@ postcore_initcall(devlink_class_init); ...@@ -678,6 +673,9 @@ postcore_initcall(devlink_class_init);
* @supplier: Supplier end of the link. * @supplier: Supplier end of the link.
* @flags: Link flags. * @flags: Link flags.
* *
* Return: On success, a device_link struct will be returned.
* On error or invalid flag settings, NULL will be returned.
*
* The caller is responsible for the proper synchronization of the link creation * The caller is responsible for the proper synchronization of the link creation
* with runtime PM. First, setting the DL_FLAG_PM_RUNTIME flag will cause the * with runtime PM. First, setting the DL_FLAG_PM_RUNTIME flag will cause the
* runtime PM framework to take the link into account. Second, if the * runtime PM framework to take the link into account. Second, if the
...@@ -1061,20 +1059,16 @@ int device_links_check_suppliers(struct device *dev) ...@@ -1061,20 +1059,16 @@ int device_links_check_suppliers(struct device *dev)
* Device waiting for supplier to become available is not allowed to * Device waiting for supplier to become available is not allowed to
* probe. * probe.
*/ */
mutex_lock(&fwnode_link_lock); scoped_guard(mutex, &fwnode_link_lock) {
sup_fw = fwnode_links_check_suppliers(dev->fwnode); sup_fw = fwnode_links_check_suppliers(dev->fwnode);
if (sup_fw) { if (sup_fw) {
if (!dev_is_best_effort(dev)) { if (dev_is_best_effort(dev))
fwnode_ret = -EPROBE_DEFER; fwnode_ret = -EAGAIN;
dev_err_probe(dev, -EPROBE_DEFER, else
"wait for supplier %pfwf\n", sup_fw); return dev_err_probe(dev, -EPROBE_DEFER,
} else { "wait for supplier %pfwf\n", sup_fw);
fwnode_ret = -EAGAIN;
} }
} }
mutex_unlock(&fwnode_link_lock);
if (fwnode_ret == -EPROBE_DEFER)
return fwnode_ret;
device_links_write_lock(); device_links_write_lock();
...@@ -1093,10 +1087,8 @@ int device_links_check_suppliers(struct device *dev) ...@@ -1093,10 +1087,8 @@ int device_links_check_suppliers(struct device *dev)
} }
device_links_missing_supplier(dev); device_links_missing_supplier(dev);
dev_err_probe(dev, -EPROBE_DEFER, ret = dev_err_probe(dev, -EPROBE_DEFER,
"supplier %s not ready\n", "supplier %s not ready\n", dev_name(link->supplier));
dev_name(link->supplier));
ret = -EPROBE_DEFER;
break; break;
} }
WRITE_ONCE(link->status, DL_STATE_CONSUMER_PROBE); WRITE_ONCE(link->status, DL_STATE_CONSUMER_PROBE);
...@@ -1249,9 +1241,8 @@ static ssize_t waiting_for_supplier_show(struct device *dev, ...@@ -1249,9 +1241,8 @@ static ssize_t waiting_for_supplier_show(struct device *dev,
bool val; bool val;
device_lock(dev); device_lock(dev);
mutex_lock(&fwnode_link_lock); scoped_guard(mutex, &fwnode_link_lock)
val = !!fwnode_links_check_suppliers(dev->fwnode); val = !!fwnode_links_check_suppliers(dev->fwnode);
mutex_unlock(&fwnode_link_lock);
device_unlock(dev); device_unlock(dev);
return sysfs_emit(buf, "%u\n", val); return sysfs_emit(buf, "%u\n", val);
} }
...@@ -1324,13 +1315,15 @@ void device_links_driver_bound(struct device *dev) ...@@ -1324,13 +1315,15 @@ void device_links_driver_bound(struct device *dev)
*/ */
if (dev->fwnode && dev->fwnode->dev == dev) { if (dev->fwnode && dev->fwnode->dev == dev) {
struct fwnode_handle *child; struct fwnode_handle *child;
fwnode_links_purge_suppliers(dev->fwnode); fwnode_links_purge_suppliers(dev->fwnode);
mutex_lock(&fwnode_link_lock);
guard(mutex)(&fwnode_link_lock);
fwnode_for_each_available_child_node(dev->fwnode, child) fwnode_for_each_available_child_node(dev->fwnode, child)
__fw_devlink_pickup_dangling_consumers(child, __fw_devlink_pickup_dangling_consumers(child,
dev->fwnode); dev->fwnode);
__fw_devlink_link_to_consumers(dev); __fw_devlink_link_to_consumers(dev);
mutex_unlock(&fwnode_link_lock);
} }
device_remove_file(dev, &dev_attr_waiting_for_supplier); device_remove_file(dev, &dev_attr_waiting_for_supplier);
...@@ -2339,10 +2332,10 @@ static void fw_devlink_link_device(struct device *dev) ...@@ -2339,10 +2332,10 @@ static void fw_devlink_link_device(struct device *dev)
fw_devlink_parse_fwtree(fwnode); fw_devlink_parse_fwtree(fwnode);
mutex_lock(&fwnode_link_lock); guard(mutex)(&fwnode_link_lock);
__fw_devlink_link_to_consumers(dev); __fw_devlink_link_to_consumers(dev);
__fw_devlink_link_to_suppliers(dev, fwnode); __fw_devlink_link_to_suppliers(dev, fwnode);
mutex_unlock(&fwnode_link_lock);
} }
/* Device links support end. */ /* Device links support end. */
...@@ -2591,7 +2584,7 @@ static const void *device_namespace(const struct kobject *kobj) ...@@ -2591,7 +2584,7 @@ static const void *device_namespace(const struct kobject *kobj)
const struct device *dev = kobj_to_dev(kobj); const struct device *dev = kobj_to_dev(kobj);
const void *ns = NULL; const void *ns = NULL;
if (dev->class && dev->class->ns_type) if (dev->class && dev->class->namespace)
ns = dev->class->namespace(dev); ns = dev->class->namespace(dev);
return ns; return ns;
...@@ -3170,7 +3163,7 @@ void device_initialize(struct device *dev) ...@@ -3170,7 +3163,7 @@ void device_initialize(struct device *dev)
} }
EXPORT_SYMBOL_GPL(device_initialize); EXPORT_SYMBOL_GPL(device_initialize);
struct kobject *virtual_device_parent(struct device *dev) struct kobject *virtual_device_parent(void)
{ {
static struct kobject *virtual_dir = NULL; static struct kobject *virtual_dir = NULL;
...@@ -3248,7 +3241,7 @@ static struct kobject *get_device_parent(struct device *dev, ...@@ -3248,7 +3241,7 @@ static struct kobject *get_device_parent(struct device *dev,
* in a "glue" directory to prevent namespace collisions. * in a "glue" directory to prevent namespace collisions.
*/ */
if (parent == NULL) if (parent == NULL)
parent_kobj = virtual_device_parent(dev); parent_kobj = virtual_device_parent();
else if (parent->class && !dev->class->ns_type) { else if (parent->class && !dev->class->ns_type) {
subsys_put(sp); subsys_put(sp);
return &parent->kobj; return &parent->kobj;
...@@ -4003,7 +3996,7 @@ int device_for_each_child(struct device *parent, void *data, ...@@ -4003,7 +3996,7 @@ int device_for_each_child(struct device *parent, void *data,
struct device *child; struct device *child;
int error = 0; int error = 0;
if (!parent->p) if (!parent || !parent->p)
return 0; return 0;
klist_iter_init(&parent->p->klist_children, &i); klist_iter_init(&parent->p->klist_children, &i);
...@@ -4033,7 +4026,7 @@ int device_for_each_child_reverse(struct device *parent, void *data, ...@@ -4033,7 +4026,7 @@ int device_for_each_child_reverse(struct device *parent, void *data,
struct device *child; struct device *child;
int error = 0; int error = 0;
if (!parent->p) if (!parent || !parent->p)
return 0; return 0;
klist_iter_init(&parent->p->klist_children, &i); klist_iter_init(&parent->p->klist_children, &i);
...@@ -4067,7 +4060,7 @@ struct device *device_find_child(struct device *parent, void *data, ...@@ -4067,7 +4060,7 @@ struct device *device_find_child(struct device *parent, void *data,
struct klist_iter i; struct klist_iter i;
struct device *child; struct device *child;
if (!parent) if (!parent || !parent->p)
return NULL; return NULL;
klist_iter_init(&parent->p->klist_children, &i); klist_iter_init(&parent->p->klist_children, &i);
...@@ -4515,9 +4508,11 @@ EXPORT_SYMBOL_GPL(device_destroy); ...@@ -4515,9 +4508,11 @@ EXPORT_SYMBOL_GPL(device_destroy);
*/ */
int device_rename(struct device *dev, const char *new_name) int device_rename(struct device *dev, const char *new_name)
{ {
struct subsys_private *sp = NULL;
struct kobject *kobj = &dev->kobj; struct kobject *kobj = &dev->kobj;
char *old_device_name = NULL; char *old_device_name = NULL;
int error; int error;
bool is_link_renamed = false;
dev = get_device(dev); dev = get_device(dev);
if (!dev) if (!dev)
...@@ -4532,7 +4527,7 @@ int device_rename(struct device *dev, const char *new_name) ...@@ -4532,7 +4527,7 @@ int device_rename(struct device *dev, const char *new_name)
} }
if (dev->class) { if (dev->class) {
struct subsys_private *sp = class_to_subsys(dev->class); sp = class_to_subsys(dev->class);
if (!sp) { if (!sp) {
error = -EINVAL; error = -EINVAL;
...@@ -4541,16 +4536,19 @@ int device_rename(struct device *dev, const char *new_name) ...@@ -4541,16 +4536,19 @@ int device_rename(struct device *dev, const char *new_name)
error = sysfs_rename_link_ns(&sp->subsys.kobj, kobj, old_device_name, error = sysfs_rename_link_ns(&sp->subsys.kobj, kobj, old_device_name,
new_name, kobject_namespace(kobj)); new_name, kobject_namespace(kobj));
subsys_put(sp);
if (error) if (error)
goto out; goto out;
is_link_renamed = true;
} }
error = kobject_rename(kobj, new_name); error = kobject_rename(kobj, new_name);
if (error)
goto out;
out: out:
if (error && is_link_renamed)
sysfs_rename_link_ns(&sp->subsys.kobj, kobj, new_name,
old_device_name, kobject_namespace(kobj));
subsys_put(sp);
put_device(dev); put_device(dev);
kfree(old_device_name); kfree(old_device_name);
...@@ -4872,7 +4870,7 @@ set_dev_info(const struct device *dev, struct dev_printk_info *dev_info) ...@@ -4872,7 +4870,7 @@ set_dev_info(const struct device *dev, struct dev_printk_info *dev_info)
else else
return; return;
strscpy(dev_info->subsystem, subsys, sizeof(dev_info->subsystem)); strscpy(dev_info->subsystem, subsys);
/* /*
* Add device identifier DEVICE=: * Add device identifier DEVICE=:
......
...@@ -248,7 +248,7 @@ static int deferred_devs_show(struct seq_file *s, void *data) ...@@ -248,7 +248,7 @@ static int deferred_devs_show(struct seq_file *s, void *data)
list_for_each_entry(curr, &deferred_probe_pending_list, deferred_probe) list_for_each_entry(curr, &deferred_probe_pending_list, deferred_probe)
seq_printf(s, "%s\t%s", dev_name(curr->device), seq_printf(s, "%s\t%s", dev_name(curr->device),
curr->device->p->deferred_probe_reason ?: "\n"); curr->deferred_probe_reason ?: "\n");
mutex_unlock(&deferred_probe_mutex); mutex_unlock(&deferred_probe_mutex);
......
...@@ -1231,6 +1231,6 @@ void devm_free_percpu(struct device *dev, void __percpu *pdata) ...@@ -1231,6 +1231,6 @@ void devm_free_percpu(struct device *dev, void __percpu *pdata)
* devm_free_pages() does. * devm_free_pages() does.
*/ */
WARN_ON(devres_release(dev, devm_percpu_release, devm_percpu_match, WARN_ON(devres_release(dev, devm_percpu_release, devm_percpu_match,
(__force void *)pdata)); (void *)(__force unsigned long)pdata));
} }
EXPORT_SYMBOL_GPL(devm_free_percpu); EXPORT_SYMBOL_GPL(devm_free_percpu);
...@@ -150,7 +150,7 @@ EXPORT_SYMBOL_GPL(driver_for_each_device); ...@@ -150,7 +150,7 @@ EXPORT_SYMBOL_GPL(driver_for_each_device);
*/ */
struct device *driver_find_device(const struct device_driver *drv, struct device *driver_find_device(const struct device_driver *drv,
struct device *start, const void *data, struct device *start, const void *data,
int (*match)(struct device *dev, const void *data)) device_match_t match)
{ {
struct klist_iter i; struct klist_iter i;
struct device *dev; struct device *dev;
......
...@@ -849,6 +849,26 @@ static void fw_log_firmware_info(const struct firmware *fw, const char *name, ...@@ -849,6 +849,26 @@ static void fw_log_firmware_info(const struct firmware *fw, const char *name,
{} {}
#endif #endif
/*
* Reject firmware file names with ".." path components.
* There are drivers that construct firmware file names from device-supplied
* strings, and we don't want some device to be able to tell us "I would like to
* be sent my firmware from ../../../etc/shadow, please".
*
* Search for ".." surrounded by either '/' or start/end of string.
*
* This intentionally only looks at the firmware name, not at the firmware base
* directory or at symlink contents.
*/
static bool name_contains_dotdot(const char *name)
{
size_t name_len = strlen(name);
return strcmp(name, "..") == 0 || strncmp(name, "../", 3) == 0 ||
strstr(name, "/../") != NULL ||
(name_len >= 3 && strcmp(name+name_len-3, "/..") == 0);
}
/* called from request_firmware() and request_firmware_work_func() */ /* called from request_firmware() and request_firmware_work_func() */
static int static int
_request_firmware(const struct firmware **firmware_p, const char *name, _request_firmware(const struct firmware **firmware_p, const char *name,
...@@ -869,6 +889,14 @@ _request_firmware(const struct firmware **firmware_p, const char *name, ...@@ -869,6 +889,14 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
goto out; goto out;
} }
if (name_contains_dotdot(name)) {
dev_warn(device,
"Firmware load for '%s' refused, path contains '..' component\n",
name);
ret = -EINVAL;
goto out;
}
ret = _request_firmware_prepare(&fw, name, device, buf, size, ret = _request_firmware_prepare(&fw, name, device, buf, size,
offset, opt_flags); offset, opt_flags);
if (ret <= 0) /* error or already assigned */ if (ret <= 0) /* error or already assigned */
...@@ -946,6 +974,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name, ...@@ -946,6 +974,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
* @name will be used as $FIRMWARE in the uevent environment and * @name will be used as $FIRMWARE in the uevent environment and
* should be distinctive enough not to be confused with any other * should be distinctive enough not to be confused with any other
* firmware image for this or any other device. * firmware image for this or any other device.
* It must not contain any ".." path components - "foo/bar..bin" is
* allowed, but "foo/../bar.bin" is not.
* *
* Caller must hold the reference count of @device. * Caller must hold the reference count of @device.
* *
......
...@@ -66,27 +66,31 @@ int module_add_driver(struct module *mod, const struct device_driver *drv) ...@@ -66,27 +66,31 @@ int module_add_driver(struct module *mod, const struct device_driver *drv)
driver_name = make_driver_name(drv); driver_name = make_driver_name(drv);
if (!driver_name) { if (!driver_name) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out_remove_kobj;
} }
module_create_drivers_dir(mk); module_create_drivers_dir(mk);
if (!mk->drivers_dir) { if (!mk->drivers_dir) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out_free_driver_name;
} }
ret = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, driver_name); ret = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, driver_name);
if (ret) if (ret)
goto out; goto out_remove_drivers_dir;
kfree(driver_name); kfree(driver_name);
return 0; return 0;
out:
sysfs_remove_link(&drv->p->kobj, "module"); out_remove_drivers_dir:
sysfs_remove_link(mk->drivers_dir, driver_name); sysfs_remove_link(mk->drivers_dir, driver_name);
out_free_driver_name:
kfree(driver_name); kfree(driver_name);
out_remove_kobj:
sysfs_remove_link(&drv->p->kobj, "module");
return ret; return ret;
} }
......
...@@ -1474,7 +1474,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = { ...@@ -1474,7 +1474,7 @@ static const struct dev_pm_ops platform_dev_pm_ops = {
USE_PLATFORM_PM_SLEEP_OPS USE_PLATFORM_PM_SLEEP_OPS
}; };
struct bus_type platform_bus_type = { const struct bus_type platform_bus_type = {
.name = "platform", .name = "platform",
.dev_groups = platform_dev_groups, .dev_groups = platform_dev_groups,
.match = platform_match, .match = platform_match,
......
...@@ -309,7 +309,7 @@ static struct attribute *fsl_mc_bus_attrs[] = { ...@@ -309,7 +309,7 @@ static struct attribute *fsl_mc_bus_attrs[] = {
ATTRIBUTE_GROUPS(fsl_mc_bus); ATTRIBUTE_GROUPS(fsl_mc_bus);
struct bus_type fsl_mc_bus_type = { const struct bus_type fsl_mc_bus_type = {
.name = "fsl-mc", .name = "fsl-mc",
.match = fsl_mc_bus_match, .match = fsl_mc_bus_match,
.uevent = fsl_mc_bus_uevent, .uevent = fsl_mc_bus_uevent,
......
...@@ -61,14 +61,8 @@ int attribute_container_device_trigger_safe(struct device *dev, ...@@ -61,14 +61,8 @@ int attribute_container_device_trigger_safe(struct device *dev,
int (*undo)(struct attribute_container *, int (*undo)(struct attribute_container *,
struct device *, struct device *,
struct device *)); struct device *));
void attribute_container_trigger(struct device *dev,
int (*fn)(struct attribute_container *,
struct device *));
int attribute_container_add_attrs(struct device *classdev); int attribute_container_add_attrs(struct device *classdev);
int attribute_container_add_class_device(struct device *classdev); int attribute_container_add_class_device(struct device *classdev);
int attribute_container_add_class_device_adapter(struct attribute_container *cont,
struct device *dev,
struct device *classdev);
void attribute_container_remove_attrs(struct device *classdev); void attribute_container_remove_attrs(struct device *classdev);
void attribute_container_class_device_del(struct device *classdev); void attribute_container_class_device_del(struct device *classdev);
struct attribute_container *attribute_container_classdev_to_container(struct device *); struct attribute_container *attribute_container_classdev_to_container(struct device *);
......
...@@ -271,6 +271,6 @@ void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv); ...@@ -271,6 +271,6 @@ void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv);
struct auxiliary_device *auxiliary_find_device(struct device *start, struct auxiliary_device *auxiliary_find_device(struct device *start,
const void *data, const void *data,
int (*match)(struct device *dev, const void *data)); device_match_t match);
#endif /* _AUXILIARY_BUS_H_ */ #endif /* _AUXILIARY_BUS_H_ */
...@@ -126,6 +126,9 @@ struct bus_attribute { ...@@ -126,6 +126,9 @@ struct bus_attribute {
int __must_check bus_create_file(const struct bus_type *bus, struct bus_attribute *attr); int __must_check bus_create_file(const struct bus_type *bus, struct bus_attribute *attr);
void bus_remove_file(const struct bus_type *bus, struct bus_attribute *attr); void bus_remove_file(const struct bus_type *bus, struct bus_attribute *attr);
/* Matching function type for drivers/base APIs to find a specific device */
typedef int (*device_match_t)(struct device *dev, const void *data);
/* Generic device matching functions that all busses can use to match with */ /* Generic device matching functions that all busses can use to match with */
int device_match_name(struct device *dev, const void *name); int device_match_name(struct device *dev, const void *name);
int device_match_of_node(struct device *dev, const void *np); int device_match_of_node(struct device *dev, const void *np);
...@@ -139,8 +142,7 @@ int device_match_any(struct device *dev, const void *unused); ...@@ -139,8 +142,7 @@ int device_match_any(struct device *dev, const void *unused);
int bus_for_each_dev(const struct bus_type *bus, struct device *start, void *data, int bus_for_each_dev(const struct bus_type *bus, struct device *start, void *data,
int (*fn)(struct device *dev, void *data)); int (*fn)(struct device *dev, void *data));
struct device *bus_find_device(const struct bus_type *bus, struct device *start, struct device *bus_find_device(const struct bus_type *bus, struct device *start,
const void *data, const void *data, device_match_t match);
int (*match)(struct device *dev, const void *data));
/** /**
* bus_find_device_by_name - device iterator for locating a particular device * bus_find_device_by_name - device iterator for locating a particular device
* of a specific name. * of a specific name.
......
...@@ -95,7 +95,7 @@ void class_dev_iter_exit(struct class_dev_iter *iter); ...@@ -95,7 +95,7 @@ void class_dev_iter_exit(struct class_dev_iter *iter);
int class_for_each_device(const struct class *class, const struct device *start, void *data, int class_for_each_device(const struct class *class, const struct device *start, void *data,
int (*fn)(struct device *dev, void *data)); int (*fn)(struct device *dev, void *data));
struct device *class_find_device(const struct class *class, const struct device *start, struct device *class_find_device(const struct class *class, const struct device *start,
const void *data, int (*match)(struct device *, const void *)); const void *data, device_match_t match);
/** /**
* class_find_device_by_name - device iterator for locating a particular device * class_find_device_by_name - device iterator for locating a particular device
......
...@@ -157,7 +157,7 @@ int __must_check driver_for_each_device(struct device_driver *drv, struct device ...@@ -157,7 +157,7 @@ int __must_check driver_for_each_device(struct device_driver *drv, struct device
void *data, int (*fn)(struct device *dev, void *)); void *data, int (*fn)(struct device *dev, void *));
struct device *driver_find_device(const struct device_driver *drv, struct device *driver_find_device(const struct device_driver *drv,
struct device *start, const void *data, struct device *start, const void *data,
int (*match)(struct device *dev, const void *data)); device_match_t match);
/** /**
* driver_find_device_by_name - device iterator for locating a particular device * driver_find_device_by_name - device iterator for locating a particular device
......
...@@ -436,7 +436,7 @@ void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev); ...@@ -436,7 +436,7 @@ void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev);
struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev, struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev,
u16 if_id); u16 if_id);
extern struct bus_type fsl_mc_bus_type; extern const struct bus_type fsl_mc_bus_type;
extern struct device_type fsl_mc_bus_dprc_type; extern struct device_type fsl_mc_bus_dprc_type;
extern struct device_type fsl_mc_bus_dpni_type; extern struct device_type fsl_mc_bus_dpni_type;
......
...@@ -52,7 +52,7 @@ struct platform_device { ...@@ -52,7 +52,7 @@ struct platform_device {
extern int platform_device_register(struct platform_device *); extern int platform_device_register(struct platform_device *);
extern void platform_device_unregister(struct platform_device *); extern void platform_device_unregister(struct platform_device *);
extern struct bus_type platform_bus_type; extern const struct bus_type platform_bus_type;
extern struct device platform_bus; extern struct device platform_bus;
extern struct resource *platform_get_resource(struct platform_device *, extern struct resource *platform_get_resource(struct platform_device *,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment