]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'driver-core-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Jun 2015 22:07:37 +0000 (15:07 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Jun 2015 22:07:37 +0000 (15:07 -0700)
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
  ...

23 files changed:
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/kernel-parameters.txt
MAINTAINERS
arch/powerpc/mm/hugetlbpage.c
drivers/base/base.h
drivers/base/bus.c
drivers/base/cacheinfo.c
drivers/base/cpu.c
drivers/base/dd.c
drivers/base/firmware_class.c
drivers/base/platform.c
drivers/edac/amd64_edac.c
fs/kernfs/file.c
fs/sysfs/file.c
fs/sysfs/group.c
include/linux/cacheinfo.h
include/linux/device.h
include/linux/module.h
include/linux/moduleparam.h
init/main.c
kernel/module.c
kernel/params.c
lib/dynamic_debug.c

index da95513571ea3e3e53263f6c91588fb58d50f3fb..b683e8ee69ecc59a353c700330b7162f50652123 100644 (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
index c84d078a6376159f4d28ea71b2550a20abdb8c63..1e18efe3a4ed82853ce8078761aeb86dfd4aecfb 100644 (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
index 161747bdecf341bcadd3082b415089111a660d8d..e4b32dcc2494b9690992cc9d264f78fe4980601a 100644 (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
index 38bd5d998c81aadda711b03093a9b854e1018cc8..1f614d778a8b5ffc2b1cf32465fce3a579839f3a 100644 (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.
index 251c5d30f963060d3fec65b61205ae0225f141a5..fd3347d9f15351c4e859816c43b69bb9f59d5c98 100644 (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);
index 79bc203f51ef08511eff94661cc77fac163475d5..500592486e8832cfd61673302359cc352b51efa0 100644 (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);
 
index df0c66cb7ad3719016436dd7eb16ab1d3234568d..764280a917761e9bf3360111bb92709d676c69e4 100644 (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;
        }
index f160ea44a86d68a26b689b5ff7c5f0bcaf5ec74e..78720e70617634c6301339510564ac6ed4380455 100644 (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
index e843fdbe492514d83fd1f66cfc8678b10099e877..a638bbb1a27a573f7d959c20d459c73a368e8794 100644 (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,31 +417,107 @@ 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);
 }
 
-/**
- * device_attach - try to attach device to a driver.
- * @dev: device.
- *
- * Walk the list of drivers that the bus has and call
- * driver_probe_device() for each pair. If a compatible
- * pair is found, break out and return.
- *
- * Returns 1 if the device was bound to a driver;
- * 0 if no matching driver was found;
- * -ENODEV if the device is not registered.
- *
- * When called for a USB interface, @dev->parent lock must be held.
- */
-int device_attach(struct device *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;
 
@@ -459,15 +535,59 @@ int device_attach(struct device *dev)
                        ret = 0;
                }
        } else {
-               ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
-               pm_request_idle(dev);
+               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.
+ *
+ * Walk the list of drivers that the bus has and call
+ * driver_probe_device() for each pair. If a compatible
+ * pair is found, break out and return.
+ *
+ * Returns 1 if the device was bound to a driver;
+ * 0 if no matching driver was found;
+ * -ENODEV if the device is not registered.
+ *
+ * When called for a USB interface, @dev->parent lock must be held.
+ */
+int device_attach(struct device *dev)
+{
+       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);
index 171841ad10089feef1aea6e6035327a68e745604..9c4288362a8eaab0825d489c6362ceb573cbad30 100644 (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);
 }
 
index ebf034b97278592ab57cbd24ef0f53d3cfc56e0a..063f0ab152590dfeea4488d2686b8ff13b99a7bf 100644 (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.
index 92772fffc52ff292fc38e8acd09bf0002d332c8b..73aea40a9c89592035e08ecf98292dc9aab9df62 100644 (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)
index 2bacb99885665f3a0fae9579a569128195d86fd4..7247252ee9b1beffa3c624cb54db676a707fffe2 100644 (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;
 
index 7c2867b44141e5df54734e7e27e3df344a976dea..6c95628ea377dc0d4c07cbb7979f2a280dd3e6a8 100644 (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;
index b400c04371f0d08c980b54183938b36afa47c1ec..39a01993676864e56b55f8125155646f808f4f40 100644 (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)
index 3daf5ed392c9a5e40fc99a7e587ee318403dbc06..2189935075b48e3d5b06012f9279f6eea4973fa7 100644 (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
index 6558af90c8fe3b9263441dc401b3689940d3453e..00ac57c26615103b0983040981cac8012c9e2f99 100644 (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);
 
 /*
index 255fca74de7dbebe02d44a0a5946217ae20f3732..7ffe0851d24438876faa9d756178d1654c7e825e 100644 (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
index 1c9effa25e2632497384e973a28954f7e33aedbc..6480dcaca275b62541964ebfe390f0c0da8d371f 100644 (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
index 2a89545e0a5d690db09acaa7042c83256ea84fb1..c599aea23bb1cbaec3eeb55ec2a181fcd735fd2c 100644 (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);
index b38f96a183b5b07e3c31e791e81062edc4b23408..f80a97f7da1f14b96c87efaf82f9f8c88612ab54 100644 (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;
index a22d6a759b1a9391d5713364097bcfca35f197e7..30288c1e15dd1afe441f7d4dd0cd8f8b288eed28 100644 (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);
index d8f3d3150603cc0d2abd06e415f0c9a35521e2fa..e491e02eff549fbe8c2e245c3f475b908818938f 100644 (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;