Merge tag 'driver-core-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 29 Dec 2018 04:44:29 +0000 (20:44 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 29 Dec 2018 04:44:29 +0000 (20:44 -0800)
Pull driver core updates from Greg KH:
 "Here is the "big" set of driver core patches for 4.21-rc1.

  It's not really big, just a number of small changes for some reported
  issues, some documentation updates to hopefully make it harder for
  people to abuse the driver model, and some other minor cleanups.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'driver-core-4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core:
  mm, memory_hotplug: update a comment in unregister_memory()
  component: convert to DEFINE_SHOW_ATTRIBUTE
  sysfs: Disable lockdep for driver bind/unbind files
  driver core: Add missing dev->bus->need_parent_lock checks
  kobject: return error code if writing /sys/.../uevent fails
  driver core: Move async_synchronize_full call
  driver core: platform: Respect return code of platform_device_register_full()
  kref/kobject: Improve documentation
  drivers/base/memory.c: Use DEVICE_ATTR_RO and friends
  driver core: Replace simple_strto{l,ul} by kstrtou{l,ul}
  kernfs: Improve kernfs_notify() poll notification latency
  kobject: Fix warnings in lib/kobject_uevent.c
  kobject: drop unnecessary cast "%llu" for u64
  driver core: fix comments for device_block_probing()
  driver core: Replace simple_strtol by kstrtoint

1  2 
drivers/base/core.c
drivers/base/memory.c
drivers/base/platform.c
kernel/module.c

diff --combined drivers/base/core.c
@@@ -8,7 -8,6 +8,7 @@@
   * Copyright (c) 2006 Novell, Inc.
   */
  
 +#include <linux/acpi.h>
  #include <linux/device.h>
  #include <linux/err.h>
  #include <linux/fwnode.h>
@@@ -729,26 -728,6 +729,26 @@@ static inline int device_is_not_partiti
  }
  #endif
  
 +static int
 +device_platform_notify(struct device *dev, enum kobject_action action)
 +{
 +      int ret;
 +
 +      ret = acpi_platform_notify(dev, action);
 +      if (ret)
 +              return ret;
 +
 +      ret = software_node_notify(dev, action);
 +      if (ret)
 +              return ret;
 +
 +      if (platform_notify && action == KOBJ_ADD)
 +              platform_notify(dev);
 +      else if (platform_notify_remove && action == KOBJ_REMOVE)
 +              platform_notify_remove(dev);
 +      return 0;
 +}
 +
  /**
   * dev_driver_string - Return a device's driver name, if at all possible
   * @dev: struct device to get the name of
@@@ -815,10 -794,12 +815,12 @@@ ssize_t device_store_ulong(struct devic
                           const char *buf, size_t size)
  {
        struct dev_ext_attribute *ea = to_ext_attr(attr);
-       char *end;
-       unsigned long new = simple_strtoul(buf, &end, 0);
-       if (end == buf)
-               return -EINVAL;
+       int ret;
+       unsigned long new;
+       ret = kstrtoul(buf, 0, &new);
+       if (ret)
+               return ret;
        *(unsigned long *)(ea->var) = new;
        /* Always return full write size even if we didn't consume all */
        return size;
