Commit 20a7b6be authored by Linus Torvalds's avatar Linus Torvalds

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

Pull driver core fixes from Greg KH:
 "Here are some small driver core and debugfs fixes for 5.9-rc5

  Included in here are:

   - firmware loader memory leak fix

   - firmware loader testing fixes for non-EFI systems

   - device link locking fixes found by lockdep

   - kobject_del() bugfix that has been affecting some callers

   - debugfs minor fix

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

* tag 'driver-core-5.9-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core:
  test_firmware: Test platform fw loading on non-EFI systems
  PM: <linux/device.h>: fix @em_pd kernel-doc warning
  kobject: Drop unneeded conditional in __kobject_del()
  driver core: Fix device_pm_lock() locking for device links
  MAINTAINERS: Add the security document to SECURITY CONTACT
  driver code: print symbolic error code
  debugfs: Fix module state check condition
  kobject: Restore old behaviour of kobject_del(NULL)
  firmware_loader: fix memory leak for paged buffer
parents 2a1a4bee baaabecf
...@@ -15577,6 +15577,7 @@ F: include/uapi/linux/sed* ...@@ -15577,6 +15577,7 @@ F: include/uapi/linux/sed*
SECURITY CONTACT SECURITY CONTACT
M: Security Officers <security@kernel.org> M: Security Officers <security@kernel.org>
S: Supported S: Supported
F: Documentation/admin-guide/security-bugs.rst
SECURITY SUBSYSTEM SECURITY SUBSYSTEM
M: James Morris <jmorris@namei.org> M: James Morris <jmorris@namei.org>
......
...@@ -807,9 +807,7 @@ static void device_link_put_kref(struct device_link *link) ...@@ -807,9 +807,7 @@ static void device_link_put_kref(struct device_link *link)
void device_link_del(struct device_link *link) void device_link_del(struct device_link *link)
{ {
device_links_write_lock(); device_links_write_lock();
device_pm_lock();
device_link_put_kref(link); device_link_put_kref(link);
device_pm_unlock();
device_links_write_unlock(); device_links_write_unlock();
} }
EXPORT_SYMBOL_GPL(device_link_del); EXPORT_SYMBOL_GPL(device_link_del);
...@@ -830,7 +828,6 @@ void device_link_remove(void *consumer, struct device *supplier) ...@@ -830,7 +828,6 @@ void device_link_remove(void *consumer, struct device *supplier)
return; return;
device_links_write_lock(); device_links_write_lock();
device_pm_lock();
list_for_each_entry(link, &supplier->links.consumers, s_node) { list_for_each_entry(link, &supplier->links.consumers, s_node) {
if (link->consumer == consumer) { if (link->consumer == consumer) {
...@@ -839,7 +836,6 @@ void device_link_remove(void *consumer, struct device *supplier) ...@@ -839,7 +836,6 @@ void device_link_remove(void *consumer, struct device *supplier)
} }
} }
device_pm_unlock();
device_links_write_unlock(); device_links_write_unlock();
} }
EXPORT_SYMBOL_GPL(device_link_remove); EXPORT_SYMBOL_GPL(device_link_remove);
...@@ -4237,10 +4233,10 @@ int dev_err_probe(const struct device *dev, int err, const char *fmt, ...) ...@@ -4237,10 +4233,10 @@ int dev_err_probe(const struct device *dev, int err, const char *fmt, ...)
vaf.va = &args; vaf.va = &args;
if (err != -EPROBE_DEFER) { if (err != -EPROBE_DEFER) {
dev_err(dev, "error %d: %pV", err, &vaf); dev_err(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
} else { } else {
device_set_deferred_probe_reason(dev, &vaf); device_set_deferred_probe_reason(dev, &vaf);
dev_dbg(dev, "error %d: %pV", err, &vaf); dev_dbg(dev, "error %pe: %pV", ERR_PTR(err), &vaf);
} }
va_end(args); va_end(args);
......
...@@ -142,10 +142,12 @@ int assign_fw(struct firmware *fw, struct device *device, u32 opt_flags); ...@@ -142,10 +142,12 @@ int assign_fw(struct firmware *fw, struct device *device, u32 opt_flags);
void fw_free_paged_buf(struct fw_priv *fw_priv); void fw_free_paged_buf(struct fw_priv *fw_priv);
int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed); int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed);
int fw_map_paged_buf(struct fw_priv *fw_priv); int fw_map_paged_buf(struct fw_priv *fw_priv);
bool fw_is_paged_buf(struct fw_priv *fw_priv);
#else #else
static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {} static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {}
static inline int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; } static inline int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; }
static inline int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; } static inline int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; }
static inline bool fw_is_paged_buf(struct fw_priv *fw_priv) { return false; }
#endif #endif
#endif /* __FIRMWARE_LOADER_H */ #endif /* __FIRMWARE_LOADER_H */
...@@ -252,9 +252,11 @@ static void __free_fw_priv(struct kref *ref) ...@@ -252,9 +252,11 @@ static void __free_fw_priv(struct kref *ref)
list_del(&fw_priv->list); list_del(&fw_priv->list);
spin_unlock(&fwc->lock); spin_unlock(&fwc->lock);
fw_free_paged_buf(fw_priv); /* free leftover pages */ if (fw_is_paged_buf(fw_priv))
if (!fw_priv->allocated_size) fw_free_paged_buf(fw_priv);
else if (!fw_priv->allocated_size)
vfree(fw_priv->data); vfree(fw_priv->data);
kfree_const(fw_priv->fw_name); kfree_const(fw_priv->fw_name);
kfree(fw_priv); kfree(fw_priv);
} }
...@@ -268,6 +270,11 @@ static void free_fw_priv(struct fw_priv *fw_priv) ...@@ -268,6 +270,11 @@ static void free_fw_priv(struct fw_priv *fw_priv)
} }
#ifdef CONFIG_FW_LOADER_PAGED_BUF #ifdef CONFIG_FW_LOADER_PAGED_BUF
bool fw_is_paged_buf(struct fw_priv *fw_priv)
{
return fw_priv->is_paged_buf;
}
void fw_free_paged_buf(struct fw_priv *fw_priv) void fw_free_paged_buf(struct fw_priv *fw_priv)
{ {
int i; int i;
...@@ -275,6 +282,8 @@ void fw_free_paged_buf(struct fw_priv *fw_priv) ...@@ -275,6 +282,8 @@ void fw_free_paged_buf(struct fw_priv *fw_priv)
if (!fw_priv->pages) if (!fw_priv->pages)
return; return;
vunmap(fw_priv->data);
for (i = 0; i < fw_priv->nr_pages; i++) for (i = 0; i < fw_priv->nr_pages; i++)
__free_page(fw_priv->pages[i]); __free_page(fw_priv->pages[i]);
kvfree(fw_priv->pages); kvfree(fw_priv->pages);
...@@ -328,10 +337,6 @@ int fw_map_paged_buf(struct fw_priv *fw_priv) ...@@ -328,10 +337,6 @@ int fw_map_paged_buf(struct fw_priv *fw_priv)
if (!fw_priv->data) if (!fw_priv->data)
return -ENOMEM; return -ENOMEM;
/* page table is no longer needed after mapping, let's free */
kvfree(fw_priv->pages);
fw_priv->pages = NULL;
return 0; return 0;
} }
#endif #endif
......
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
/* Exported for use by lib/test_firmware.c only */ /* Exported for use by lib/test_firmware.c only */
LIST_HEAD(efi_embedded_fw_list); LIST_HEAD(efi_embedded_fw_list);
EXPORT_SYMBOL_GPL(efi_embedded_fw_list); EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_list, TEST_FIRMWARE);
bool efi_embedded_fw_checked;
static bool checked_for_fw; EXPORT_SYMBOL_NS_GPL(efi_embedded_fw_checked, TEST_FIRMWARE);
static const struct dmi_system_id * const embedded_fw_table[] = { static const struct dmi_system_id * const embedded_fw_table[] = {
#ifdef CONFIG_TOUCHSCREEN_DMI #ifdef CONFIG_TOUCHSCREEN_DMI
...@@ -116,14 +116,14 @@ void __init efi_check_for_embedded_firmwares(void) ...@@ -116,14 +116,14 @@ void __init efi_check_for_embedded_firmwares(void)
} }
} }
checked_for_fw = true; efi_embedded_fw_checked = true;
} }
int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size) int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size)
{ {
struct efi_embedded_fw *iter, *fw = NULL; struct efi_embedded_fw *iter, *fw = NULL;
if (!checked_for_fw) { if (!efi_embedded_fw_checked) {
pr_warn("Warning %s called while we did not check for embedded fw\n", pr_warn("Warning %s called while we did not check for embedded fw\n",
__func__); __func__);
return -ENOENT; return -ENOENT;
......
...@@ -177,7 +177,7 @@ static int open_proxy_open(struct inode *inode, struct file *filp) ...@@ -177,7 +177,7 @@ static int open_proxy_open(struct inode *inode, struct file *filp)
goto out; goto out;
if (!fops_get(real_fops)) { if (!fops_get(real_fops)) {
#ifdef MODULE #ifdef CONFIG_MODULES
if (real_fops->owner && if (real_fops->owner &&
real_fops->owner->state == MODULE_STATE_GOING) real_fops->owner->state == MODULE_STATE_GOING)
goto out; goto out;
...@@ -312,7 +312,7 @@ static int full_proxy_open(struct inode *inode, struct file *filp) ...@@ -312,7 +312,7 @@ static int full_proxy_open(struct inode *inode, struct file *filp)
goto out; goto out;
if (!fops_get(real_fops)) { if (!fops_get(real_fops)) {
#ifdef MODULE #ifdef CONFIG_MODULES
if (real_fops->owner && if (real_fops->owner &&
real_fops->owner->state == MODULE_STATE_GOING) real_fops->owner->state == MODULE_STATE_GOING)
goto out; goto out;
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
#define EFI_EMBEDDED_FW_PREFIX_LEN 8 #define EFI_EMBEDDED_FW_PREFIX_LEN 8
/* /*
* This struct and efi_embedded_fw_list are private to the efi-embedded fw * This struct is private to the efi-embedded fw implementation.
* implementation they are in this header for use by lib/test_firmware.c only! * They are in this header for use by lib/test_firmware.c only!
*/ */
struct efi_embedded_fw { struct efi_embedded_fw {
struct list_head list; struct list_head list;
...@@ -18,8 +18,6 @@ struct efi_embedded_fw { ...@@ -18,8 +18,6 @@ struct efi_embedded_fw {
size_t length; size_t length;
}; };
extern struct list_head efi_embedded_fw_list;
/** /**
* struct efi_embedded_fw_desc - This struct is used by the EFI embedded-fw * struct efi_embedded_fw_desc - This struct is used by the EFI embedded-fw
* code to search for embedded firmwares. * code to search for embedded firmwares.
......
...@@ -604,9 +604,6 @@ static void __kobject_del(struct kobject *kobj) ...@@ -604,9 +604,6 @@ static void __kobject_del(struct kobject *kobj)
struct kernfs_node *sd; struct kernfs_node *sd;
const struct kobj_type *ktype; const struct kobj_type *ktype;
if (!kobj)
return;
sd = kobj->sd; sd = kobj->sd;
ktype = get_ktype(kobj); ktype = get_ktype(kobj);
...@@ -637,8 +634,12 @@ static void __kobject_del(struct kobject *kobj) ...@@ -637,8 +634,12 @@ static void __kobject_del(struct kobject *kobj)
*/ */
void kobject_del(struct kobject *kobj) void kobject_del(struct kobject *kobj)
{ {
struct kobject *parent = kobj->parent; struct kobject *parent;
if (!kobj)
return;
parent = kobj->parent;
__kobject_del(kobj); __kobject_del(kobj);
kobject_put(parent); kobject_put(parent);
} }
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/efi_embedded_fw.h> #include <linux/efi_embedded_fw.h>
MODULE_IMPORT_NS(TEST_FIRMWARE);
#define TEST_FIRMWARE_NAME "test-firmware.bin" #define TEST_FIRMWARE_NAME "test-firmware.bin"
#define TEST_FIRMWARE_NUM_REQS 4 #define TEST_FIRMWARE_NUM_REQS 4
#define TEST_FIRMWARE_BUF_SIZE SZ_1K #define TEST_FIRMWARE_BUF_SIZE SZ_1K
...@@ -489,6 +491,9 @@ static ssize_t trigger_request_store(struct device *dev, ...@@ -489,6 +491,9 @@ static ssize_t trigger_request_store(struct device *dev,
static DEVICE_ATTR_WO(trigger_request); static DEVICE_ATTR_WO(trigger_request);
#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE #ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
extern struct list_head efi_embedded_fw_list;
extern bool efi_embedded_fw_checked;
static ssize_t trigger_request_platform_store(struct device *dev, static ssize_t trigger_request_platform_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
...@@ -501,6 +506,7 @@ static ssize_t trigger_request_platform_store(struct device *dev, ...@@ -501,6 +506,7 @@ static ssize_t trigger_request_platform_store(struct device *dev,
}; };
struct efi_embedded_fw efi_embedded_fw; struct efi_embedded_fw efi_embedded_fw;
const struct firmware *firmware = NULL; const struct firmware *firmware = NULL;
bool saved_efi_embedded_fw_checked;
char *name; char *name;
int rc; int rc;
...@@ -513,6 +519,8 @@ static ssize_t trigger_request_platform_store(struct device *dev, ...@@ -513,6 +519,8 @@ static ssize_t trigger_request_platform_store(struct device *dev,
efi_embedded_fw.data = (void *)test_data; efi_embedded_fw.data = (void *)test_data;
efi_embedded_fw.length = sizeof(test_data); efi_embedded_fw.length = sizeof(test_data);
list_add(&efi_embedded_fw.list, &efi_embedded_fw_list); list_add(&efi_embedded_fw.list, &efi_embedded_fw_list);
saved_efi_embedded_fw_checked = efi_embedded_fw_checked;
efi_embedded_fw_checked = true;
pr_info("loading '%s'\n", name); pr_info("loading '%s'\n", name);
rc = firmware_request_platform(&firmware, name, dev); rc = firmware_request_platform(&firmware, name, dev);
...@@ -530,6 +538,7 @@ static ssize_t trigger_request_platform_store(struct device *dev, ...@@ -530,6 +538,7 @@ static ssize_t trigger_request_platform_store(struct device *dev,
rc = count; rc = count;
out: out:
efi_embedded_fw_checked = saved_efi_embedded_fw_checked;
release_firmware(firmware); release_firmware(firmware);
list_del(&efi_embedded_fw.list); list_del(&efi_embedded_fw.list);
kfree(name); kfree(name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment