You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'driver-core-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core updates from Greg KH: "Here is the driver core / firmware changes for 4.2-rc1. A number of small changes all over the place in the driver core, and in the firmware subsystem. Nothing really major, full details in the shortlog. Some of it is a bit of churn, given that the platform driver probing changes was found to not work well, so they were reverted. All of these have been in linux-next for a while with no reported issues" * tag 'driver-core-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (31 commits) Revert "base/platform: Only insert MEM and IO resources" Revert "base/platform: Continue on insert_resource() error" Revert "of/platform: Use platform_device interface" Revert "base/platform: Remove code duplication" firmware: add missing kfree for work on async call fs: sysfs: don't pass count == 0 to bin file readers base:dd - Fix for typo in comment to function driver_deferred_probe_trigger(). base/platform: Remove code duplication of/platform: Use platform_device interface base/platform: Continue on insert_resource() error base/platform: Only insert MEM and IO resources firmware: use const for remaining firmware names firmware: fix possible use after free on name on asynchronous request firmware: check for file truncation on direct firmware loading firmware: fix __getname() missing failure check drivers: of/base: move of_init to driver_init drivers/base: cacheinfo: fix annoying typo when DT nodes are absent sysfs: disambiguate between "error code" and "failure" in comments driver-core: fix build for !CONFIG_MODULES driver-core: make __device_attach() static ...
This commit is contained in:
@@ -116,6 +116,7 @@ static inline int driver_match_device(struct device_driver *drv,
|
||||
{
|
||||
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
|
||||
}
|
||||
extern bool driver_allows_async_probing(struct device_driver *drv);
|
||||
|
||||
extern int driver_add_groups(struct device_driver *drv,
|
||||
const struct attribute_group **groups);
|
||||
|
||||
+23
-8
@@ -10,6 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/async.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
@@ -549,15 +550,12 @@ void bus_probe_device(struct device *dev)
|
||||
{
|
||||
struct bus_type *bus = dev->bus;
|
||||
struct subsys_interface *sif;
|
||||
int ret;
|
||||
|
||||
if (!bus)
|
||||
return;
|
||||
|
||||
if (bus->p->drivers_autoprobe) {
|
||||
ret = device_attach(dev);
|
||||
WARN_ON(ret < 0);
|
||||
}
|
||||
if (bus->p->drivers_autoprobe)
|
||||
device_initial_probe(dev);
|
||||
|
||||
mutex_lock(&bus->p->mutex);
|
||||
list_for_each_entry(sif, &bus->p->interfaces, node)
|
||||
@@ -659,6 +657,17 @@ static ssize_t uevent_store(struct device_driver *drv, const char *buf,
|
||||
}
|
||||
static DRIVER_ATTR_WO(uevent);
|
||||
|
||||
static void driver_attach_async(void *_drv, async_cookie_t cookie)
|
||||
{
|
||||
struct device_driver *drv = _drv;
|
||||
int ret;
|
||||
|
||||
ret = driver_attach(drv);
|
||||
|
||||
pr_debug("bus: '%s': driver %s async attach completed: %d\n",
|
||||
drv->bus->name, drv->name, ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* bus_add_driver - Add a driver to the bus.
|
||||
* @drv: driver.
|
||||
@@ -691,9 +700,15 @@ int bus_add_driver(struct device_driver *drv)
|
||||
|
||||
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
|
||||
if (drv->bus->p->drivers_autoprobe) {
|
||||
error = driver_attach(drv);
|
||||
if (error)
|
||||
goto out_unregister;
|
||||
if (driver_allows_async_probing(drv)) {
|
||||
pr_debug("bus: '%s': probing driver %s asynchronously\n",
|
||||
drv->bus->name, drv->name);
|
||||
async_schedule(driver_attach_async, drv);
|
||||
} else {
|
||||
error = driver_attach(drv);
|
||||
if (error)
|
||||
goto out_unregister;
|
||||
}
|
||||
}
|
||||
module_add_driver(drv->owner, drv);
|
||||
|
||||
|
||||
@@ -191,12 +191,12 @@ static int detect_cache_attributes(unsigned int cpu)
|
||||
if (ret)
|
||||
goto free_ci;
|
||||
/*
|
||||
* For systems using DT for cache hierarcy, of_node and shared_cpu_map
|
||||
* For systems using DT for cache hierarchy, of_node and shared_cpu_map
|
||||
* will be set up here only if they are not populated already
|
||||
*/
|
||||
ret = cache_shared_cpu_map_setup(cpu);
|
||||
if (ret) {
|
||||
pr_warn("Unable to detect cache hierarcy from DT for CPU %d\n",
|
||||
pr_warn("Unable to detect cache hierarchy from DT for CPU %d\n",
|
||||
cpu);
|
||||
goto free_ci;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/tick.h>
|
||||
|
||||
#include "base.h"
|
||||
|
||||
@@ -265,6 +266,30 @@ static ssize_t print_cpus_offline(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
|
||||
|
||||
static ssize_t print_cpus_isolated(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int n = 0, len = PAGE_SIZE-2;
|
||||
|
||||
n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(cpu_isolated_map));
|
||||
|
||||
return n;
|
||||
}
|
||||
static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL);
|
||||
|
||||
#ifdef CONFIG_NO_HZ_FULL
|
||||
static ssize_t print_cpus_nohz_full(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int n = 0, len = PAGE_SIZE-2;
|
||||
|
||||
n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
|
||||
|
||||
return n;
|
||||
}
|
||||
static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL);
|
||||
#endif
|
||||
|
||||
static void cpu_device_release(struct device *dev)
|
||||
{
|
||||
/*
|
||||
@@ -431,6 +456,10 @@ static struct attribute *cpu_root_attrs[] = {
|
||||
&cpu_attrs[2].attr.attr,
|
||||
&dev_attr_kernel_max.attr,
|
||||
&dev_attr_offline.attr,
|
||||
&dev_attr_isolated.attr,
|
||||
#ifdef CONFIG_NO_HZ_FULL
|
||||
&dev_attr_nohz_full.attr,
|
||||
#endif
|
||||
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
|
||||
&dev_attr_modalias.attr,
|
||||
#endif
|
||||
|
||||
+148
-25
@@ -141,7 +141,7 @@ static bool driver_deferred_probe_enable = false;
|
||||
* more than one device is probing at the same time, it is possible for one
|
||||
* probe to complete successfully while another is about to defer. If the second
|
||||
* depends on the first, then it will get put on the pending list after the
|
||||
* trigger event has already occured and will be stuck there.
|
||||
* trigger event has already occurred and will be stuck there.
|
||||
*
|
||||
* The atomic 'deferred_trigger_count' is used to determine if a successful
|
||||
* trigger has occurred in the midst of probing a driver. If the trigger count
|
||||
@@ -417,16 +417,152 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __device_attach(struct device_driver *drv, void *data)
|
||||
bool driver_allows_async_probing(struct device_driver *drv)
|
||||
{
|
||||
struct device *dev = data;
|
||||
switch (drv->probe_type) {
|
||||
case PROBE_PREFER_ASYNCHRONOUS:
|
||||
return true;
|
||||
|
||||
case PROBE_FORCE_SYNCHRONOUS:
|
||||
return false;
|
||||
|
||||
default:
|
||||
if (module_requested_async_probing(drv->owner))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct device_attach_data {
|
||||
struct device *dev;
|
||||
|
||||
/*
|
||||
* Indicates whether we are are considering asynchronous probing or
|
||||
* not. Only initial binding after device or driver registration
|
||||
* (including deferral processing) may be done asynchronously, the
|
||||
* rest is always synchronous, as we expect it is being done by
|
||||
* request from userspace.
|
||||
*/
|
||||
bool check_async;
|
||||
|
||||
/*
|
||||
* Indicates if we are binding synchronous or asynchronous drivers.
|
||||
* When asynchronous probing is enabled we'll execute 2 passes
|
||||
* over drivers: first pass doing synchronous probing and second
|
||||
* doing asynchronous probing (if synchronous did not succeed -
|
||||
* most likely because there was no driver requiring synchronous
|
||||
* probing - and we found asynchronous driver during first pass).
|
||||
* The 2 passes are done because we can't shoot asynchronous
|
||||
* probe for given device and driver from bus_for_each_drv() since
|
||||
* driver pointer is not guaranteed to stay valid once
|
||||
* bus_for_each_drv() iterates to the next driver on the bus.
|
||||
*/
|
||||
bool want_async;
|
||||
|
||||
/*
|
||||
* We'll set have_async to 'true' if, while scanning for matching
|
||||
* driver, we'll encounter one that requests asynchronous probing.
|
||||
*/
|
||||
bool have_async;
|
||||
};
|
||||
|
||||
static int __device_attach_driver(struct device_driver *drv, void *_data)
|
||||
{
|
||||
struct device_attach_data *data = _data;
|
||||
struct device *dev = data->dev;
|
||||
bool async_allowed;
|
||||
|
||||
/*
|
||||
* Check if device has already been claimed. This may
|
||||
* happen with driver loading, device discovery/registration,
|
||||
* and deferred probe processing happens all at once with
|
||||
* multiple threads.
|
||||
*/
|
||||
if (dev->driver)
|
||||
return -EBUSY;
|
||||
|
||||
if (!driver_match_device(drv, dev))
|
||||
return 0;
|
||||
|
||||
async_allowed = driver_allows_async_probing(drv);
|
||||
|
||||
if (async_allowed)
|
||||
data->have_async = true;
|
||||
|
||||
if (data->check_async && async_allowed != data->want_async)
|
||||
return 0;
|
||||
|
||||
return driver_probe_device(drv, dev);
|
||||
}
|
||||
|
||||
static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
|
||||
{
|
||||
struct device *dev = _dev;
|
||||
struct device_attach_data data = {
|
||||
.dev = dev,
|
||||
.check_async = true,
|
||||
.want_async = true,
|
||||
};
|
||||
|
||||
device_lock(dev);
|
||||
|
||||
bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
|
||||
dev_dbg(dev, "async probe completed\n");
|
||||
|
||||
pm_request_idle(dev);
|
||||
|
||||
device_unlock(dev);
|
||||
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
static int __device_attach(struct device *dev, bool allow_async)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
device_lock(dev);
|
||||
if (dev->driver) {
|
||||
if (klist_node_attached(&dev->p->knode_driver)) {
|
||||
ret = 1;
|
||||
goto out_unlock;
|
||||
}
|
||||
ret = device_bind_driver(dev);
|
||||
if (ret == 0)
|
||||
ret = 1;
|
||||
else {
|
||||
dev->driver = NULL;
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
struct device_attach_data data = {
|
||||
.dev = dev,
|
||||
.check_async = allow_async,
|
||||
.want_async = false,
|
||||
};
|
||||
|
||||
ret = bus_for_each_drv(dev->bus, NULL, &data,
|
||||
__device_attach_driver);
|
||||
if (!ret && allow_async && data.have_async) {
|
||||
/*
|
||||
* If we could not find appropriate driver
|
||||
* synchronously and we are allowed to do
|
||||
* async probes and there are drivers that
|
||||
* want to probe asynchronously, we'll
|
||||
* try them.
|
||||
*/
|
||||
dev_dbg(dev, "scheduling asynchronous probe\n");
|
||||
get_device(dev);
|
||||
async_schedule(__device_attach_async_helper, dev);
|
||||
} else {
|
||||
pm_request_idle(dev);
|
||||
}
|
||||
}
|
||||
out_unlock:
|
||||
device_unlock(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_attach - try to attach device to a driver.
|
||||
* @dev: device.
|
||||
@@ -443,31 +579,15 @@ static int __device_attach(struct device_driver *drv, void *data)
|
||||
*/
|
||||
int device_attach(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
device_lock(dev);
|
||||
if (dev->driver) {
|
||||
if (klist_node_attached(&dev->p->knode_driver)) {
|
||||
ret = 1;
|
||||
goto out_unlock;
|
||||
}
|
||||
ret = device_bind_driver(dev);
|
||||
if (ret == 0)
|
||||
ret = 1;
|
||||
else {
|
||||
dev->driver = NULL;
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
|
||||
pm_request_idle(dev);
|
||||
}
|
||||
out_unlock:
|
||||
device_unlock(dev);
|
||||
return ret;
|
||||
return __device_attach(dev, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_attach);
|
||||
|
||||
void device_initial_probe(struct device *dev)
|
||||
{
|
||||
__device_attach(dev, true);
|
||||
}
|
||||
|
||||
static int __driver_attach(struct device *dev, void *data)
|
||||
{
|
||||
struct device_driver *drv = data;
|
||||
@@ -522,6 +642,9 @@ static void __device_release_driver(struct device *dev)
|
||||
|
||||
drv = dev->driver;
|
||||
if (drv) {
|
||||
if (driver_allows_async_probing(drv))
|
||||
async_synchronize_full();
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
driver_sysfs_remove(dev);
|
||||
|
||||
@@ -150,17 +150,17 @@ struct firmware_buf {
|
||||
int page_array_size;
|
||||
struct list_head pending_list;
|
||||
#endif
|
||||
char fw_id[];
|
||||
const char *fw_id;
|
||||
};
|
||||
|
||||
struct fw_cache_entry {
|
||||
struct list_head list;
|
||||
char name[];
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct fw_name_devm {
|
||||
unsigned long magic;
|
||||
char name[];
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#define to_fwbuf(d) container_of(d, struct firmware_buf, ref)
|
||||
@@ -181,13 +181,17 @@ static struct firmware_buf *__allocate_fw_buf(const char *fw_name,
|
||||
{
|
||||
struct firmware_buf *buf;
|
||||
|
||||
buf = kzalloc(sizeof(*buf) + strlen(fw_name) + 1, GFP_ATOMIC);
|
||||
|
||||
buf = kzalloc(sizeof(*buf), GFP_ATOMIC);
|
||||
if (!buf)
|
||||
return buf;
|
||||
return NULL;
|
||||
|
||||
buf->fw_id = kstrdup_const(fw_name, GFP_ATOMIC);
|
||||
if (!buf->fw_id) {
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kref_init(&buf->ref);
|
||||
strcpy(buf->fw_id, fw_name);
|
||||
buf->fwc = fwc;
|
||||
init_completion(&buf->completion);
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
@@ -257,6 +261,7 @@ static void __fw_free_buf(struct kref *ref)
|
||||
} else
|
||||
#endif
|
||||
vfree(buf->data);
|
||||
kfree_const(buf->fw_id);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
@@ -320,9 +325,13 @@ fail:
|
||||
static int fw_get_filesystem_firmware(struct device *device,
|
||||
struct firmware_buf *buf)
|
||||
{
|
||||
int i;
|
||||
int i, len;
|
||||
int rc = -ENOENT;
|
||||
char *path = __getname();
|
||||
char *path;
|
||||
|
||||
path = __getname();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
|
||||
struct file *file;
|
||||
@@ -331,7 +340,12 @@ static int fw_get_filesystem_firmware(struct device *device,
|
||||
if (!fw_path[i][0])
|
||||
continue;
|
||||
|
||||
snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id);
|
||||
len = snprintf(path, PATH_MAX, "%s/%s",
|
||||
fw_path[i], buf->fw_id);
|
||||
if (len >= PATH_MAX) {
|
||||
rc = -ENAMETOOLONG;
|
||||
break;
|
||||
}
|
||||
|
||||
file = filp_open(path, O_RDONLY, 0);
|
||||
if (IS_ERR(file))
|
||||
@@ -392,6 +406,7 @@ static void fw_name_devm_release(struct device *dev, void *res)
|
||||
if (fwn->magic == (unsigned long)&fw_cache)
|
||||
pr_debug("%s: fw_name-%s devm-%p released\n",
|
||||
__func__, fwn->name, res);
|
||||
kfree_const(fwn->name);
|
||||
}
|
||||
|
||||
static int fw_devm_match(struct device *dev, void *res,
|
||||
@@ -422,13 +437,17 @@ static int fw_add_devm_name(struct device *dev, const char *name)
|
||||
if (fwn)
|
||||
return 1;
|
||||
|
||||
fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm) +
|
||||
strlen(name) + 1, GFP_KERNEL);
|
||||
fwn = devres_alloc(fw_name_devm_release, sizeof(struct fw_name_devm),
|
||||
GFP_KERNEL);
|
||||
if (!fwn)
|
||||
return -ENOMEM;
|
||||
fwn->name = kstrdup_const(name, GFP_KERNEL);
|
||||
if (!fwn->name) {
|
||||
kfree(fwn);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fwn->magic = (unsigned long)&fw_cache;
|
||||
strcpy(fwn->name, name);
|
||||
devres_add(dev, fwn);
|
||||
|
||||
return 0;
|
||||
@@ -1247,6 +1266,7 @@ static void request_firmware_work_func(struct work_struct *work)
|
||||
put_device(fw_work->device); /* taken in request_firmware_nowait() */
|
||||
|
||||
module_put(fw_work->module);
|
||||
kfree_const(fw_work->name);
|
||||
kfree(fw_work);
|
||||
}
|
||||
|
||||
@@ -1286,7 +1306,11 @@ request_firmware_nowait(
|
||||
return -ENOMEM;
|
||||
|
||||
fw_work->module = module;
|
||||
fw_work->name = name;
|
||||
fw_work->name = kstrdup_const(name, gfp);
|
||||
if (!fw_work->name) {
|
||||
kfree(fw_work);
|
||||
return -ENOMEM;
|
||||
}
|
||||
fw_work->device = device;
|
||||
fw_work->context = context;
|
||||
fw_work->cont = cont;
|
||||
@@ -1294,6 +1318,7 @@ request_firmware_nowait(
|
||||
(uevent ? FW_OPT_UEVENT : FW_OPT_USERHELPER);
|
||||
|
||||
if (!try_module_get(module)) {
|
||||
kfree_const(fw_work->name);
|
||||
kfree(fw_work);
|
||||
return -EFAULT;
|
||||
}
|
||||
@@ -1384,11 +1409,16 @@ static struct fw_cache_entry *alloc_fw_cache_entry(const char *name)
|
||||
{
|
||||
struct fw_cache_entry *fce;
|
||||
|
||||
fce = kzalloc(sizeof(*fce) + strlen(name) + 1, GFP_ATOMIC);
|
||||
fce = kzalloc(sizeof(*fce), GFP_ATOMIC);
|
||||
if (!fce)
|
||||
goto exit;
|
||||
|
||||
strcpy(fce->name, name);
|
||||
fce->name = kstrdup_const(name, GFP_ATOMIC);
|
||||
if (!fce->name) {
|
||||
kfree(fce);
|
||||
fce = NULL;
|
||||
goto exit;
|
||||
}
|
||||
exit:
|
||||
return fce;
|
||||
}
|
||||
@@ -1428,6 +1458,7 @@ found:
|
||||
|
||||
static void free_fw_cache_entry(struct fw_cache_entry *fce)
|
||||
{
|
||||
kfree_const(fce->name);
|
||||
kfree(fce);
|
||||
}
|
||||
|
||||
|
||||
@@ -613,6 +613,19 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv,
|
||||
{
|
||||
int retval, code;
|
||||
|
||||
if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) {
|
||||
pr_err("%s: drivers registered with %s can not be probed asynchronously\n",
|
||||
drv->driver.name, __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to run our probes synchronously because we check if
|
||||
* we find any devices to bind to and exit with error if there
|
||||
* are any.
|
||||
*/
|
||||
drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
|
||||
|
||||
/*
|
||||
* Prevent driver from requesting probe deferral to avoid further
|
||||
* futile probe attempts.
|
||||
|
||||
Reference in New Issue
Block a user