Driver core changes for 6.16-rc1

Here are the driver core / kernfs changes for 6.16-rc1.
 
 Not a huge number of changes this development cycle, here's the summary
 of what is included in here:
   - kernfs locking tweaks, pushing some global locks down into a per-fs
     image lock
   - rust driver core and pci device bindings added for new features.
   - sysfs const work for bin_attributes.  This churn should now be
     completed for those types of attributes
   - auxbus device creation helpers added
   - fauxbus fix for creating sysfs files after the probe completed
     properly
   - other tiny updates for driver core things.
 
 All of these have been in linux-next for over a week with no reported
 issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCaDbe+g8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ylYbACgl/MngU9pRnx5jZIQh6bWveFSeo8AnRE4U5x0
 X+lgTPjGKL1RrV3C5HJp
 =+0BA
 -----END PGP SIGNATURE-----

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

Pull driver core updates from Greg KH:
 "Here are the driver core / kernfs changes for 6.16-rc1.

  Not a huge number of changes this development cycle, here's the
  summary of what is included in here:

   - kernfs locking tweaks, pushing some global locks down into a per-fs
     image lock

   - rust driver core and pci device bindings added for new features.

   - sysfs const work for bin_attributes.

     The final churn of switching away from and removing the
     transitional struct members, "read_new", "write_new" and
     "bin_attrs_new" will come after the merge window to avoid
     unnecesary merge conflicts.

   - auxbus device creation helpers added

   - fauxbus fix for creating sysfs files after the probe completed
     properly

   - other tiny updates for driver core things.

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

* tag 'driver-core-6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core:
  kernfs: Relax constraint in draining guard
  Documentation: embargoed-hardware-issues.rst: Remove myself
  drivers: hv: fix up const issue with vmbus_chan_bin_attrs
  firmware_loader: use SHA-256 library API instead of crypto_shash API
  docs: debugfs: do not recommend debugfs_remove_recursive
  PM: wakeup: Do not expose 4 device wakeup source APIs
  kernfs: switch global kernfs_rename_lock to per-fs lock
  kernfs: switch global kernfs_idr_lock to per-fs lock
  driver core: auxiliary bus: Fix IS_ERR() vs NULL mixup in __devm_auxiliary_device_create()
  sysfs: constify attribute_group::bin_attrs
  sysfs: constify bin_attribute argument of bin_attribute::read/write()
  software node: Correct a OOB check in software_node_get_reference_args()
  devres: simplify devm_kstrdup() using devm_kmemdup()
  platform: replace magic number with macro PLATFORM_DEVID_NONE
  component: do not try to unbind unbound components
  driver core: auxiliary bus: add device creation helpers
  driver core: faux: Add sysfs groups after probing
This commit is contained in:
Linus Torvalds 2025-05-29 09:11:39 -07:00
commit 9d230d500b
20 changed files with 205 additions and 132 deletions

View File

@ -229,22 +229,15 @@ module is unloaded without explicitly removing debugfs entries, the result
will be a lot of stale pointers and no end of highly antisocial behavior.
So all debugfs users - at least those which can be built as modules - must
be prepared to remove all files and directories they create there. A file
can be removed with::
or directory can be removed with::
void debugfs_remove(struct dentry *dentry);
The dentry value can be NULL or an error value, in which case nothing will
be removed.
Once upon a time, debugfs users were required to remember the dentry
pointer for every debugfs file they created so that all files could be
cleaned up. We live in more civilized times now, though, and debugfs users
can call::
void debugfs_remove_recursive(struct dentry *dentry);
If this function is passed a pointer for the dentry corresponding to the
top-level directory, the entire hierarchy below that directory will be
removed.
be removed. Note that this function will recursively remove all files and
directories underneath it. Previously, debugfs_remove_recursive() was used
to perform that task, but this function is now just an alias to
debugfs_remove(). debugfs_remove_recursive() should be considered
deprecated.
.. [1] http://lwn.net/Articles/309298/

View File

@ -155,7 +155,7 @@ The general idea is:
``my_variable``
- Clean up the directory when removing the device
(``debugfs_remove_recursive(parent);``)
(``debugfs_remove(parent);``)
For the full documentation see :doc:`/filesystems/debugfs`.

