Driver core patches for 4.2-rc1

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.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iEYEABECAAYFAlWNoCQACgkQMUfUDdst+ym4JACdFrrXoMt2pb8nl5gMidGyM9/D
 jg8AnRgdW8ArDA/xOarULd/X43eA3J3C
 =Al2B
 -----END PGP SIGNATURE-----

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:
Linus Torvalds 2015-06-26 15:07:37 -07:00
commit 8d7804a2f0
23 changed files with 372 additions and 84 deletions

View File

@ -243,7 +243,7 @@ Description: Parameters for the CPU cache attributes
coherency_line_size: the minimum amount of data in bytes that gets
transferred from memory to cache
level: the cache hierarcy in the multi-level cache configuration
level: the cache hierarchy in the multi-level cache configuration
number_of_sets: total number of sets in the cache, a set is a
collection of cache lines with the same cache index

View File

@ -953,6 +953,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
auto selects the default scheme, which automatically
enables eagerfpu restore for xsaveopt.
module.async_probe [KNL]
Enable asynchronous probe on this module.
early_ioremap_debug [KNL]
Enable debug messages in early_ioremap support. This
is useful for tracking down temporary early mappings

View File

@ -3450,16 +3450,17 @@ F: drivers/block/drbd/
F: lib/lru_cache.c
F: Documentation/blockdev/drbd/
DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
DRIVER CORE, KOBJECTS, DEBUGFS, KERNFS AND SYSFS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
S: Supported
F: Documentation/kobject.txt
F: drivers/base/
F: fs/sysfs/
F: fs/debugfs/
F: include/linux/kobj*
F: fs/kernfs/
F: fs/sysfs/
F: include/linux/debugfs.h
F: include/linux/kobj*
F: lib/kobj*
DRM DRIVERS

View File

@ -336,7 +336,7 @@ int alloc_bootmem_huge_page(struct hstate *hstate)
unsigned long gpage_npages[MMU_PAGE_COUNT];
static int __init do_gpage_early_setup(char *param, char *val,
const char *unused)
const char *unused, void *arg)
{
static phys_addr_t size;
unsigned long npages;
@ -385,7 +385,7 @@ void __init reserve_hugetlb_gpages(void)
strlcpy(cmdline, boot_command_line, COMMAND_LINE_SIZE);
parse_args("hugetlb gpages", cmdline, NULL, 0, 0, 0,
&do_gpage_early_setup);
NULL, &do_gpage_early_setup);
/*
* Walk gpage list in reverse, allocating larger page sizes first.

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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);
}

View File

@ -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.

View File

@ -2964,6 +2964,7 @@ static struct pci_driver amd64_pci_driver = {
.probe = probe_one_instance,
.remove = remove_one_instance,
.id_table = amd64_pci_table,
.driver.probe_type = PROBE_FORCE_SYNCHRONOUS,
};
static void setup_pci_device(void)

View File

@ -785,7 +785,6 @@ static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait)
struct kernfs_node *kn = filp->f_path.dentry->d_fsdata;
struct kernfs_open_node *on = kn->attr.open;
/* need parent for the kobj, grab both */
if (!kernfs_get_active(kn))
goto trigger;

View File