@@@ -839,9 -820,14 +841,14 @@@ ssize_t device_store_int(struct device 
                         const char *buf, size_t size)
  {
        struct dev_ext_attribute *ea = to_ext_attr(attr);
-       char *end;
-       long new = simple_strtol(buf, &end, 0);
-       if (end == buf || new > INT_MAX || new < INT_MIN)
+       int ret;
+       long new;
+       ret = kstrtol(buf, 0, &new);
+       if (ret)
+               return ret;
+       if (new > INT_MAX || new < INT_MIN)
                return -EINVAL;
        *(int *)(ea->var) = new;
        /* Always return full write size even if we didn't consume all */
@@@ -911,8 -897,7 +918,7 @@@ static void device_release(struct kobje
        else if (dev->class && dev->class->dev_release)
                dev->class->dev_release(dev);
        else
-               WARN(1, KERN_ERR "Device '%s' does not have a release() "
-                       "function, it is broken and must be fixed.\n",
+               WARN(1, KERN_ERR "Device '%s' does not have a release() function, it is broken and must be fixed. See Documentation/kobject.txt.\n",
                        dev_name(dev));
        kfree(p);
  }
  static ssize_t uevent_store(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
  {
-       if (kobject_synth_uevent(&dev->kobj, buf, count))
+       int rc;
+       rc = kobject_synth_uevent(&dev->kobj, buf, count);
+       if (rc) {
                dev_err(dev, "uevent: failed to send synthetic uevent\n");
+               return rc;
+       }
  
        return count;
  }
@@@ -1904,9 -1895,8 +1916,9 @@@ int device_add(struct device *dev
        }
  
        /* notify platform of device entry */
 -      if (platform_notify)
 -              platform_notify(dev);
 +      error = device_platform_notify(dev, KOBJ_ADD);
 +      if (error)
 +              goto platform_error;
  
        error = device_create_file(dev, &dev_attr_uevent);
        if (error)
@@@ -1982,8 -1972,6 +1994,8 @@@ done
   SymlinkError:
        device_remove_file(dev, &dev_attr_uevent);
   attrError:
 +      device_platform_notify(dev, KOBJ_REMOVE);
 +platform_error:
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
        glue_dir = get_glue_dir(dev);
        kobject_del(&dev->kobj);
@@@ -2101,10 -2089,14 +2113,10 @@@ void device_del(struct device *dev
        bus_remove_device(dev);
        device_pm_remove(dev);
        driver_deferred_probe_del(dev);
 +      device_platform_notify(dev, KOBJ_REMOVE);
        device_remove_properties(dev);
        device_links_purge(dev);
  
 -      /* Notify the platform of the removal, in case they
 -       * need to do anything...
 -       */
 -      if (platform_notify_remove)
 -              platform_notify_remove(dev);
        if (dev->bus)
                blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                                             BUS_NOTIFY_REMOVED_DEVICE, dev);
diff --combined drivers/base/memory.c
@@@ -109,8 -109,8 +109,8 @@@ static unsigned long get_memory_block_s
   * uses.
   */
  
- static ssize_t show_mem_start_phys_index(struct device *dev,
-                       struct device_attribute *attr, char *buf)
+ static ssize_t phys_index_show(struct device *dev,
+                              struct device_attribute *attr, char *buf)
  {
        struct memory_block *mem = to_memory_block(dev);
        unsigned long phys_index;
  /*
   * Show whether the section of memory is likely to be hot-removable
   */
- static ssize_t show_mem_removable(struct device *dev,
-                       struct device_attribute *attr, char *buf)
+ static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
+                             char *buf)
  {
        unsigned long i, pfn;
        int ret = 1;
@@@ -146,8 -146,8 +146,8 @@@ out
  /*
   * online, offline, going offline, etc.
   */
- static ssize_t show_mem_state(struct device *dev,
-                       struct device_attribute *attr, char *buf)
+ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+                         char *buf)
  {
        struct memory_block *mem = to_memory_block(dev);
        ssize_t len = 0;
@@@ -207,15 -207,15 +207,15 @@@ static bool pages_correctly_probed(unsi
                        return false;
  
                if (!present_section_nr(section_nr)) {
 -                      pr_warn("section %ld pfn[%lx, %lx) not present",
 +                      pr_warn("section %ld pfn[%lx, %lx) not present\n",
                                section_nr, pfn, pfn + PAGES_PER_SECTION);
                        return false;
                } else if (!valid_section_nr(section_nr)) {
 -                      pr_warn("section %ld pfn[%lx, %lx) no valid memmap",
 +                      pr_warn("section %ld pfn[%lx, %lx) no valid memmap\n",
                                section_nr, pfn, pfn + PAGES_PER_SECTION);
                        return false;
                } else if (online_section_nr(section_nr)) {
 -                      pr_warn("section %ld pfn[%lx, %lx) is already online",
 +                      pr_warn("section %ld pfn[%lx, %lx) is already online\n",
                                section_nr, pfn, pfn + PAGES_PER_SECTION);
                        return false;
                }
@@@ -286,7 -286,7 +286,7 @@@ static int memory_subsys_online(struct 
                return 0;
  
        /*
-        * If we are called from store_mem_state(), online_type will be
+        * If we are called from state_store(), online_type will be
         * set >= 0 Otherwise we were called from the device online
         * attribute and need to set the online_type.
         */
@@@ -315,9 -315,8 +315,8 @@@ static int memory_subsys_offline(struc
        return memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
  }
  
- static ssize_t
- store_mem_state(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
+ static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
  {
        struct memory_block *mem = to_memory_block(dev);
        int ret, online_type;
@@@ -374,7 -373,7 +373,7 @@@ err
   * s.t. if I offline all of these sections I can then
   * remove the physical device?
   */
- static ssize_t show_phys_device(struct device *dev,
+ static ssize_t phys_device_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
  {
        struct memory_block *mem = to_memory_block(dev);
@@@ -395,7 -394,7 +394,7 @@@ static void print_allowed_zone(char *bu
        }
  }
  
- static ssize_t show_valid_zones(struct device *dev,
+ static ssize_t valid_zones_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
  {
        struct memory_block *mem = to_memory_block(dev);
@@@ -435,33 -434,31 +434,31 @@@ out
  
        return strlen(buf);
  }
- static DEVICE_ATTR(valid_zones, 0444, show_valid_zones, NULL);
+ static DEVICE_ATTR_RO(valid_zones);
  #endif
  
- static DEVICE_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL);
- static DEVICE_ATTR(state, 0644, show_mem_state, store_mem_state);
- static DEVICE_ATTR(phys_device, 0444, show_phys_device, NULL);
- static DEVICE_ATTR(removable, 0444, show_mem_removable, NULL);
+ static DEVICE_ATTR_RO(phys_index);
+ static DEVICE_ATTR_RW(state);
+ static DEVICE_ATTR_RO(phys_device);
+ static DEVICE_ATTR_RO(removable);
  
  /*
   * Block size attribute stuff
   */
- static ssize_t
- print_block_size(struct device *dev, struct device_attribute *attr,
-                char *buf)
+ static ssize_t block_size_bytes_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
  {
        return sprintf(buf, "%lx\n", get_memory_block_size());
  }
  
- static DEVICE_ATTR(block_size_bytes, 0444, print_block_size, NULL);
+ static DEVICE_ATTR_RO(block_size_bytes);
  
  /*
   * Memory auto online policy.
   */
  
- static ssize_t
- show_auto_online_blocks(struct device *dev, struct device_attribute *attr,
-                       char *buf)
+ static ssize_t auto_online_blocks_show(struct device *dev,
+                                      struct device_attribute *attr, char *buf)
  {
        if (memhp_auto_online)
                return sprintf(buf, "online\n");
                return sprintf(buf, "offline\n");
  }
  
- static ssize_t
store_auto_online_blocks(struct device *dev, struct device_attribute *attr,
-                        const char *buf, size_t count)
+ static ssize_t auto_online_blocks_store(struct device *dev,
                                      struct device_attribute *attr,
+                                       const char *buf, size_t count)
  {
        if (sysfs_streq(buf, "online"))
                memhp_auto_online = true;
        return count;
  }
  
- static DEVICE_ATTR(auto_online_blocks, 0644, show_auto_online_blocks,
-                  store_auto_online_blocks);
+ static DEVICE_ATTR_RW(auto_online_blocks);
  
  /*
   * Some architectures will have custom drivers to do this, and
   * and will require this interface.
   */
  #ifdef CONFIG_ARCH_MEMORY_PROBE
- static ssize_t
- memory_probe_store(struct device *dev, struct device_attribute *attr,
-                  const char *buf, size_t count)
+ static ssize_t probe_store(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
  {
        u64 phys_addr;
        int nid, ret;
@@@ -525,7 -520,7 +520,7 @@@ out
        return ret;
  }
  
- static DEVICE_ATTR(probe, S_IWUSR, NULL, memory_probe_store);
+ static DEVICE_ATTR_WO(probe);
  #endif
  
  #ifdef CONFIG_MEMORY_FAILURE
   */
  
  /* Soft offline a page */
- static ssize_t
- store_soft_offline_page(struct device *dev,
-                       struct device_attribute *attr,
-                       const char *buf, size_t count)
+ static ssize_t soft_offline_page_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
  {
        int ret;
        u64 pfn;
  }
  
  /* Forcibly offline a page, including killing processes. */
- static ssize_t
- store_hard_offline_page(struct device *dev,
-                       struct device_attribute *attr,
-                       const char *buf, size_t count)
+ static ssize_t hard_offline_page_store(struct device *dev,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
  {
        int ret;
        u64 pfn;
        return ret ? ret : count;
  }
  
- static DEVICE_ATTR(soft_offline_page, S_IWUSR, NULL, store_soft_offline_page);
- static DEVICE_ATTR(hard_offline_page, S_IWUSR, NULL, store_hard_offline_page);
+ static DEVICE_ATTR_WO(soft_offline_page);
+ static DEVICE_ATTR_WO(hard_offline_page);
  #endif
  
  /*
@@@ -688,7 -681,7 +681,7 @@@ static int add_memory_block(int base_se
        int i, ret, section_count = 0, section_nr;
  
        for (i = base_section_nr;
 -           (i < base_section_nr + sections_per_block) && i < NR_MEM_SECTIONS;
 +           i < base_section_nr + sections_per_block;
             i++) {
                if (!present_section_nr(i))
                        continue;
@@@ -739,7 -732,7 +732,7 @@@ unregister_memory(struct memory_block *
  {
        BUG_ON(memory->dev.bus != &memory_subsys);
  
-       /* drop the ref. we got in remove_memory_block() */
+       /* drop the ref. we got in remove_memory_section() */
        put_device(&memory->dev);
        device_unregister(&memory->dev);
  }
diff --combined drivers/base/platform.c
@@@ -234,7 -234,7 +234,7 @@@ struct platform_object 
   */
  void platform_device_put(struct platform_device *pdev)
  {
-       if (pdev)
+       if (!IS_ERR_OR_NULL(pdev))
                put_device(&pdev->dev);
  }
  EXPORT_SYMBOL_GPL(platform_device_put);
@@@ -447,7 -447,8 +447,7 @@@ void platform_device_del(struct platfor
  {
        int i;
  
-       if (pdev) {
+       if (!IS_ERR_OR_NULL(pdev)) {
 -              device_remove_properties(&pdev->dev);
                device_del(&pdev->dev);
  
                if (pdev->id_auto) {
@@@ -1137,7 -1138,8 +1137,7 @@@ int platform_dma_configure(struct devic
                ret = of_dma_configure(dev, dev->of_node, true);
        } else if (has_acpi_companion(dev)) {
                attr = acpi_get_dma_attr(to_acpi_device_node(dev->fwnode));
 -              if (attr != DEV_DMA_NOT_SUPPORTED)
 -                      ret = acpi_dma_configure(dev, attr);
 +              ret = acpi_dma_configure(dev, attr);
        }
  
        return ret;
@@@ -1177,6 -1179,37 +1177,6 @@@ int __init platform_bus_init(void
        return error;
  }
  
 -#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
 -static u64 dma_default_get_required_mask(struct device *dev)
 -{
 -      u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT);
 -      u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT));
 -      u64 mask;
 -
 -      if (!high_totalram) {
 -              /* convert to mask just covering totalram */
 -              low_totalram = (1 << (fls(low_totalram) - 1));
 -              low_totalram += low_totalram - 1;
 -              mask = low_totalram;
 -      } else {
 -              high_totalram = (1 << (fls(high_totalram) - 1));
 -              high_totalram += high_totalram - 1;
 -              mask = (((u64)high_totalram) << 32) + 0xffffffff;
 -      }
 -      return mask;
 -}
 -
 -u64 dma_get_required_mask(struct device *dev)
 -{
 -      const struct dma_map_ops *ops = get_dma_ops(dev);
 -
 -      if (ops->get_required_mask)
 -              return ops->get_required_mask(dev);
 -      return dma_default_get_required_mask(dev);
 -}
 -EXPORT_SYMBOL_GPL(dma_get_required_mask);
 -#endif
 -
  static __initdata LIST_HEAD(early_platform_driver_list);
  static __initdata LIST_HEAD(early_platform_device_list);
  
diff --combined kernel/module.c
@@@ -495,9 -495,9 +495,9 @@@ struct find_symbol_arg 
        const struct kernel_symbol *sym;
  };
  
 -static bool check_symbol(const struct symsearch *syms,
 -                               struct module *owner,
 -                               unsigned int symnum, void *data)
 +static bool check_exported_symbol(const struct symsearch *syms,
 +                                struct module *owner,
 +                                unsigned int symnum, void *data)
  {
        struct find_symbol_arg *fsa = data;
  
@@@ -555,9 -555,9 +555,9 @@@ static int cmp_name(const void *va, con
        return strcmp(a, kernel_symbol_name(b));
  }
  
 -static bool find_symbol_in_section(const struct symsearch *syms,
 -                                 struct module *owner,
 -                                 void *data)
 +static bool find_exported_symbol_in_section(const struct symsearch *syms,
 +                                          struct module *owner,
 +                                          void *data)
  {
        struct find_symbol_arg *fsa = data;
        struct kernel_symbol *sym;
        sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,
                        sizeof(struct kernel_symbol), cmp_name);
  
 -      if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data))
 +      if (sym != NULL && check_exported_symbol(syms, owner,
 +                                               sym - syms->start, data))
                return true;
  
        return false;
  }
  
 -/* Find a symbol and return it, along with, (optional) crc and
 +/* Find an exported symbol and return it, along with, (optional) crc and
   * (optional) module which owns it.  Needs preempt disabled or module_mutex. */
  const struct kernel_symbol *find_symbol(const char *name,
                                        struct module **owner,
        fsa.gplok = gplok;
        fsa.warn = warn;
  
 -      if (each_symbol_section(find_symbol_in_section, &fsa)) {
 +      if (each_symbol_section(find_exported_symbol_in_section, &fsa)) {
                if (owner)
                        *owner = fsa.owner;
                if (crc)
@@@ -1208,8 -1207,10 +1208,10 @@@ static ssize_t store_uevent(struct modu
                            struct module_kobject *mk,
                            const char *buffer, size_t count)
  {
-       kobject_synth_uevent(&mk->kobj, buffer, count);
-       return count;
+       int rc;
+       rc = kobject_synth_uevent(&mk->kobj, buffer, count);
+       return rc ? rc : count;
  }
  
  struct module_attribute module_uevent =
@@@ -2160,7 -2161,7 +2162,7 @@@ static void free_module(struct module *
        /* Remove this module from bug list, this uses list_del_rcu */
        module_bug_cleanup(mod);
        /* Wait for RCU-sched synchronizing before releasing mod->list and buglist. */
 -      synchronize_sched();
 +      synchronize_rcu();
        mutex_unlock(&module_mutex);
  
        /* This may be empty, but that's OK */
@@@ -2199,7 -2200,7 +2201,7 @@@ EXPORT_SYMBOL_GPL(__symbol_get)
   *
   * You must hold the module_mutex.
   */
 -static int verify_export_symbols(struct module *mod)
 +static int verify_exported_symbols(struct module *mod)
  {
        unsigned int i;
        struct module *owner;
@@@ -2520,10 -2521,10 +2522,10 @@@ static void free_modinfo(struct module 
  
  #ifdef CONFIG_KALLSYMS
  
 -/* lookup symbol in given range of kernel_symbols */
 -static const struct kernel_symbol *lookup_symbol(const char *name,
 -      const struct kernel_symbol *start,
 -      const struct kernel_symbol *stop)
 +/* Lookup exported symbol in given range of kernel_symbols */
 +static const struct kernel_symbol *lookup_exported_symbol(const char *name,
 +                                                        const struct kernel_symbol *start,
 +                                                        const struct kernel_symbol *stop)
  {
        return bsearch(name, start, stop - start,
                        sizeof(struct kernel_symbol), cmp_name);
@@@ -2534,10 -2535,9 +2536,10 @@@ static int is_exported(const char *name
  {
        const struct kernel_symbol *ks;
        if (!mod)
 -              ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
 +              ks = lookup_exported_symbol(name, __start___ksymtab, __stop___ksymtab);
        else
 -              ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
 +              ks = lookup_exported_symbol(name, mod->syms, mod->syms + mod->num_syms);
 +
        return ks != NULL && kernel_symbol_value(ks) == value;
  }
  
@@@ -2684,7 -2684,7 +2686,7 @@@ static void add_kallsyms(struct module 
  
        /* Set types up while we still have access to sections. */
        for (i = 0; i < mod->kallsyms->num_symtab; i++)
 -              mod->kallsyms->symtab[i].st_info
 +              mod->kallsyms->symtab[i].st_size
                        = elf_type(&mod->kallsyms->symtab[i], info);
  
        /* Now populate the cut down core kallsyms for after init. */
@@@ -3095,11 -3095,6 +3097,11 @@@ static int find_module_sections(struct 
                                             sizeof(*mod->tracepoints_ptrs),
                                             &mod->num_tracepoints);
  #endif
 +#ifdef CONFIG_BPF_EVENTS
 +      mod->bpf_raw_events = section_objs(info, "__bpf_raw_tp_map",
 +                                         sizeof(*mod->bpf_raw_events),
 +                                         &mod->num_bpf_raw_events);
 +#endif
  #ifdef HAVE_JUMP_LABEL
        mod->jump_entries = section_objs(info, "__jump_table",
                                        sizeof(*mod->jump_entries),
@@@ -3514,15 -3509,15 +3516,15 @@@ static noinline int do_init_module(stru
        /*
         * We want to free module_init, but be aware that kallsyms may be
         * walking this with preempt disabled.  In all the failure paths, we
 -       * call synchronize_sched(), but we don't want to slow down the success
 +       * call synchronize_rcu(), but we don't want to slow down the success
         * path, so use actual RCU here.
         * Note that module_alloc() on most architectures creates W+X page
         * mappings which won't be cleaned up until do_free_init() runs.  Any
         * code such as mark_rodata_ro() which depends on those mappings to
         * be cleaned up needs to sync with the queued work - ie
 -       * rcu_barrier_sched()
 +       * rcu_barrier()
         */
 -      call_rcu_sched(&freeinit->rcu, do_free_init);
 +      call_rcu(&freeinit->rcu, do_free_init);
        mutex_unlock(&module_mutex);
        wake_up_all(&module_wq);
  
@@@ -3533,7 -3528,7 +3535,7 @@@ fail_free_freeinit
  fail:
        /* Try to protect us from buggy refcounters. */
        mod->state = MODULE_STATE_GOING;
 -      synchronize_sched();
 +      synchronize_rcu();
        module_put(mod);
        blocking_notifier_call_chain(&module_notify_list,
                                     MODULE_STATE_GOING, mod);
@@@ -3599,7 -3594,7 +3601,7 @@@ static int complete_formation(struct mo
        mutex_lock(&module_mutex);
  
        /* Find duplicate symbols (must be called under lock). */
 -      err = verify_export_symbols(mod);
 +      err = verify_exported_symbols(mod);
        if (err < 0)
                goto out;
  
@@@ -3826,7 -3821,7 +3828,7 @@@ static int load_module(struct load_inf
   ddebug_cleanup:
        ftrace_release_mod(mod);
        dynamic_debug_remove(mod, info->debug);
 -      synchronize_sched();
 +      synchronize_rcu();
        kfree(mod->args);
   free_arch_cleanup:
        module_arch_cleanup(mod);
        mod_tree_remove(mod);
        wake_up_all(&module_wq);
        /* Wait for RCU-sched synchronizing before releasing mod->list. */
 -      synchronize_sched();
 +      synchronize_rcu();
        mutex_unlock(&module_mutex);
   free_module:
        /* Free lock-classes; relies on the preceding sync_rcu() */
@@@ -3918,22 -3913,18 +3920,22 @@@ static inline int is_arm_mapping_symbol
               && (str[2] == '\0' || str[2] == '.');
  }
  
 -static const char *symname(struct mod_kallsyms *kallsyms, unsigned int symnum)
 +static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned int symnum)
  {
        return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
  }
  
 -static const char *get_ksymbol(struct module *mod,
 -                             unsigned long addr,
 -                             unsigned long *size,
 -                             unsigned long *offset)
 +/*
 + * Given a module and address, find the corresponding symbol and return its name
 + * while providing its size and offset if needed.
 + */
 +static const char *find_kallsyms_symbol(struct module *mod,
 +                                      unsigned long addr,
 +                                      unsigned long *size,
 +                                      unsigned long *offset)
  {
        unsigned int i, best = 0;
 -      unsigned long nextval;
 +      unsigned long nextval, bestval;
        struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
  
        /* At worse, next value is at end of module */
        else
                nextval = (unsigned long)mod->core_layout.base+mod->core_layout.text_size;
  
 +      bestval = kallsyms_symbol_value(&kallsyms->symtab[best]);
 +
        /* Scan for closest preceding symbol, and next symbol. (ELF
           starts real symbols at 1). */
        for (i = 1; i < kallsyms->num_symtab; i++) {
 -              if (kallsyms->symtab[i].st_shndx == SHN_UNDEF)
 +              const Elf_Sym *sym = &kallsyms->symtab[i];
 +              unsigned long thisval = kallsyms_symbol_value(sym);
 +
 +              if (sym->st_shndx == SHN_UNDEF)
                        continue;
  
                /* We ignore unnamed symbols: they're uninformative
                 * and inserted at a whim. */
 -              if (*symname(kallsyms, i) == '\0'
 -                  || is_arm_mapping_symbol(symname(kallsyms, i)))
 +              if (*kallsyms_symbol_name(kallsyms, i) == '\0'
 +                  || is_arm_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
                        continue;
  
 -              if (kallsyms->symtab[i].st_value <= addr
 -                  && kallsyms->symtab[i].st_value > kallsyms->symtab[best].st_value)
 +              if (thisval <= addr && thisval > bestval) {
                        best = i;
 -              if (kallsyms->symtab[i].st_value > addr
 -                  && kallsyms->symtab[i].st_value < nextval)
 -                      nextval = kallsyms->symtab[i].st_value;
 +                      bestval = thisval;
 +              }
 +              if (thisval > addr && thisval < nextval)
 +                      nextval = thisval;
        }
  
        if (!best)
                return NULL;
  
        if (size)
 -              *size = nextval - kallsyms->symtab[best].st_value;
 +              *size = nextval - bestval;
        if (offset)
 -              *offset = addr - kallsyms->symtab[best].st_value;
 -      return symname(kallsyms, best);
 +              *offset = addr - bestval;
 +
 +      return kallsyms_symbol_name(kallsyms, best);
  }
  
  void * __weak dereference_module_function_descriptor(struct module *mod,
@@@ -4000,8 -3985,7 +4002,8 @@@ const char *module_address_lookup(unsig
        if (mod) {
                if (modname)
                        *modname = mod->name;
 -              ret = get_ksymbol(mod, addr, size, offset);
 +
 +              ret = find_kallsyms_symbol(mod, addr, size, offset);
        }
        /* Make a copy in here where it's safe */
        if (ret) {
@@@ -4024,10 -4008,9 +4026,10 @@@ int lookup_module_symbol_name(unsigned 
                if (within_module(addr, mod)) {
                        const char *sym;
  
 -                      sym = get_ksymbol(mod, addr, NULL, NULL);
 +                      sym = find_kallsyms_symbol(mod, addr, NULL, NULL);
                        if (!sym)
                                goto out;
 +
                        strlcpy(symname, sym, KSYM_NAME_LEN);
                        preempt_enable();
                        return 0;
@@@ -4050,7 -4033,7 +4052,7 @@@ int lookup_module_symbol_attrs(unsigne
                if (within_module(addr, mod)) {
                        const char *sym;
  
 -                      sym = get_ksymbol(mod, addr, size, offset);
 +                      sym = find_kallsyms_symbol(mod, addr, size, offset);
                        if (!sym)
                                goto out;
                        if (modname)
@@@ -4079,11 -4062,9 +4081,11 @@@ int module_get_kallsym(unsigned int sym
                        continue;
                kallsyms = rcu_dereference_sched(mod->kallsyms);
                if (symnum < kallsyms->num_symtab) {
 -                      *value = kallsyms->symtab[symnum].st_value;
 -                      *type = kallsyms->symtab[symnum].st_info;
 -                      strlcpy(name, symname(kallsyms, symnum), KSYM_NAME_LEN);
 +                      const Elf_Sym *sym = &kallsyms->symtab[symnum];
 +
 +                      *value = kallsyms_symbol_value(sym);
 +                      *type = sym->st_size;
 +                      strlcpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN);
                        strlcpy(module_name, mod->name, MODULE_NAME_LEN);
                        *exported = is_exported(name, *value, mod);
                        preempt_enable();
        return -ERANGE;
  }
  
 -static unsigned long mod_find_symname(struct module *mod, const char *name)
 +/* Given a module and name of symbol, find and return the symbol's value */
 +static unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
  {
        unsigned int i;
        struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms);
  
 -      for (i = 0; i < kallsyms->num_symtab; i++)
 -              if (strcmp(name, symname(kallsyms, i)) == 0 &&
 -                  kallsyms->symtab[i].st_shndx != SHN_UNDEF)
 -                      return kallsyms->symtab[i].st_value;
 +      for (i = 0; i < kallsyms->num_symtab; i++) {
 +              const Elf_Sym *sym = &kallsyms->symtab[i];
 +
 +              if (strcmp(name, kallsyms_symbol_name(kallsyms, i)) == 0 &&
 +                  sym->st_shndx != SHN_UNDEF)
 +                      return kallsyms_symbol_value(sym);
 +      }
        return 0;
  }
  
@@@ -4122,12 -4099,12 +4124,12 @@@ unsigned long module_kallsyms_lookup_na
        preempt_disable();
        if ((colon = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
                if ((mod = find_module_all(name, colon - name, false)) != NULL)
 -                      ret = mod_find_symname(mod, colon+1);
 +                      ret = find_kallsyms_symbol_value(mod, colon+1);
        } else {
                list_for_each_entry_rcu(mod, &modules, list) {
                        if (mod->state == MODULE_STATE_UNFORMED)
                                continue;
 -                      if ((ret = mod_find_symname(mod, name)) != 0)
 +                      if ((ret = find_kallsyms_symbol_value(mod, name)) != 0)
                                break;
                }
        }
@@@ -4152,13 -4129,12 +4154,13 @@@ int module_kallsyms_on_each_symbol(int 
                if (mod->state == MODULE_STATE_UNFORMED)
                        continue;
                for (i = 0; i < kallsyms->num_symtab; i++) {
 +                      const Elf_Sym *sym = &kallsyms->symtab[i];
  
 -                      if (kallsyms->symtab[i].st_shndx == SHN_UNDEF)
 +                      if (sym->st_shndx == SHN_UNDEF)
                                continue;
  
 -                      ret = fn(data, symname(kallsyms, i),
 -                               mod, kallsyms->symtab[i].st_value);
 +                      ret = fn(data, kallsyms_symbol_name(kallsyms, i),
 +                               mod, kallsyms_symbol_value(sym));
                        if (ret != 0)
                                return ret;
                }