View File

@ -290,7 +290,6 @@ an involved disclosed party. The current ambassadors list:
AMD Tom Lendacky <thomas.lendacky@amd.com>
Ampere Darren Hart <darren@os.amperecomputing.com>
ARM Catalin Marinas <catalin.marinas@arm.com>
IBM Power Michael Ellerman <ellerman@au.ibm.com>
IBM Z Christian Borntraeger <borntraeger@de.ibm.com>
Intel Tony Luck <tony.luck@intel.com>
Qualcomm Trilok Soni <quic_tsoni@quicinc.com>

View File

@ -395,6 +395,114 @@ void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv)
}
EXPORT_SYMBOL_GPL(auxiliary_driver_unregister);
static void auxiliary_device_release(struct device *dev)
{
struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
kfree(auxdev);
}
/**
* auxiliary_device_create - create a device on the auxiliary bus
* @dev: parent device
* @modname: module name used to create the auxiliary driver name.
* @devname: auxiliary bus device name
* @platform_data: auxiliary bus device platform data
* @id: auxiliary bus device id
*
* Helper to create an auxiliary bus device.
* The device created matches driver 'modname.devname' on the auxiliary bus.
*/
struct auxiliary_device *auxiliary_device_create(struct device *dev,
const char *modname,
const char *devname,
void *platform_data,
int id)
{
struct auxiliary_device *auxdev;
int ret;
auxdev = kzalloc(sizeof(*auxdev), GFP_KERNEL);
if (!auxdev)
return NULL;
auxdev->id = id;
auxdev->name = devname;
auxdev->dev.parent = dev;
auxdev->dev.platform_data = platform_data;
auxdev->dev.release = auxiliary_device_release;
device_set_of_node_from_dev(&auxdev->dev, dev);
ret = auxiliary_device_init(auxdev);
if (ret) {
kfree(auxdev);
return NULL;
}
ret = __auxiliary_device_add(auxdev, modname);
if (ret) {
/*
* It may look odd but auxdev should not be freed here.
* auxiliary_device_uninit() calls device_put() which call
* the device release function, freeing auxdev.
*/
auxiliary_device_uninit(auxdev);
return NULL;
}
return auxdev;
}
EXPORT_SYMBOL_GPL(auxiliary_device_create);
/**
* auxiliary_device_destroy - remove an auxiliary device
* @auxdev: pointer to the auxdev to be removed
*
* Helper to remove an auxiliary device created with
* auxiliary_device_create()
*/
void auxiliary_device_destroy(void *auxdev)
{
struct auxiliary_device *_auxdev = auxdev;
auxiliary_device_delete(_auxdev);
auxiliary_device_uninit(_auxdev);
}
EXPORT_SYMBOL_GPL(auxiliary_device_destroy);
/**
* __devm_auxiliary_device_create - create a managed device on the auxiliary bus
* @dev: parent device
* @modname: module name used to create the auxiliary driver name.
* @devname: auxiliary bus device name
* @platform_data: auxiliary bus device platform data
* @id: auxiliary bus device id
*
* Device managed helper to create an auxiliary bus device.
* The device created matches driver 'modname.devname' on the auxiliary bus.
*/
struct auxiliary_device *__devm_auxiliary_device_create(struct device *dev,
const char *modname,
const char *devname,
void *platform_data,
int id)
{
struct auxiliary_device *auxdev;
int ret;
auxdev = auxiliary_device_create(dev, modname, devname, platform_data, id);
if (!auxdev)
return NULL;
ret = devm_add_action_or_reset(dev, auxiliary_device_destroy,
auxdev);
if (ret)
return NULL;
return auxdev;
}
EXPORT_SYMBOL_GPL(__devm_auxiliary_device_create);
void __init auxiliary_bus_init(void)
{
WARN_ON(bus_register(&auxiliary_bus_type));

View File

@ -586,7 +586,8 @@ EXPORT_SYMBOL_GPL(component_master_is_bound);
static void component_unbind(struct component *component,
struct aggregate_device *adev, void *data)
{
WARN_ON(!component->bound);
if (WARN_ON(!component->bound))
return;
dev_dbg(adev->parent, "unbinding %s component %p (ops %ps)\n",
dev_name(component->dev), component, component->ops);

View File

@ -987,17 +987,10 @@ EXPORT_SYMBOL_GPL(devm_krealloc);
*/
char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
{
size_t size;
char *buf;
if (!s)
return NULL;
size = strlen(s) + 1;
buf = devm_kmalloc(dev, size, gfp);
if (buf)
memcpy(buf, s, size);
return buf;
return devm_kmemdup(dev, s, strlen(s) + 1, gfp);
}
EXPORT_SYMBOL_GPL(devm_kstrdup);

View File

@ -25,6 +25,7 @@
struct faux_object {
struct faux_device faux_dev;
const struct faux_device_ops *faux_ops;
const struct attribute_group **groups;
};
#define to_faux_object(dev) container_of_const(dev, struct faux_object, faux_dev.dev)
@ -43,10 +44,21 @@ static int faux_probe(struct device *dev)
struct faux_object *faux_obj = to_faux_object(dev);
struct faux_device *faux_dev = &faux_obj->faux_dev;
const struct faux_device_ops *faux_ops = faux_obj->faux_ops;
int ret = 0;
int ret;
if (faux_ops && faux_ops->probe)
if (faux_ops && faux_ops->probe) {
ret = faux_ops->probe(faux_dev);
if (ret)
return ret;
}
/*
* Add groups after the probe succeeds to ensure resources are
* initialized correctly
*/
ret = device_add_groups(dev, faux_obj->groups);
if (ret && faux_ops && faux_ops->remove)
faux_ops->remove(faux_dev);
return ret;
}
@ -57,6 +69,8 @@ static void faux_remove(struct device *dev)
struct faux_device *faux_dev = &faux_obj->faux_dev;
const struct faux_device_ops *faux_ops = faux_obj->faux_ops;
device_remove_groups(dev, faux_obj->groups);
if (faux_ops && faux_ops->remove)
faux_ops->remove(faux_dev);
}
@ -124,8 +138,9 @@ struct faux_device *faux_device_create_with_groups(const char *name,
if (!faux_obj)
return NULL;
/* Save off the callbacks so we can use them in the future */
/* Save off the callbacks and groups so we can use them in the future */
faux_obj->faux_ops = faux_ops;
faux_obj->groups = groups;
/* Initialize the device portion and register it with the driver core */
faux_dev = &faux_obj->faux_dev;
@ -138,7 +153,6 @@ struct faux_device *faux_device_create_with_groups(const char *name,
else
dev->parent = &faux_bus_root;
dev->bus = &faux_bus_type;
dev->groups = groups;
dev_set_name(dev, "%s", name);
ret = device_add(dev);

View File

@ -3,8 +3,7 @@ menu "Firmware loader"
config FW_LOADER
tristate "Firmware loading facility" if EXPERT
select CRYPTO_HASH if FW_LOADER_DEBUG
select CRYPTO_SHA256 if FW_LOADER_DEBUG
select CRYPTO_LIB_SHA256 if FW_LOADER_DEBUG
default y
help
This enables the firmware loading facility in the kernel. The kernel
@ -28,7 +27,6 @@ config FW_LOADER
config FW_LOADER_DEBUG
bool "Log filenames and checksums for loaded firmware"
depends on CRYPTO = FW_LOADER || CRYPTO=y
depends on DYNAMIC_DEBUG
depends on FW_LOADER
default FW_LOADER

View File

@ -806,41 +806,15 @@ static void fw_abort_batch_reqs(struct firmware *fw)
}
#if defined(CONFIG_FW_LOADER_DEBUG)
#include <crypto/hash.h>
#include <crypto/sha2.h>
static void fw_log_firmware_info(const struct firmware *fw, const char *name, struct device *device)
{
struct shash_desc *shash;
struct crypto_shash *alg;
u8 *sha256buf;
char *outbuf;
u8 digest[SHA256_DIGEST_SIZE];
alg = crypto_alloc_shash("sha256", 0, 0);
if (IS_ERR(alg))
return;
sha256buf = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL);
outbuf = kmalloc(SHA256_BLOCK_SIZE + 1, GFP_KERNEL);
shash = kmalloc(sizeof(*shash) + crypto_shash_descsize(alg), GFP_KERNEL);
if (!sha256buf || !outbuf || !shash)
goto out_free;
shash->tfm = alg;
if (crypto_shash_digest(shash, fw->data, fw->size, sha256buf) < 0)
goto out_free;
for (int i = 0; i < SHA256_DIGEST_SIZE; i++)
sprintf(&outbuf[i * 2], "%02x", sha256buf[i]);
outbuf[SHA256_BLOCK_SIZE] = 0;
dev_dbg(device, "Loaded FW: %s, sha256: %s\n", name, outbuf);
out_free:
kfree(shash);
kfree(outbuf);
kfree(sha256buf);
crypto_free_shash(alg);
sha256(fw->data, fw->size, digest);
dev_dbg(device, "Loaded FW: %s, sha256: %*phN\n",
name, SHA256_DIGEST_SIZE, digest);
}
#else
static void fw_log_firmware_info(const struct firmware *fw, const char *name,

View File

@ -982,7 +982,7 @@ struct platform_device * __init_or_module __platform_create_bundle(
struct platform_device *pdev;
int error;
pdev = platform_device_alloc(driver->driver.name, -1);
pdev = platform_device_alloc(driver->driver.name, PLATFORM_DEVID_NONE);
if (!pdev) {
error = -ENOMEM;
goto err_out;

View File

@ -77,7 +77,7 @@ static DEFINE_IDA(wakeup_ida);
* wakeup_source_create - Create a struct wakeup_source object.
* @name: Name of the new wakeup source.
*/
struct wakeup_source *wakeup_source_create(const char *name)
static struct wakeup_source *wakeup_source_create(const char *name)
{
struct wakeup_source *ws;
const char *ws_name;
@ -106,7 +106,6 @@ err_name:
err_ws:
return NULL;
}
EXPORT_SYMBOL_GPL(wakeup_source_create);
/*
* Record wakeup_source statistics being deleted into a dummy wakeup_source.
@ -149,7 +148,7 @@ static void wakeup_source_free(struct wakeup_source *ws)
*
* Use only for wakeup source objects created with wakeup_source_create().
*/
void wakeup_source_destroy(struct wakeup_source *ws)
static void wakeup_source_destroy(struct wakeup_source *ws)
{
if (!ws)
return;
@ -158,13 +157,12 @@ void wakeup_source_destroy(struct wakeup_source *ws)
wakeup_source_record(ws);
wakeup_source_free(ws);
}
EXPORT_SYMBOL_GPL(wakeup_source_destroy);
/**
* wakeup_source_add - Add given object to the list of wakeup sources.
* @ws: Wakeup source object to add to the list.
*/
void wakeup_source_add(struct wakeup_source *ws)
static void wakeup_source_add(struct wakeup_source *ws)
{
unsigned long flags;
@ -179,13 +177,12 @@ void wakeup_source_add(struct wakeup_source *ws)
list_add_rcu(&ws->entry, &wakeup_sources);
raw_spin_unlock_irqrestore(&events_lock, flags);
}
EXPORT_SYMBOL_GPL(wakeup_source_add);
/**
* wakeup_source_remove - Remove given object from the wakeup sources list.
* @ws: Wakeup source object to remove from the list.
*/
void wakeup_source_remove(struct wakeup_source *ws)
static void wakeup_source_remove(struct wakeup_source *ws)
{
unsigned long flags;
@ -204,7 +201,6 @@ void wakeup_source_remove(struct wakeup_source *ws)
*/
ws->timer.function = NULL;
}
EXPORT_SYMBOL_GPL(wakeup_source_remove);
/**
* wakeup_source_register - Create wakeup source and add it to the list.

View File

@ -529,7 +529,7 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
if (prop->is_inline)
return -EINVAL;
if (index * sizeof(*ref) >= prop->length)
if ((index + 1) * sizeof(*ref) > prop->length)
return -ENOENT;
ref_array = prop->pointer;

View File

@ -1841,7 +1841,7 @@ static struct attribute *vmbus_chan_attrs[] = {
NULL
};
static struct bin_attribute *vmbus_chan_bin_attrs[] = {
static const struct bin_attribute *vmbus_chan_bin_attrs[] = {
&chan_attr_ring_buffer,
NULL
};

View File

@ -17,7 +17,6 @@
#include "kernfs-internal.h"
DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */
/*
* Don't use rename_lock to piggy back on pr_cont_buf. We don't want to
* call pr_cont() while holding rename_lock. Because sometimes pr_cont()
@ -27,7 +26,6 @@ DEFINE_RWLOCK(kernfs_rename_lock); /* kn->parent and ->name */
*/
static DEFINE_SPINLOCK(kernfs_pr_cont_lock);
static char kernfs_pr_cont_buf[PATH_MAX]; /* protected by pr_cont_lock */
static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */
#define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb)
@ -229,7 +227,7 @@ int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from,
if (to) {
root = kernfs_root(to);
if (!(root->flags & KERNFS_ROOT_INVARIANT_PARENT)) {
guard(read_lock_irqsave)(&kernfs_rename_lock);
guard(read_lock_irqsave)(&root->kernfs_rename_lock);
return kernfs_path_from_node_locked(to, from, buf, buflen);
}
}
@ -296,12 +294,14 @@ out:
struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn)
{
struct kernfs_node *parent;
struct kernfs_root *root;
unsigned long flags;
read_lock_irqsave(&kernfs_rename_lock, flags);
root = kernfs_root(kn);
read_lock_irqsave(&root->kernfs_rename_lock, flags);
parent = kernfs_parent(kn);
kernfs_get(parent);
read_unlock_irqrestore(&kernfs_rename_lock, flags);
read_unlock_irqrestore(&root->kernfs_rename_lock, flags);
return parent;
}
@ -584,9 +584,9 @@ void kernfs_put(struct kernfs_node *kn)
if (kernfs_type(kn) == KERNFS_LINK)
kernfs_put(kn->symlink.target_kn);
spin_lock(&kernfs_idr_lock);
spin_lock(&root->kernfs_idr_lock);
idr_remove(&root->ino_idr, (u32)kernfs_ino(kn));
spin_unlock(&kernfs_idr_lock);
spin_unlock(&root->kernfs_idr_lock);
call_rcu(&kn->rcu, kernfs_free_rcu);
@ -639,13 +639,13 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
goto err_out1;
idr_preload(GFP_KERNEL);
spin_lock(&kernfs_idr_lock);
spin_lock(&root->kernfs_idr_lock);
ret = idr_alloc_cyclic(&root->ino_idr, kn, 1, 0, GFP_ATOMIC);
if (ret >= 0 && ret < root->last_id_lowbits)
root->id_highbits++;
id_highbits = root->id_highbits;
root->last_id_lowbits = ret;
spin_unlock(&kernfs_idr_lock);
spin_unlock(&root->kernfs_idr_lock);
idr_preload_end();
if (ret < 0)
goto err_out2;
@ -681,9 +681,9 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
return kn;
err_out3:
spin_lock(&kernfs_idr_lock);
spin_lock(&root->kernfs_idr_lock);
idr_remove(&root->ino_idr, (u32)kernfs_ino(kn));
spin_unlock(&kernfs_idr_lock);
spin_unlock(&root->kernfs_idr_lock);
err_out2:
kmem_cache_free(kernfs_node_cache, kn);
err_out1:
@ -989,10 +989,12 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
return ERR_PTR(-ENOMEM);
idr_init(&root->ino_idr);
spin_lock_init(&root->kernfs_idr_lock);
init_rwsem(&root->kernfs_rwsem);
init_rwsem(&root->kernfs_iattr_rwsem);
init_rwsem(&root->kernfs_supers_rwsem);
INIT_LIST_HEAD(&root->supers);
rwlock_init(&root->kernfs_rename_lock);
/*
* On 64bit ino setups, id is ino. On 32bit, low 32bits are ino.
@ -1580,8 +1582,9 @@ void kernfs_break_active_protection(struct kernfs_node *kn)
* invoked before finishing the kernfs operation. Note that while this
* function restores the active reference, it doesn't and can't actually
* restore the active protection - @kn may already or be in the process of
* being removed. Once kernfs_break_active_protection() is invoked, that
* protection is irreversibly gone for the kernfs operation instance.
* being drained and removed. Once kernfs_break_active_protection() is
* invoked, that protection is irreversibly gone for the kernfs operation
* instance.
*
* While this function may be called at any point after
* kernfs_break_active_protection() is invoked, its most useful location
@ -1789,7 +1792,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
/* rename_lock protects ->parent accessors */
if (old_parent != new_parent) {
kernfs_get(new_parent);
write_lock_irq(&kernfs_rename_lock);
write_lock_irq(&root->kernfs_rename_lock);
rcu_assign_pointer(kn->__parent, new_parent);
@ -1797,7 +1800,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
if (new_name)
rcu_assign_pointer(kn->name, new_name);
write_unlock_irq(&kernfs_rename_lock);
write_unlock_irq(&root->kernfs_rename_lock);
kernfs_put(old_parent);
} else {
/* name assignment is RCU protected, parent is the same */

View File

@ -778,8 +778,9 @@ bool kernfs_should_drain_open_files(struct kernfs_node *kn)
/*
* @kn being deactivated guarantees that @kn->attr.open can't change
* beneath us making the lockless test below safe.
* Callers post kernfs_unbreak_active_protection may be counted in
* kn->active by now, do not WARN_ON because of them.
*/
WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS);
rcu_read_lock();
on = rcu_dereference(kn->attr.open);

View File

@ -19,8 +19,6 @@
#include <linux/kernfs.h>
#include <linux/fs_context.h>
extern rwlock_t kernfs_rename_lock;
struct kernfs_iattrs {
kuid_t ia_uid;
kgid_t ia_gid;
@ -40,6 +38,7 @@ struct kernfs_root {
/* private fields, do not use outside kernfs proper */
struct idr ino_idr;
spinlock_t kernfs_idr_lock; /* root->ino_idr */
u32 last_id_lowbits;
u32 id_highbits;
struct kernfs_syscall_ops *syscall_ops;
@ -52,6 +51,9 @@ struct kernfs_root {
struct rw_semaphore kernfs_iattr_rwsem;
struct rw_semaphore kernfs_supers_rwsem;
/* kn->parent and kn->name */
rwlock_t kernfs_rename_lock;
struct rcu_head rcu;
};
@ -107,6 +109,11 @@ static inline bool kernfs_root_is_locked(const struct kernfs_node *kn)
return lockdep_is_held(&kernfs_root(kn)->kernfs_rwsem);
}
static inline bool kernfs_rename_is_locked(const struct kernfs_node *kn)
{
return lockdep_is_held(&kernfs_root(kn)->kernfs_rename_lock);
}
static inline const char *kernfs_rcu_name(const struct kernfs_node *kn)
{
return rcu_dereference_check(kn->name, kernfs_root_is_locked(kn));
@ -117,14 +124,15 @@ static inline struct kernfs_node *kernfs_parent(const struct kernfs_node *kn)
/*
* The kernfs_node::__parent remains valid within a RCU section. The kn
* can be reparented (and renamed) which changes the entry. This can be
* avoided by locking kernfs_root::kernfs_rwsem or kernfs_rename_lock.
* avoided by locking kernfs_root::kernfs_rwsem or
* kernfs_root::kernfs_rename_lock.
* Both locks can be used to obtain a reference on __parent. Once the
* reference count reaches 0 then the node is about to be freed
* and can not be renamed (or become a different parent) anymore.
*/
return rcu_dereference_check(kn->__parent,
kernfs_root_is_locked(kn) ||
lockdep_is_held(&kernfs_rename_lock) ||
kernfs_rename_is_locked(kn) ||
!atomic_read(&kn->count));
}

View File

@ -21,7 +21,7 @@ static void remove_files(struct kernfs_node *parent,
const struct attribute_group *grp)
{
struct attribute *const *attr;
struct bin_attribute *const *bin_attr;
const struct bin_attribute *const *bin_attr;
if (grp->attrs)
for (attr = grp->attrs; *attr; attr++)
@ -47,7 +47,7 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
const struct attribute_group *grp, int update)
{
struct attribute *const *attr;
struct bin_attribute *const *bin_attr;
const struct bin_attribute *const *bin_attr;
int error = 0, i;
if (grp->attrs) {
@ -521,7 +521,7 @@ static int sysfs_group_attrs_change_owner(struct kernfs_node *grp_kn,
}
if (grp->bin_attrs) {
struct bin_attribute *const *bin_attr;
const struct bin_attribute *const *bin_attr;
for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
kn = kernfs_find_and_get(grp_kn, (*bin_attr)->attr.name);

View File

@ -254,6 +254,23 @@ int __auxiliary_driver_register(struct auxiliary_driver *auxdrv, struct module *
void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv);
struct auxiliary_device *auxiliary_device_create(struct device *dev,
const char *modname,
const char *devname,
void *platform_data,
int id);
void auxiliary_device_destroy(void *auxdev);
struct auxiliary_device *__devm_auxiliary_device_create(struct device *dev,
const char *modname,
const char *devname,
void *platform_data,
int id);
#define devm_auxiliary_device_create(dev, devname, platform_data) \
__devm_auxiliary_device_create(dev, KBUILD_MODNAME, devname, \
platform_data, 0)
/**
* module_auxiliary_driver() - Helper macro for registering an auxiliary driver
* @__auxiliary_driver: auxiliary driver struct

View File

@ -95,10 +95,6 @@ static inline void device_set_wakeup_path(struct device *dev)
}
/* drivers/base/power/wakeup.c */
extern struct wakeup_source *wakeup_source_create(const char *name);
extern void wakeup_source_destroy(struct wakeup_source *ws);
extern void wakeup_source_add(struct wakeup_source *ws);
extern void wakeup_source_remove(struct wakeup_source *ws);
extern struct wakeup_source *wakeup_source_register(struct device *dev,
const char *name);
extern void wakeup_source_unregister(struct wakeup_source *ws);
@ -129,17 +125,6 @@ static inline bool device_can_wakeup(struct device *dev)
return dev->power.can_wakeup;
}
static inline struct wakeup_source *wakeup_source_create(const char *name)
{
return NULL;
}
static inline void wakeup_source_destroy(struct wakeup_source *ws) {}
static inline void wakeup_source_add(struct wakeup_source *ws) {}
static inline void wakeup_source_remove(struct wakeup_source *ws) {}
static inline struct wakeup_source *wakeup_source_register(struct device *dev,
const char *name)
{

View File

@ -107,7 +107,7 @@ struct attribute_group {
int);
struct attribute **attrs;
union {
struct bin_attribute **bin_attrs;
const struct bin_attribute *const *bin_attrs;
const struct bin_attribute *const *bin_attrs_new;
};
};
@ -306,11 +306,11 @@ struct bin_attribute {
size_t size;
void *private;
struct address_space *(*f_mapping)(void);
ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *,
ssize_t (*read)(struct file *, struct kobject *, const struct bin_attribute *,
char *, loff_t, size_t);
ssize_t (*read_new)(struct file *, struct kobject *, const struct bin_attribute *,
char *, loff_t, size_t);
ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *,
ssize_t (*write)(struct file *, struct kobject *, const struct bin_attribute *,
char *, loff_t, size_t);
ssize_t (*write_new)(struct file *, struct kobject *,
const struct bin_attribute *, char *, loff_t, size_t);
@ -332,28 +332,11 @@ struct bin_attribute {
*/
#define sysfs_bin_attr_init(bin_attr) sysfs_attr_init(&(bin_attr)->attr)
typedef ssize_t __sysfs_bin_rw_handler_new(struct file *, struct kobject *,
const struct bin_attribute *, char *, loff_t, size_t);
/* macros to create static binary attributes easier */
#define __BIN_ATTR(_name, _mode, _read, _write, _size) { \
.attr = { .name = __stringify(_name), .mode = _mode }, \
.read = _Generic(_read, \
__sysfs_bin_rw_handler_new * : NULL, \
default : _read \
), \
.read_new = _Generic(_read, \
__sysfs_bin_rw_handler_new * : _read, \
default : NULL \
), \
.write = _Generic(_write, \
__sysfs_bin_rw_handler_new * : NULL, \
default : _write \
), \
.write_new = _Generic(_write, \
__sysfs_bin_rw_handler_new * : _write, \
default : NULL \
), \
.read = _read, \
.write = _write, \
.size = _size, \
}