Commit dd27111e authored by Linus Torvalds's avatar Linus Torvalds

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

Pull driver core updates from Greg KH:
 "Here is the "big" set of changes to the driver core, and some drivers
  using the changes, for 5.9-rc1.

  "Biggest" thing in here is the device link exposure in sysfs, to help
  to tame the madness that is SoC device tree representations and driver
  interactions with it.

  Other stuff in here that is interesting is:

   - device probe log helper so that drivers can report problems in a
     unified way easier.

   - devres functions added

   - DEVICE_ATTR_ADMIN_* macro added to make it harder to write
     incorrect sysfs file permissions

   - documentation cleanups

   - ability for debugfs to be present in the kernel, yet not exposed to
     userspace. Needed for systems that want it enabled, but do not
     trust users, so they can still use some kernel functions that were
     otherwise disabled.

   - other minor fixes and cleanups

  The patches outside of drivers/base/ all have acks from the respective
  subsystem maintainers to go through this tree instead of theirs.

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

* tag 'driver-core-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (39 commits)
  drm/bridge: lvds-codec: simplify error handling
  drm/bridge/sii8620: fix resource acquisition error handling
  driver core: add deferring probe reason to devices_deferred property
  driver core: add device probe log helper
  driver core: Avoid binding drivers to dead devices
  Revert "test_firmware: Test platform fw loading on non-EFI systems"
  firmware_loader: EFI firmware loader must handle pre-allocated buffer
  selftest/firmware: Add selftest timeout in settings
  test_firmware: Test platform fw loading on non-EFI systems
  driver core: Change delimiter in devlink device's name to "--"
  debugfs: Add access restriction option
  tracefs: Remove unnecessary debug_fs checks.
  driver core: Fix probe_count imbalance in really_probe()
  kobject: remove unused KOBJ_MAX action
  driver core: Fix sleeping in invalid context during device link deletion
  driver core: Add waiting_for_supplier sysfs file for devices
  driver core: Add state_synced sysfs file for devices that support it
  driver core: Expose device link details in sysfs
  driver core: Drop mention of obsolete bus rwsem from kernel-doc
  debugfs: file: Remove unnecessary cast in kfree()
  ...