@ -90,7 +90,7 @@ static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf,
return 0;
if (size) {
if (pos > size)
if (pos >= size)
return 0;
if (pos + count > size)
count = size - pos;

View File

@ -135,7 +135,7 @@ static int internal_create_group(struct kobject *kobj, int update,
* This function creates a group for the first time. It will explicitly
* warn and error if any of the attribute files being created already exist.
*
* Returns 0 on success or error.
* Returns 0 on success or error code on failure.
*/
int sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp)
@ -155,7 +155,7 @@ EXPORT_SYMBOL_GPL(sysfs_create_group);
* It will explicitly warn and error if any of the attribute files being
* created already exist.
*
* Returns 0 on success or error code from sysfs_create_group on error.
* Returns 0 on success or error code from sysfs_create_group on failure.
*/
int sysfs_create_groups(struct kobject *kobj,
const struct attribute_group **groups)
@ -193,7 +193,7 @@ EXPORT_SYMBOL_GPL(sysfs_create_groups);
* The primary use for this function is to call it after making a change
* that affects group visibility.
*
* Returns 0 on success or error.
* Returns 0 on success or error code on failure.
*/
int sysfs_update_group(struct kobject *kobj,
const struct attribute_group *grp)

View File

@ -19,7 +19,7 @@ enum cache_type {
/**
* struct cacheinfo - represent a cache leaf node
* @type: type of the cache - data, inst or unified
* @level: represents the hierarcy in the multi-level cache
* @level: represents the hierarchy in the multi-level cache
* @coherency_line_size: size of each cache line usually representing
* the minimum amount of data that gets transferred from memory
* @number_of_sets: total number of sets, a set is a collection of cache

View File

@ -195,6 +195,34 @@ extern int bus_unregister_notifier(struct bus_type *bus,
extern struct kset *bus_get_kset(struct bus_type *bus);
extern struct klist *bus_get_device_klist(struct bus_type *bus);
/**
* enum probe_type - device driver probe type to try
* Device drivers may opt in for special handling of their
* respective probe routines. This tells the core what to
* expect and prefer.
*
* @PROBE_DEFAULT_STRATEGY: Used by drivers that work equally well
* whether probed synchronously or asynchronously.
* @PROBE_PREFER_ASYNCHRONOUS: Drivers for "slow" devices which
* probing order is not essential for booting the system may
* opt into executing their probes asynchronously.
* @PROBE_FORCE_SYNCHRONOUS: Use this to annotate drivers that need
* their probe routines to run synchronously with driver and
* device registration (with the exception of -EPROBE_DEFER
* handling - re-probing always ends up being done asynchronously).
*
* Note that the end goal is to switch the kernel to use asynchronous
* probing by default, so annotating drivers with
* %PROBE_PREFER_ASYNCHRONOUS is a temporary measure that allows us
* to speed up boot process while we are validating the rest of the
* drivers.
*/
enum probe_type {
PROBE_DEFAULT_STRATEGY,
PROBE_PREFER_ASYNCHRONOUS,
PROBE_FORCE_SYNCHRONOUS,
};
/**
* struct device_driver - The basic device driver structure
* @name: Name of the device driver.
@ -202,6 +230,7 @@ extern struct klist *bus_get_device_klist(struct bus_type *bus);
* @owner: The module owner.
* @mod_name: Used for built-in modules.
* @suppress_bind_attrs: Disables bind/unbind via sysfs.
* @probe_type: Type of the probe (synchronous or asynchronous) to use.
* @of_match_table: The open firmware table.
* @acpi_match_table: The ACPI match table.
* @probe: Called to query the existence of a specific device,
@ -235,6 +264,7 @@ struct device_driver {
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
enum probe_type probe_type;
const struct of_device_id *of_match_table;
const struct acpi_device_id *acpi_match_table;
@ -975,6 +1005,7 @@ extern int __must_check device_bind_driver(struct device *dev);
extern void device_release_driver(struct device *dev);
extern int __must_check device_attach(struct device *dev);
extern int __must_check driver_attach(struct device_driver *drv);
extern void device_initial_probe(struct device *dev);
extern int __must_check device_reprobe(struct device *dev);
/*

View File

@ -257,6 +257,8 @@ struct module {
bool sig_ok;
#endif
bool async_probe_requested;
/* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms;
const unsigned long *gpl_future_crcs;
@ -508,6 +510,11 @@ int unregister_module_notifier(struct notifier_block *nb);
extern void print_modules(void);
static inline bool module_requested_async_probing(struct module *module)
{
return module && module->async_probe_requested;
}
#else /* !CONFIG_MODULES... */
/* Given an address, look for it in the exception tables. */
@ -618,6 +625,12 @@ static inline int unregister_module_notifier(struct notifier_block *nb)
static inline void print_modules(void)
{
}
static inline bool module_requested_async_probing(struct module *module)
{
return false;
}
#endif /* CONFIG_MODULES */
#ifdef CONFIG_SYSFS

View File

@ -310,6 +310,15 @@ static inline void __kernel_param_unlock(void)
#define core_param(name, var, type, perm) \
param_check_##type(name, &(var)); \
__module_param_call("", name, &param_ops_##type, &var, perm, -1, 0)
/**
* core_param_unsafe - same as core_param but taints kernel
*/
#define core_param_unsafe(name, var, type, perm) \
param_check_##type(name, &(var)); \
__module_param_call("", name, &param_ops_##type, &var, perm, \
-1, KERNEL_PARAM_FL_UNSAFE)
#endif /* !MODULE */
/**
@ -357,8 +366,9 @@ extern char *parse_args(const char *name,
unsigned num,
s16 level_min,
s16 level_max,
void *arg,
int (*unknown)(char *param, char *val,
const char *doing));
const char *doing, void *arg));
/* Called by module remove. */
#ifdef CONFIG_SYSFS

View File

@ -235,7 +235,8 @@ static int __init loglevel(char *str)
early_param("loglevel", loglevel);
/* Change NUL term back to "=", to make "param" the whole string. */
static int __init repair_env_string(char *param, char *val, const char *unused)
static int __init repair_env_string(char *param, char *val,
const char *unused, void *arg)
{
if (val) {
/* param=val or param="val"? */
@ -252,14 +253,15 @@ static int __init repair_env_string(char *param, char *val, const char *unused)
}
/* Anything after -- gets handed straight to init. */
static int __init set_init_arg(char *param, char *val, const char *unused)
static int __init set_init_arg(char *param, char *val,
const char *unused, void *arg)
{
unsigned int i;
if (panic_later)
return 0;
repair_env_string(param, val, unused);
repair_env_string(param, val, unused, NULL);
for (i = 0; argv_init[i]; i++) {
if (i == MAX_INIT_ARGS) {
@ -276,9 +278,10 @@ static int __init set_init_arg(char *param, char *val, const char *unused)
* Unknown boot options get handed to init, unless they look like
* unused parameters (modprobe will find them in /proc/cmdline).
*/
static int __init unknown_bootoption(char *param, char *val, const char *unused)
static int __init unknown_bootoption(char *param, char *val,
const char *unused, void *arg)
{
repair_env_string(param, val, unused);
repair_env_string(param, val, unused, NULL);
/* Handle obsolete-style parameters */
if (obsolete_checksetup(param))
@ -410,7 +413,8 @@ static noinline void __init_refok rest_init(void)
}
/* Check for early params. */
static int __init do_early_param(char *param, char *val, const char *unused)
static int __init do_early_param(char *param, char *val,
const char *unused, void *arg)
{
const struct obs_kernel_param *p;
@ -429,7 +433,8 @@ static int __init do_early_param(char *param, char *val, const char *unused)
void __init parse_early_options(char *cmdline)
{
parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param);
parse_args("early options", cmdline, NULL, 0, 0, 0, NULL,
do_early_param);
}
/* Arch code calls this early on, or if not, just before other parsing. */
@ -535,10 +540,10 @@ asmlinkage __visible void __init start_kernel(void)
after_dashes = parse_args("Booting kernel",
static_command_line, __start___param,
__stop___param - __start___param,
-1, -1, &unknown_bootoption);
-1, -1, NULL, &unknown_bootoption);
if (!IS_ERR_OR_NULL(after_dashes))
parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
set_init_arg);
NULL, set_init_arg);
jump_label_init();
@ -848,7 +853,7 @@ static void __init do_initcall_level(int level)
initcall_command_line, __start___param,
__stop___param - __start___param,
level, level,
&repair_env_string);
NULL, &repair_env_string);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(*fn);

View File

@ -3107,7 +3107,7 @@ static noinline int do_init_module(struct module *mod)
*
* http://thread.gmane.org/gmane.linux.kernel/1420814
*/
if (current->flags & PF_USED_ASYNC)
if (!mod->async_probe_requested && (current->flags & PF_USED_ASYNC))
async_synchronize_full();
mutex_lock(&module_mutex);
@ -3237,10 +3237,19 @@ out:
return err;
}
static int unknown_module_param_cb(char *param, char *val, const char *modname)
static int unknown_module_param_cb(char *param, char *val, const char *modname,
void *arg)
{
struct module *mod = arg;
int ret;
if (strcmp(param, "async_probe") == 0) {
mod->async_probe_requested = true;
return 0;
}
/* Check for magic 'dyndbg' arg */
int ret = ddebug_dyndbg_module_param_cb(param, val, modname);
ret = ddebug_dyndbg_module_param_cb(param, val, modname);
if (ret != 0)
pr_warn("%s: unknown parameter '%s' ignored\n", modname, param);
return 0;
@ -3342,7 +3351,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
/* Module is ready to execute: parsing args may do that. */
after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
-32768, 32767, unknown_module_param_cb);
-32768, 32767, NULL,
unknown_module_param_cb);
if (IS_ERR(after_dashes)) {
err = PTR_ERR(after_dashes);
goto bug_cleanup;

View File

@ -100,8 +100,9 @@ static int parse_one(char *param,
unsigned num_params,
s16 min_level,
s16 max_level,
void *arg,
int (*handle_unknown)(char *param, char *val,
const char *doing))
const char *doing, void *arg))
{
unsigned int i;
int err;
@ -128,7 +129,7 @@ static int parse_one(char *param,
if (handle_unknown) {
pr_debug("doing %s: %s='%s'\n", doing, param, val);
return handle_unknown(param, val, doing);
return handle_unknown(param, val, doing, arg);
}
pr_debug("Unknown argument '%s'\n", param);
@ -194,7 +195,9 @@ char *parse_args(const char *doing,
unsigned num,
s16 min_level,
s16 max_level,
int (*unknown)(char *param, char *val, const char *doing))
void *arg,
int (*unknown)(char *param, char *val,
const char *doing, void *arg))
{
char *param, *val;
@ -214,7 +217,7 @@ char *parse_args(const char *doing,
return args;
irq_was_disabled = irqs_disabled();
ret = parse_one(param, val, doing, params, num,
min_level, max_level, unknown);
min_level, max_level, arg, unknown);
if (irq_was_disabled && !irqs_disabled())
pr_warn("%s: option '%s' enabled irq's!\n",
doing, param);

View File

@ -887,7 +887,7 @@ static int ddebug_dyndbg_param_cb(char *param, char *val,
/* handle both dyndbg and $module.dyndbg params at boot */
static int ddebug_dyndbg_boot_param_cb(char *param, char *val,
const char *unused)
const char *unused, void *arg)
{
vpr_info("%s=\"%s\"\n", param, val);
return ddebug_dyndbg_param_cb(param, val, NULL, 0);
@ -1028,7 +1028,7 @@ static int __init dynamic_debug_init(void)
*/
cmdline = kstrdup(saved_command_line, GFP_KERNEL);
parse_args("dyndbg params", cmdline, NULL,
0, 0, 0, &ddebug_dyndbg_boot_param_cb);
0, 0, 0, NULL, &ddebug_dyndbg_boot_param_cb);
kfree(cmdline);
return 0;