parents 1785d116 76acb5ee
...@@ -18,3 +18,13 @@ Description: ...@@ -18,3 +18,13 @@ Description:
devices to opt-out of driver binding using a driver_override devices to opt-out of driver binding using a driver_override
name such as "none". Only a single driver may be specified in name such as "none". Only a single driver may be specified in
the override, there is no support for parsing delimiters. the override, there is no support for parsing delimiters.
What: /sys/bus/platform/devices/.../numa_node
Date: June 2020
Contact: Barry Song <song.bao.hua@hisilicon.com>
Description:
This file contains the NUMA node to which the platform device
is attached. It won't be visible if the node is unknown. The
value comes from an ACPI _PXM method or a similar firmware
source. Initial users for this file would be devices like
arm smmu which are populated by arm64 acpi_iort.
What: /sys/class/devlink/.../
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
Provide a place in sysfs for the device link objects in the
kernel at any given time. The name of a device link directory,
denoted as ... above, is of the form <supplier>--<consumer>
where <supplier> is the supplier device name and <consumer> is
the consumer device name.
What: /sys/class/devlink/.../auto_remove_on
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file indicates if the device link will ever be
automatically removed by the driver core when the consumer and
supplier devices themselves are still present.
This will be one of the following strings:
'consumer unbind'
'supplier unbind'
'never'
'consumer unbind' means the device link will be removed when
the consumer's driver is unbound from the consumer device.
'supplier unbind' means the device link will be removed when
the supplier's driver is unbound from the supplier device.
'never' means the device link will not be automatically removed
when as long as the supplier and consumer devices themselves
are still present.
What: /sys/class/devlink/.../consumer
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file is a symlink to the consumer device's sysfs directory.
What: /sys/class/devlink/.../runtime_pm
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file indicates if the device link has any impact on the
runtime power management behavior of the consumer and supplier
devices. For example: Making sure the supplier doesn't enter
runtime suspend while the consumer is active.
This will be one of the following strings:
'0' - Does not affect runtime power management
'1' - Affects runtime power management
What: /sys/class/devlink/.../status
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file indicates the status of the device link. The status
of a device link is affected by whether the supplier and
consumer devices have been bound to their corresponding
drivers. The status of a device link also affects the binding
and unbinding of the supplier and consumer devices with their
drivers and also affects whether the software state of the
supplier device is synced with the hardware state of the
supplier device after boot up.
See also: sysfs-devices-state_synced.
This will be one of the following strings:
'not tracked'
'dormant'
'available'
'consumer probing'
'active'
'supplier unbinding'
'unknown'
'not tracked' means this device link does not track the status
and has no impact on the binding, unbinding and syncing the
hardware and software device state.
'dormant' means the supplier and the consumer devices have not
bound to their driver.
'available' means the supplier has bound to its driver and is
available to supply resources to the consumer device.
'consumer probing' means the consumer device is currently
trying to bind to its driver.
'active' means the supplier and consumer devices have both
bound successfully to their drivers.
'supplier unbinding' means the supplier devices is currently in
the process of unbinding from its driver.
'unknown' means the state of the device link is not any of the
above. If this is ever the value, there's a bug in the kernel.
What: /sys/class/devlink/.../supplier
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file is a symlink to the supplier device's sysfs directory.
What: /sys/class/devlink/.../sync_state_only
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
This file indicates if the device link is limited to only
affecting the syncing of the hardware and software state of the
supplier device.
This will be one of the following strings:
'0'
'1' - Affects runtime power management
'0' means the device link can affect other device behaviors
like binding/unbinding, suspend/resume, runtime power
management, etc.
'1' means the device link will only affect the syncing of
hardware and software state of the supplier device after boot
up and doesn't not affect other behaviors of the devices.
What: /sys/devices/.../consumer:<consumer>
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
The /sys/devices/.../consumer:<consumer> are symlinks to device
links where this device is the supplier. <consumer> denotes the
name of the consumer in that device link. There can be zero or
more of these symlinks for a given device.
What: /sys/devices/.../state_synced
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
The /sys/devices/.../state_synced attribute is only present for
devices whose bus types or driver provides the .sync_state()
callback. The number read from it (0 or 1) reflects the value
of the device's 'state_synced' field. A value of 0 means the
.sync_state() callback hasn't been called yet. A value of 1
means the .sync_state() callback has been called.
Generally, if a device has sync_state() support and has some of
the resources it provides enabled at the time the kernel starts
(Eg: enabled by hardware reset or bootloader or anything that
run before the kernel starts), then it'll keep those resources
enabled and in a state that's compatible with the state they
were in at the start of the kernel. The device will stop doing
this only when the sync_state() callback has been called --
which happens only when all its consumer devices are registered
and have probed successfully. Resources that were left disabled
at the time the kernel starts are not affected or limited in
any way by sync_state() callbacks.
What: /sys/devices/.../supplier:<supplier>
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
The /sys/devices/.../supplier:<supplier> are symlinks to device
links where this device is the consumer. <supplier> denotes the
name of the supplier in that device link. There can be zero or
more of these symlinks for a given device.
What: /sys/devices/.../waiting_for_supplier
Date: May 2020
Contact: Saravana Kannan <saravanak@google.com>
Description:
The /sys/devices/.../waiting_for_supplier attribute is only
present when fw_devlink kernel command line option is enabled
and is set to something stricter than "permissive". It is
removed once a device probes successfully (because the
information is no longer relevant). The number read from it (0
or 1) reflects whether the device is waiting for one or more
suppliers to be added and then linked to using device links
before the device can probe.
A value of 0 means the device is not waiting for any suppliers
to be added before it can probe. A value of 1 means the device
is waiting for one or more suppliers to be added before it can
probe.
...@@ -832,6 +832,21 @@ ...@@ -832,6 +832,21 @@
useful to also enable the page_owner functionality. useful to also enable the page_owner functionality.
on: enable the feature on: enable the feature
debugfs= [KNL] This parameter enables what is exposed to userspace
and debugfs internal clients.
Format: { on, no-mount, off }
on: All functions are enabled.
no-mount:
Filesystem is not registered but kernel clients can
access APIs and a crashkernel can be used to read
its content. There is nothing to mount.
off: Filesystem is not registered and clients
get a -EPERM as result when trying to register files
or directories within debugfs.
This is equivalent of the runtime functionality if
debugfs was not enabled in the kernel at all.
Default value is set in build-time with a kernel configuration.
debugpat [X86] Enable PAT debugging debugpat [X86] Enable PAT debugging
decnet.addr= [HW,NET] decnet.addr= [HW,NET]
......
...@@ -108,7 +108,7 @@ field to hold additional information. ...@@ -108,7 +108,7 @@ field to hold additional information.
Embedded systems frequently need one or more clocks for platform devices, Embedded systems frequently need one or more clocks for platform devices,
which are normally kept off until they're actively needed (to save power). which are normally kept off until they're actively needed (to save power).
System setup also associates those clocks with the device, so that that System setup also associates those clocks with the device, so that
calls to clk_get(&pdev->dev, clock_name) return them as needed. calls to clk_get(&pdev->dev, clock_name) return them as needed.
......
...@@ -93,6 +93,7 @@ struct device_private { ...@@ -93,6 +93,7 @@ struct device_private {
struct klist_node knode_class; struct klist_node knode_class;
struct list_head deferred_probe; struct list_head deferred_probe;
struct device_driver *async_driver; struct device_driver *async_driver;
char *deferred_probe_reason;
struct device *device; struct device *device;
u8 dead:1; u8 dead:1;
}; };
...@@ -134,6 +135,8 @@ extern void device_release_driver_internal(struct device *dev, ...@@ -134,6 +135,8 @@ extern void device_release_driver_internal(struct device *dev,
extern void driver_detach(struct device_driver *drv); extern void driver_detach(struct device_driver *drv);
extern int driver_probe_device(struct device_driver *drv, struct device *dev); extern int driver_probe_device(struct device_driver *drv, struct device *dev);
extern void driver_deferred_probe_del(struct device *dev); extern void driver_deferred_probe_del(struct device *dev);
extern void device_set_deferred_probe_reason(const struct device *dev,
struct va_format *vaf);
static inline int driver_match_device(struct device_driver *drv, static inline int driver_match_device(struct device_driver *drv,
struct device *dev) struct device *dev)
{ {
......
This diff is collapsed.
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/async.h> #include <linux/async.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pinctrl/devinfo.h> #include <linux/pinctrl/devinfo.h>
#include <linux/slab.h>
#include "base.h" #include "base.h"
#include "power/power.h" #include "power/power.h"
...@@ -136,6 +137,8 @@ void driver_deferred_probe_del(struct device *dev) ...@@ -136,6 +137,8 @@ void driver_deferred_probe_del(struct device *dev)
if (!list_empty(&dev->p->deferred_probe)) { if (!list_empty(&dev->p->deferred_probe)) {
dev_dbg(dev, "Removed from deferred list\n"); dev_dbg(dev, "Removed from deferred list\n");
list_del_init(&dev->p->deferred_probe); list_del_init(&dev->p->deferred_probe);
kfree(dev->p->deferred_probe_reason);
dev->p->deferred_probe_reason = NULL;
} }
mutex_unlock(&deferred_probe_mutex); mutex_unlock(&deferred_probe_mutex);
} }
...@@ -206,6 +209,23 @@ void device_unblock_probing(void) ...@@ -206,6 +209,23 @@ void device_unblock_probing(void)
driver_deferred_probe_trigger(); driver_deferred_probe_trigger();
} }
/**
* device_set_deferred_probe_reason() - Set defer probe reason message for device
* @dev: the pointer to the struct device
* @vaf: the pointer to va_format structure with message
*/
void device_set_deferred_probe_reason(const struct device *dev, struct va_format *vaf)
{
const char *drv = dev_driver_string(dev);
mutex_lock(&deferred_probe_mutex);
kfree(dev->p->deferred_probe_reason);
dev->p->deferred_probe_reason = kasprintf(GFP_KERNEL, "%s: %pV", drv, vaf);
mutex_unlock(&deferred_probe_mutex);
}
/* /*
* deferred_devs_show() - Show the devices in the deferred probe pending list. * deferred_devs_show() - Show the devices in the deferred probe pending list.
*/ */
...@@ -216,7 +236,8 @@ static int deferred_devs_show(struct seq_file *s, void *data) ...@@ -216,7 +236,8 @@ static int deferred_devs_show(struct seq_file *s, void *data)
mutex_lock(&deferred_probe_mutex); mutex_lock(&deferred_probe_mutex);
list_for_each_entry(curr, &deferred_probe_pending_list, deferred_probe) list_for_each_entry(curr, &deferred_probe_pending_list, deferred_probe)
seq_printf(s, "%s\n", dev_name(curr->device)); seq_printf(s, "%s\t%s", dev_name(curr->device),
curr->device->p->deferred_probe_reason ?: "\n");
mutex_unlock(&deferred_probe_mutex); mutex_unlock(&deferred_probe_mutex);
...@@ -276,7 +297,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work) ...@@ -276,7 +297,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe) list_for_each_entry_safe(private, p, &deferred_probe_pending_list, deferred_probe)
dev_info(private->device, "deferred probe pending\n"); dev_info(private->device, "deferred probe pending\n");
wake_up(&probe_timeout_waitqueue); wake_up_all(&probe_timeout_waitqueue);
} }
static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func); static DECLARE_DELAYED_WORK(deferred_probe_timeout_work, deferred_probe_timeout_work_func);
...@@ -425,10 +446,9 @@ static void driver_sysfs_remove(struct device *dev) ...@@ -425,10 +446,9 @@ static void driver_sysfs_remove(struct device *dev)
* Allow manual attachment of a driver to a device. * Allow manual attachment of a driver to a device.
* Caller must have already set @dev->driver. * Caller must have already set @dev->driver.
* *
* Note that this does not modify the bus reference count * Note that this does not modify the bus reference count.
* nor take the bus's rwsem. Please verify those are accounted * Please verify that is accounted for before calling this.
* for before calling this. (It is ok to call with no other effort * (It is ok to call with no other effort from a driver's probe() method.)
* from a driver's probe() method.)
* *
* This function must be called with the device lock held. * This function must be called with the device lock held.
*/ */
...@@ -458,6 +478,18 @@ static void driver_deferred_probe_add_trigger(struct device *dev, ...@@ -458,6 +478,18 @@ static void driver_deferred_probe_add_trigger(struct device *dev,
driver_deferred_probe_trigger(); driver_deferred_probe_trigger();
} }
static ssize_t state_synced_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
bool val;
device_lock(dev);
val = dev->state_synced;
device_unlock(dev);
return sprintf(buf, "%u\n", val);
}
static DEVICE_ATTR_RO(state_synced);
static int really_probe(struct device *dev, struct device_driver *drv) static int really_probe(struct device *dev, struct device_driver *drv)
{ {
int ret = -EPROBE_DEFER; int ret = -EPROBE_DEFER;
...@@ -487,7 +519,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -487,7 +519,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
drv->bus->name, __func__, drv->name, dev_name(dev)); drv->bus->name, __func__, drv->name, dev_name(dev));
if (!list_empty(&dev->devres_head)) { if (!list_empty(&dev->devres_head)) {
dev_crit(dev, "Resources present before probing\n"); dev_crit(dev, "Resources present before probing\n");
return -EBUSY; ret = -EBUSY;
goto done;
} }
re_probe: re_probe:
...@@ -531,9 +564,16 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -531,9 +564,16 @@ static int really_probe(struct device *dev, struct device_driver *drv)
goto dev_groups_failed; goto dev_groups_failed;
} }
if (dev_has_sync_state(dev) &&
device_create_file(dev, &dev_attr_state_synced)) {
dev_err(dev, "state_synced sysfs add failed\n");
goto dev_sysfs_state_synced_failed;
}
if (test_remove) { if (test_remove) {
test_remove = false; test_remove = false;
device_remove_file(dev, &dev_attr_state_synced);
device_remove_groups(dev, drv->dev_groups); device_remove_groups(dev, drv->dev_groups);
if (dev->bus->remove) if (dev->bus->remove)
...@@ -563,6 +603,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -563,6 +603,8 @@ static int really_probe(struct device *dev, struct device_driver *drv)
drv->bus->name, __func__, dev_name(dev), drv->name); drv->bus->name, __func__, dev_name(dev), drv->name);
goto done; goto done;
dev_sysfs_state_synced_failed:
device_remove_groups(dev, drv->dev_groups);
dev_groups_failed: dev_groups_failed:
if (dev->bus->remove) if (dev->bus->remove)
dev->bus->remove(dev); dev->bus->remove(dev);
...@@ -607,7 +649,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) ...@@ -607,7 +649,7 @@ static int really_probe(struct device *dev, struct device_driver *drv)
ret = 0; ret = 0;
done: done:
atomic_dec(&probe_count); atomic_dec(&probe_count);
wake_up(&probe_waitqueue); wake_up_all(&probe_waitqueue);
return ret; return ret;
} }
...@@ -843,7 +885,9 @@ static int __device_attach(struct device *dev, bool allow_async) ...@@ -843,7 +885,9 @@ static int __device_attach(struct device *dev, bool allow_async)
int ret = 0; int ret = 0;
device_lock(dev); device_lock(dev);
if (dev->driver) { if (dev->p->dead) {
goto out_unlock;
} else if (dev->driver) {
if (device_is_bound(dev)) { if (device_is_bound(dev)) {
ret = 1; ret = 1;
goto out_unlock; goto out_unlock;
...@@ -1100,6 +1144,7 @@ static void __device_release_driver(struct device *dev, struct device *parent) ...@@ -1100,6 +1144,7 @@ static void __device_release_driver(struct device *dev, struct device *parent)
pm_runtime_put_sync(dev); pm_runtime_put_sync(dev);
device_remove_file(dev, &dev_attr_state_synced);
device_remove_groups(dev, drv->dev_groups); device_remove_groups(dev, drv->dev_groups);
if (dev->bus && dev->bus->remove) if (dev->bus && dev->bus->remove)
......
...@@ -89,15 +89,23 @@ static struct devres_group * node_to_group(struct devres_node *node) ...@@ -89,15 +89,23 @@ static struct devres_group * node_to_group(struct devres_node *node)
return NULL; return NULL;
} }
static bool check_dr_size(size_t size, size_t *tot_size)
{
/* We must catch any near-SIZE_MAX cases that could overflow. */
if (unlikely(check_add_overflow(sizeof(struct devres),
size, tot_size)))
return false;
return true;
}
static __always_inline struct devres * alloc_dr(dr_release_t release, static __always_inline struct devres * alloc_dr(dr_release_t release,
size_t size, gfp_t gfp, int nid) size_t size, gfp_t gfp, int nid)
{ {
size_t tot_size; size_t tot_size;
struct devres *dr; struct devres *dr;
/* We must catch any near-SIZE_MAX cases that could overflow. */ if (!check_dr_size(size, &tot_size))
if (unlikely(check_add_overflow(sizeof(struct devres), size,
&tot_size)))
return NULL; return NULL;
dr = kmalloc_node_track_caller(tot_size, gfp, nid); dr = kmalloc_node_track_caller(tot_size, gfp, nid);
...@@ -807,10 +815,13 @@ static int devm_kmalloc_match(struct device *dev, void *res, void *data) ...@@ -807,10 +815,13 @@ static int devm_kmalloc_match(struct device *dev, void *res, void *data)
* RETURNS: * RETURNS:
* Pointer to allocated memory on success, NULL on failure. * Pointer to allocated memory on success, NULL on failure.
*/ */
void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
{ {
struct devres *dr; struct devres *dr;
if (unlikely(!size))
return ZERO_SIZE_PTR;
/* use raw alloc_dr for kmalloc caller tracing */ /* use raw alloc_dr for kmalloc caller tracing */
dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev)); dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev));
if (unlikely(!dr)) if (unlikely(!dr))
...@@ -942,10 +953,10 @@ void devm_kfree(struct device *dev, const void *p) ...@@ -942,10 +953,10 @@ void devm_kfree(struct device *dev, const void *p)
int rc; int rc;
/* /*
* Special case: pointer to a string in .rodata returned by * Special cases: pointer to a string in .rodata returned by
* devm_kstrdup_const(). * devm_kstrdup_const() or NULL/ZERO ptr.
*/ */
if (unlikely(is_kernel_rodata((unsigned long)p))) if (unlikely(is_kernel_rodata((unsigned long)p) || ZERO_OR_NULL_PTR(p)))
return; return;
rc = devres_destroy(dev, devm_kmalloc_release, rc = devres_destroy(dev, devm_kmalloc_release,
......
...@@ -158,12 +158,12 @@ int driver_register(struct device_driver *drv) ...@@ -158,12 +158,12 @@ int driver_register(struct device_driver *drv)
if ((drv->bus->probe && drv->probe) || if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) || (drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown)) (drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use " pr_warn("Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name); "bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus); other = driver_find(drv->name, drv->bus);
if (other) { if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, " pr_err("Error: Driver '%s' is already registered, "
"aborting...\n", drv->name); "aborting...\n", drv->name);
return -EBUSY; return -EBUSY;
} }
......
...@@ -25,6 +25,9 @@ int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags) ...@@ -25,6 +25,9 @@ int firmware_fallback_platform(struct fw_priv *fw_priv, u32 opt_flags)
if (rc) if (rc)
return rc; /* rc == -ENOENT when the fw was not found */ return rc; /* rc == -ENOENT when the fw was not found */
if (fw_priv->data && size > fw_priv->allocated_size)
return -ENOMEM;
if (!fw_priv->data)
fw_priv->data = vmalloc(size); fw_priv->data = vmalloc(size);
if (!fw_priv->data) if (!fw_priv->data)
return -ENOMEM; return -ENOMEM;
......
...@@ -838,12 +838,12 @@ EXPORT_SYMBOL(request_firmware); ...@@ -838,12 +838,12 @@ EXPORT_SYMBOL(request_firmware);
* @name: name of firmware file * @name: name of firmware file
* @device: device for which firmware is being loaded * @device: device for which firmware is being loaded
* *
* This function is similar in behaviour to request_firmware(), except * This function is similar in behaviour to request_firmware(), except it
* it doesn't produce warning messages when the file is not found. * doesn't produce warning messages when the file is not found. The sysfs
* The sysfs fallback mechanism is enabled if direct filesystem lookup fails, * fallback mechanism is enabled if direct filesystem lookup fails. However,
* however, however failures to find the firmware file with it are still * failures to find the firmware file with it are still suppressed. It is
* suppressed. It is therefore up to the driver to check for the return value * therefore up to the driver to check for the return value of this call and to
* of this call and to decide when to inform the users of errors. * decide when to inform the users of errors.
**/ **/
int firmware_request_nowarn(const struct firmware **firmware, const char *name, int firmware_request_nowarn(const struct firmware **firmware, const char *name,
struct device *device) struct device *device)
......
...@@ -50,14 +50,14 @@ int memhp_online_type_from_str(const char *str) ...@@ -50,14 +50,14 @@ int memhp_online_type_from_str(const char *str)
static int sections_per_block; static int sections_per_block;
static inline unsigned long base_memory_block_id(unsigned long section_nr) static inline unsigned long memory_block_id(unsigned long section_nr)
{ {
return section_nr / sections_per_block; return section_nr / sections_per_block;
} }
static inline unsigned long pfn_to_block_id(unsigned long pfn) static inline unsigned long pfn_to_block_id(unsigned long pfn)
{ {
return base_memory_block_id(pfn_to_section_nr(pfn)); return memory_block_id(pfn_to_section_nr(pfn));
} }
static inline unsigned long phys_to_block_id(unsigned long phys) static inline unsigned long phys_to_block_id(unsigned long phys)
...@@ -517,7 +517,7 @@ static struct memory_block *find_memory_block_by_id(unsigned long block_id) ...@@ -517,7 +517,7 @@ static struct memory_block *find_memory_block_by_id(unsigned long block_id)
*/ */
struct memory_block *find_memory_block(struct mem_section *section) struct memory_block *find_memory_block(struct mem_section *section)
{ {
unsigned long block_id = base_memory_block_id(__section_nr(section)); unsigned long block_id = memory_block_id(__section_nr(section));
return find_memory_block_by_id(block_id); return find_memory_block_by_id(block_id);
} }
...@@ -570,8 +570,7 @@ int register_memory(struct memory_block *memory) ...@@ -570,8 +570,7 @@ int register_memory(struct memory_block *memory)
return ret; return ret;
} }
static int init_memory_block(struct memory_block **memory, static int init_memory_block(unsigned long block_id, unsigned long state)
unsigned long block_id, unsigned long state)
{ {
struct memory_block *mem; struct memory_block *mem;
unsigned long start_pfn; unsigned long start_pfn;
...@@ -594,14 +593,12 @@ static int init_memory_block(struct memory_block **memory, ...@@ -594,14 +593,12 @@ static int init_memory_block(struct memory_block **memory,
ret = register_memory(mem); ret = register_memory(mem);
*memory = mem;
return ret; return ret;
} }
static int add_memory_block(unsigned long base_section_nr) static int add_memory_block(unsigned long base_section_nr)
{ {
int section_count = 0; int section_count = 0;
struct memory_block *mem;
unsigned long nr; unsigned long nr;
for (nr = base_section_nr; nr < base_section_nr + sections_per_block; for (nr = base_section_nr; nr < base_section_nr + sections_per_block;
...@@ -611,7 +608,7 @@ static int add_memory_block(unsigned long base_section_nr) ...@@ -611,7 +608,7 @@ static int add_memory_block(unsigned long base_section_nr)
if (section_count == 0) if (section_count == 0)
return 0; return 0;
return init_memory_block(&mem, base_memory_block_id(base_section_nr), return init_memory_block(memory_block_id(base_section_nr),
MEM_ONLINE); MEM_ONLINE);
} }
...@@ -647,7 +644,7 @@ int create_memory_block_devices(unsigned long start, unsigned long size) ...@@ -647,7 +644,7 @@ int create_memory_block_devices(unsigned long start, unsigned long size)
return -EINVAL; return -EINVAL;
for (block_id = start_block_id; block_id != end_block_id; block_id++) { for (block_id = start_block_id; block_id != end_block_id; block_id++) {
ret = init_memory_block(&mem, block_id, MEM_OFFLINE); ret = init_memory_block(block_id, MEM_OFFLINE);
if (ret) if (ret)
break; break;
} }
......
...@@ -1019,7 +1019,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a, ...@@ -1019,7 +1019,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
if (len != -ENODEV) if (len != -ENODEV)
return len; return len;
len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1);
if (len != -ENODEV) if (len != -ENODEV)
return len; return len;
...@@ -1076,13 +1076,37 @@ static ssize_t driver_override_show(struct device *dev, ...@@ -1076,13 +1076,37 @@ static ssize_t driver_override_show(struct device *dev,
} }
static DEVICE_ATTR_RW(driver_override); static DEVICE_ATTR_RW(driver_override);
static ssize_t numa_node_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", dev_to_node(dev));
}
static DEVICE_ATTR_RO(numa_node);
static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute *a,
int n)
{
struct device *dev = container_of(kobj, typeof(*dev), kobj);
if (a == &dev_attr_numa_node.attr &&
dev_to_node(dev) == NUMA_NO_NODE)
return 0;
return a->mode;
}
static struct attribute *platform_dev_attrs[] = { static struct attribute *platform_dev_attrs[] = {
&dev_attr_modalias.attr, &dev_attr_modalias.attr,
&dev_attr_numa_node.attr,
&dev_attr_driver_override.attr, &dev_attr_driver_override.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(platform_dev);
static struct attribute_group platform_dev_group = {
.attrs = platform_dev_attrs,
.is_visible = platform_dev_attrs_visible,
};
__ATTRIBUTE_GROUPS(platform_dev);
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
{ {
......
...@@ -761,17 +761,13 @@ EXPORT_SYMBOL_GPL(software_node_register_node_group); ...@@ -761,17 +761,13 @@ EXPORT_SYMBOL_GPL(software_node_register_node_group);
*/ */
void software_node_unregister_node_group(const struct software_node **node_group) void software_node_unregister_node_group(const struct software_node **node_group)
{ {
struct swnode *swnode;
unsigned int i; unsigned int i;
if (!node_group) if (!node_group)
return; return;
for (i = 0; node_group[i]; i++) { for (i = 0; node_group[i]; i++)
swnode = software_node_to_swnode(node_group[i]); software_node_unregister(node_group[i]);
if (swnode)
fwnode_remove_software_node(&swnode->fwnode);
}
} }
EXPORT_SYMBOL_GPL(software_node_unregister_node_group); EXPORT_SYMBOL_GPL(software_node_unregister_node_group);
......
...@@ -133,7 +133,7 @@ static int topology_remove_dev(unsigned int cpu) ...@@ -133,7 +133,7 @@ static int topology_remove_dev(unsigned int cpu)
return 0; return 0;
} }
static int topology_sysfs_init(void) static int __init topology_sysfs_init(void)
{ {
return cpuhp_setup_state(CPUHP_TOPOLOGY_PREPARE, return cpuhp_setup_state(CPUHP_TOPOLOGY_PREPARE,
"base/topology:prepare", topology_add_dev, "base/topology:prepare", topology_add_dev,
......
...@@ -71,13 +71,9 @@ static int lvds_codec_probe(struct platform_device *pdev) ...@@ -71,13 +71,9 @@ static int lvds_codec_probe(struct platform_device *pdev)
lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev); lvds_codec->connector_type = (uintptr_t)of_device_get_match_data(dev);
lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", lvds_codec->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown",
GPIOD_OUT_HIGH); GPIOD_OUT_HIGH);
if (IS_ERR(lvds_codec->powerdown_gpio)) { if (IS_ERR(lvds_codec->powerdown_gpio))
int err = PTR_ERR(lvds_codec->powerdown_gpio); return dev_err_probe(dev, PTR_ERR(lvds_codec->powerdown_gpio),
"powerdown GPIO failure\n");
if (err != -EPROBE_DEFER)
dev_err(dev, "powerdown GPIO failure: %d\n", err);
return err;
}
/* Locate the panel DT node. */ /* Locate the panel DT node. */
panel_node = of_graph_get_remote_node(dev->of_node, 1, 0); panel_node = of_graph_get_remote_node(dev->of_node, 1, 0);
......
...@@ -2299,10 +2299,9 @@ static int sii8620_probe(struct i2c_client *client, ...@@ -2299,10 +2299,9 @@ static int sii8620_probe(struct i2c_client *client,
INIT_LIST_HEAD(&ctx->mt_queue); INIT_LIST_HEAD(&ctx->mt_queue);
ctx->clk_xtal = devm_clk_get(dev, "xtal"); ctx->clk_xtal = devm_clk_get(dev, "xtal");
if (IS_ERR(ctx->clk_xtal)) { if (IS_ERR(ctx->clk_xtal))
dev_err(dev, "failed to get xtal clock from DT\n"); return dev_err_probe(dev, PTR_ERR(ctx->clk_xtal),
return PTR_ERR(ctx->clk_xtal); "failed to get xtal clock from DT\n");
}
if (!client->irq) { if (!client->irq) {
dev_err(dev, "no irq provided\n"); dev_err(dev, "no irq provided\n");
...@@ -2313,16 +2312,14 @@ static int sii8620_probe(struct i2c_client *client, ...@@ -2313,16 +2312,14 @@ static int sii8620_probe(struct i2c_client *client,
sii8620_irq_thread, sii8620_irq_thread,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"sii8620", ctx); "sii8620", ctx);
if (ret < 0) { if (ret < 0)
dev_err(dev, "failed to install IRQ handler\n"); return dev_err_probe(dev, ret,
return ret; "failed to install IRQ handler\n");
}
ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); ctx->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->gpio_reset)) { if (IS_ERR(ctx->gpio_reset))
dev_err(dev, "failed to get reset gpio from DT\n"); return dev_err_probe(dev, PTR_ERR(ctx->gpio_reset),
return PTR_ERR(ctx->gpio_reset); "failed to get reset gpio from DT\n");
}
ctx->supplies[0].supply = "cvcc10"; ctx->supplies[0].supply = "cvcc10";
ctx->supplies[1].supply = "iovcc18"; ctx->supplies[1].supply = "iovcc18";
......
...@@ -273,7 +273,7 @@ static int full_proxy_release(struct inode *inode, struct file *filp) ...@@ -273,7 +273,7 @@ static int full_proxy_release(struct inode *inode, struct file *filp)
r = real_fops->release(inode, filp); r = real_fops->release(inode, filp);
replace_fops(filp, d_inode(dentry)->i_fop); replace_fops(filp, d_inode(dentry)->i_fop);
kfree((void *)proxy_fops); kfree(proxy_fops);
fops_put(real_fops); fops_put(real_fops);
return r; return r;
} }
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
static struct vfsmount *debugfs_mount; static struct vfsmount *debugfs_mount;
static int debugfs_mount_count; static int debugfs_mount_count;
static bool debugfs_registered; static bool debugfs_registered;
static unsigned int debugfs_allow = DEFAULT_DEBUGFS_ALLOW_BITS;
/* /*
* Don't allow access attributes to be changed whilst the kernel is locked down * Don't allow access attributes to be changed whilst the kernel is locked down
...@@ -266,6 +267,9 @@ static struct dentry *debug_mount(struct file_system_type *fs_type, ...@@ -266,6 +267,9 @@ static struct dentry *debug_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, int flags, const char *dev_name,
void *data) void *data)
{ {
if (!(debugfs_allow & DEBUGFS_ALLOW_API))
return ERR_PTR(-EPERM);
return mount_single(fs_type, flags, data, debug_fill_super); return mount_single(fs_type, flags, data, debug_fill_super);
} }
...@@ -311,6 +315,9 @@ static struct dentry *start_creating(const char *name, struct dentry *parent) ...@@ -311,6 +315,9 @@ static struct dentry *start_creating(const char *name, struct dentry *parent)
struct dentry *dentry; struct dentry *dentry;
int error; int error;
if (!(debugfs_allow & DEBUGFS_ALLOW_API))
return ERR_PTR(-EPERM);
pr_debug("creating file '%s'\n", name); pr_debug("creating file '%s'\n", name);
if (IS_ERR(parent)) if (IS_ERR(parent))
...@@ -385,6 +392,11 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode, ...@@ -385,6 +392,11 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode,
if (IS_ERR(dentry)) if (IS_ERR(dentry))
return dentry; return dentry;
if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {
failed_creating(dentry);
return ERR_PTR(-EPERM);
}
inode = debugfs_get_inode(dentry->d_sb); inode = debugfs_get_inode(dentry->d_sb);
if (unlikely(!inode)) { if (unlikely(!inode)) {
pr_err("out of free dentries, can not create file '%s'\n", pr_err("out of free dentries, can not create file '%s'\n",
...@@ -541,6 +553,11 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) ...@@ -541,6 +553,11 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
if (IS_ERR(dentry)) if (IS_ERR(dentry))
return dentry; return dentry;
if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {
failed_creating(dentry);
return ERR_PTR(-EPERM);
}
inode = debugfs_get_inode(dentry->d_sb); inode = debugfs_get_inode(dentry->d_sb);
if (unlikely(!inode)) { if (unlikely(!inode)) {
pr_err("out of free dentries, can not create directory '%s'\n", pr_err("out of free dentries, can not create directory '%s'\n",
...@@ -583,6 +600,11 @@ struct dentry *debugfs_create_automount(const char *name, ...@@ -583,6 +600,11 @@ struct dentry *debugfs_create_automount(const char *name,
if (IS_ERR(dentry)) if (IS_ERR(dentry))
return dentry; return dentry;
if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {
failed_creating(dentry);
return ERR_PTR(-EPERM);
}
inode = debugfs_get_inode(dentry->d_sb); inode = debugfs_get_inode(dentry->d_sb);
if (unlikely(!inode)) { if (unlikely(!inode)) {
pr_err("out of free dentries, can not create automount '%s'\n", pr_err("out of free dentries, can not create automount '%s'\n",
...@@ -786,10 +808,27 @@ bool debugfs_initialized(void) ...@@ -786,10 +808,27 @@ bool debugfs_initialized(void)
} }
EXPORT_SYMBOL_GPL(debugfs_initialized); EXPORT_SYMBOL_GPL(debugfs_initialized);
static int __init debugfs_kernel(char *str)
{
if (str) {
if (!strcmp(str, "on"))
debugfs_allow = DEBUGFS_ALLOW_API | DEBUGFS_ALLOW_MOUNT;
else if (!strcmp(str, "no-mount"))
debugfs_allow = DEBUGFS_ALLOW_API;
else if (!strcmp(str, "off"))
debugfs_allow = 0;
}
return 0;
}
early_param("debugfs", debugfs_kernel);
static int __init debugfs_init(void) static int __init debugfs_init(void)
{ {
int retval; int retval;
if (!(debugfs_allow & DEBUGFS_ALLOW_MOUNT))
return -EPERM;
retval = sysfs_create_mount_point(kernel_kobj, "debug"); retval = sysfs_create_mount_point(kernel_kobj, "debug");
if (retval) if (retval)
return retval; return retval;
......
...@@ -29,4 +29,18 @@ struct debugfs_fsdata { ...@@ -29,4 +29,18 @@ struct debugfs_fsdata {
*/ */
#define DEBUGFS_FSDATA_IS_REAL_FOPS_BIT BIT(0) #define DEBUGFS_FSDATA_IS_REAL_FOPS_BIT BIT(0)
/* Access BITS */
#define DEBUGFS_ALLOW_API BIT(0)
#define DEBUGFS_ALLOW_MOUNT BIT(1)
#ifdef CONFIG_DEBUG_FS_ALLOW_ALL
#define DEFAULT_DEBUGFS_ALLOW_BITS (DEBUGFS_ALLOW_MOUNT | DEBUGFS_ALLOW_API)
#endif
#ifdef CONFIG_DEBUG_FS_DISALLOW_MOUNT
#define DEFAULT_DEBUGFS_ALLOW_BITS (DEBUGFS_ALLOW_API)
#endif
#ifdef CONFIG_DEBUG_FS_ALLOW_NONE
#define DEFAULT_DEBUGFS_ALLOW_BITS (0)
#endif
#endif /* _DEBUGFS_INTERNAL_H_ */ #endif /* _DEBUGFS_INTERNAL_H_ */
This diff is collapsed.
...@@ -59,7 +59,6 @@ enum kobject_action { ...@@ -59,7 +59,6 @@ enum kobject_action {
KOBJ_OFFLINE, KOBJ_OFFLINE,
KOBJ_BIND, KOBJ_BIND,
KOBJ_UNBIND, KOBJ_UNBIND,
KOBJ_MAX
}; };
struct kobject { struct kobject {
......
...@@ -123,6 +123,13 @@ struct attribute_group { ...@@ -123,6 +123,13 @@ struct attribute_group {
.show = _name##_show, \ .show = _name##_show, \
} }
#define __ATTR_RW_MODE(_name, _mode) { \
.attr = { .name = __stringify(_name), \
.mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \
.show = _name##_show, \
.store = _name##_store, \
}
#define __ATTR_WO(_name) { \ #define __ATTR_WO(_name) { \
.attr = { .name = __stringify(_name), .mode = 0200 }, \ .attr = { .name = __stringify(_name), .mode = 0200 }, \
.store = _name##_store, \ .store = _name##_store, \
......
...@@ -8945,9 +8945,7 @@ struct dentry *tracing_init_dentry(void) ...@@ -8945,9 +8945,7 @@ struct dentry *tracing_init_dentry(void)
if (tr->dir) if (tr->dir)
return NULL; return NULL;
if (WARN_ON(!tracefs_initialized()) || if (WARN_ON(!tracefs_initialized()))
(IS_ENABLED(CONFIG_DEBUG_FS) &&
WARN_ON(!debugfs_initialized())))
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
/* /*
......
...@@ -476,6 +476,38 @@ config DEBUG_FS ...@@ -476,6 +476,38 @@ config DEBUG_FS
If unsure, say N. If unsure, say N.
choice
prompt "Debugfs default access"
depends on DEBUG_FS
default DEBUG_FS_ALLOW_ALL
help
This selects the default access restrictions for debugfs.
It can be overridden with kernel command line option
debugfs=[on,no-mount,off]. The restrictions apply for API access
and filesystem registration.
config DEBUG_FS_ALLOW_ALL
bool "Access normal"
help
No restrictions apply. Both API and filesystem registration
is on. This is the normal default operation.
config DEBUG_FS_DISALLOW_MOUNT
bool "Do not register debugfs as filesystem"
help
The API is open but filesystem is not loaded. Clients can still do
their work and read with debug tools that do not need
debugfs filesystem.
config DEBUG_FS_ALLOW_NONE
bool "No access"
help
Access is off. Clients get -PERM when trying to create nodes in
debugfs tree and debugfs is not registered as a filesystem.
Client can then back-off or continue without debugfs access.
endchoice
source "lib/Kconfig.kgdb" source "lib/Kconfig.kgdb"
source "lib/Kconfig.ubsan" source "lib/Kconfig.ubsan"
...@@ -844,10 +876,10 @@ config DEBUG_SHIRQ ...@@ -844,10 +876,10 @@ config DEBUG_SHIRQ
bool "Debug shared IRQ handlers" bool "Debug shared IRQ handlers"
depends on DEBUG_KERNEL depends on DEBUG_KERNEL
help help
Enable this to generate a spurious interrupt as soon as a shared Enable this to generate a spurious interrupt just before a shared
interrupt handler is registered, and just before one is deregistered. interrupt handler is deregistered (generating one when registering
Drivers ought to be able to handle interrupts coming in at those is currently disabled). Drivers need to handle this correctly. Some
points; some don't and need to be caught. don't and need to be caught.
menu "Debug Oops, Lockups and Hangs" menu "Debug Oops, Lockups and Hangs"
......
...@@ -119,6 +119,7 @@ __devm_ioremap_resource(struct device *dev, const struct resource *res, ...@@ -119,6 +119,7 @@ __devm_ioremap_resource(struct device *dev, const struct resource *res,
{ {
resource_size_t size; resource_size_t size;
void __iomem *dest_ptr; void __iomem *dest_ptr;
char *pretty_name;
BUG_ON(!dev); BUG_ON(!dev);
...@@ -129,7 +130,15 @@ __devm_ioremap_resource(struct device *dev, const struct resource *res, ...@@ -129,7 +130,15 @@ __devm_ioremap_resource(struct device *dev, const struct resource *res,
size = resource_size(res); size = resource_size(res);
if (!devm_request_mem_region(dev, res->start, size, dev_name(dev))) { if (res->name)
pretty_name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
dev_name(dev), res->name);
else
pretty_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
if (!pretty_name)
return IOMEM_ERR_PTR(-ENOMEM);
if (!devm_request_mem_region(dev, res->start, size, pretty_name)) {
dev_err(dev, "can't request region for resource %pR\n", res); dev_err(dev, "can't request region for resource %pR\n", res);
return IOMEM_ERR_PTR(-EBUSY); return IOMEM_ERR_PTR(-EBUSY);
} }
...@@ -204,6 +213,12 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev, ...@@ -204,6 +213,12 @@ void __iomem *devm_ioremap_resource_wc(struct device *dev,
* base = devm_of_iomap(&pdev->dev, node, 0, NULL); * base = devm_of_iomap(&pdev->dev, node, 0, NULL);
* if (IS_ERR(base)) * if (IS_ERR(base))
* return PTR_ERR(base); * return PTR_ERR(base);
*
* Please Note: This is not a one-to-one replacement for of_iomap() because the
* of_iomap() function does not track whether the region is already mapped. If
* two drivers try to map the same memory, the of_iomap() function will succeed
* but the the devm_of_iomap() function will return -EBUSY.
*
*/ */
void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index, void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index,
resource_size_t *size) resource_size_t *size)
......
...@@ -599,14 +599,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) ...@@ -599,14 +599,7 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent)
} }
EXPORT_SYMBOL_GPL(kobject_move); EXPORT_SYMBOL_GPL(kobject_move);
/** static void __kobject_del(struct kobject *kobj)
* kobject_del() - Unlink kobject from hierarchy.
* @kobj: object.
*
* This is the function that should be called to delete an object
* successfully added via kobject_add().
*/
void kobject_del(struct kobject *kobj)
{ {
struct kernfs_node *sd; struct kernfs_node *sd;
const struct kobj_type *ktype; const struct kobj_type *ktype;
...@@ -632,9 +625,23 @@ void kobject_del(struct kobject *kobj) ...@@ -632,9 +625,23 @@ void kobject_del(struct kobject *kobj)
kobj->state_in_sysfs = 0; kobj->state_in_sysfs = 0;
kobj_kset_leave(kobj); kobj_kset_leave(kobj);
kobject_put(kobj->parent);
kobj->parent = NULL; kobj->parent = NULL;
} }
/**
* kobject_del() - Unlink kobject from hierarchy.
* @kobj: object.
*
* This is the function that should be called to delete an object
* successfully added via kobject_add().
*/
void kobject_del(struct kobject *kobj)
{
struct kobject *parent = kobj->parent;
__kobject_del(kobj);
kobject_put(parent);
}
EXPORT_SYMBOL(kobject_del); EXPORT_SYMBOL(kobject_del);
/** /**
...@@ -670,6 +677,7 @@ EXPORT_SYMBOL(kobject_get_unless_zero); ...@@ -670,6 +677,7 @@ EXPORT_SYMBOL(kobject_get_unless_zero);
*/ */
static void kobject_cleanup(struct kobject *kobj) static void kobject_cleanup(struct kobject *kobj)
{ {
struct kobject *parent = kobj->parent;
struct kobj_type *t = get_ktype(kobj); struct kobj_type *t = get_ktype(kobj);
const char *name = kobj->name; const char *name = kobj->name;
...@@ -684,7 +692,10 @@ static void kobject_cleanup(struct kobject *kobj) ...@@ -684,7 +692,10 @@ static void kobject_cleanup(struct kobject *kobj)
if (kobj->state_in_sysfs) { if (kobj->state_in_sysfs) {
pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n", pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n",
kobject_name(kobj), kobj); kobject_name(kobj), kobj);
kobject_del(kobj); __kobject_del(kobj);
} else {
/* avoid dropping the parent reference unnecessarily */
parent = NULL;
} }
if (t && t->release) { if (t && t->release) {
...@@ -698,6 +709,8 @@ static void kobject_cleanup(struct kobject *kobj) ...@@ -698,6 +709,8 @@ static void kobject_cleanup(struct kobject *kobj)
pr_debug("kobject: '%s': free name\n", name); pr_debug("kobject: '%s': free name\n", name);
kfree_const(name); kfree_const(name);
} }
kobject_put(parent);
} }
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE #ifdef CONFIG_DEBUG_KOBJECT_RELEASE
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
/// add a missing namespace tag to a module source file. /// add a missing namespace tag to a module source file.
/// ///
virtual nsdeps
virtual report virtual report
@has_ns_import@ @has_ns_import@
...@@ -16,10 +17,15 @@ MODULE_IMPORT_NS(ns); ...@@ -16,10 +17,15 @@ MODULE_IMPORT_NS(ns);
// Add missing imports, but only adjacent to a MODULE_LICENSE statement. // Add missing imports, but only adjacent to a MODULE_LICENSE statement.
// That ensures we are adding it only to the main module source file. // That ensures we are adding it only to the main module source file.
@do_import depends on !has_ns_import@ @do_import depends on !has_ns_import && nsdeps@
declarer name MODULE_LICENSE; declarer name MODULE_LICENSE;
expression license; expression license;
identifier virtual.ns; identifier virtual.ns;
@@ @@
MODULE_LICENSE(license); MODULE_LICENSE(license);
+ MODULE_IMPORT_NS(ns); + MODULE_IMPORT_NS(ns);
// Dummy rule for report mode that would otherwise be empty and make spatch
// fail ("No rules apply.")
@script:python depends on report@
@@
...@@ -29,7 +29,7 @@ fi ...@@ -29,7 +29,7 @@ fi
generate_deps_for_ns() { generate_deps_for_ns() {
$SPATCH --very-quiet --in-place --sp-file \ $SPATCH --very-quiet --in-place --sp-file \
$srctree/scripts/coccinelle/misc/add_namespace.cocci -D ns=$1 $2 $srctree/scripts/coccinelle/misc/add_namespace.cocci -D nsdeps -D ns=$1 $2
} }
generate_deps() { generate_deps() {
......
# The async firmware timeout is set to 1 second (but ends up being effectively
# 2 seconds). There are 3 test configs, each done with and without firmware
# present, each with 2 "nowait" functions tested 5 times. Expected time for a
# normal execution should be 2 * 3 * 2 * 2 * 5 = 120 seconds for those alone.
# Additionally, fw_fallback may take 5 seconds for internal timeouts in each
# of the 3 configs, so at least another 15 seconds are needed. Add another
# 10 seconds for each testing config: 120 + 15 + 30
timeout=165
...@@ -53,6 +53,10 @@ run_one() ...@@ -53,6 +53,10 @@ run_one()
settings="$BASE_DIR/$DIR/settings" settings="$BASE_DIR/$DIR/settings"
if [ -r "$settings" ] ; then if [ -r "$settings" ] ; then
while read line ; do while read line ; do
# Skip comments.
if echo "$line" | grep -q '^#'; then
continue
fi
field=$(echo "$line" | cut -d= -f1) field=$(echo "$line" | cut -d= -f1)
value=$(echo "$line" | cut -d= -f2-) value=$(echo "$line" | cut -d= -f2-)
eval "kselftest_$field"="$value" eval "kselftest_$field"="$value"
...@@ -80,7 +84,7 @@ run_one() ...@@ -80,7 +84,7 @@ run_one()
echo "ok $test_num $TEST_HDR_MSG # SKIP" echo "ok $test_num $TEST_HDR_MSG # SKIP"
elif [ $rc -eq $timeout_rc ]; then \ elif [ $rc -eq $timeout_rc ]; then \
echo "#" echo "#"
echo "not ok $test_num $TEST_HDR_MSG # TIMEOUT" echo "not ok $test_num $TEST_HDR_MSG # TIMEOUT $kselftest_timeout seconds"
else else
echo "not ok $test_num $TEST_HDR_MSG # exit=$rc" echo "not ok $test_num $TEST_HDR_MSG # exit=$rc"
fi) fi)
......
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