Provide devm_{atomic,blocking}_notifier_chain_register()

Base for merging into subsystem trees that want to benefit from the devm
 variants of notifier_chain_register functions created by Eliav Farber
 for the 7.4 merge window.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEP4GsaTp6HlmJrf7Tj4D7WH0S/k4FAmqJQWAACgkQj4D7WH0S
 /k52uQf/RB79Bi3soq3261cpnJmvYvXi6JyraCPJpQA9eia+5RqjQnpNgKh+5OAU
 5bruyuM4wz4Nbek+bujXyurksW/v9QSYlIknCknBVEy73WndJH+bFwR8fdw0DFyR
 2UIdCXYY4AM5mJfHbXXKKahJYN/m60X7VV4oZzqljQJYHIVjzSa/lidvBN1x97/k
 IXBUjfl2/+dNq+iVqg74CM+JnmLfNjOn4UQVyzec1c2rLpN5bOXJQAuzvtBI06kA
 wk3b3jFRWj0bBfLb0wCoA+6xPDIsNZWDX53RyrM03DLhbXxLIeeoFaR9ZWAwszo9
 2FrH/pmsaTSDiKnAtq10TqULWT96yA==
 =aWmZ
 -----END PGP SIGNATURE-----

Merge tag 'devm_notifier_chain_register-for-7.4' of https://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux into HEAD

Provide devm_{atomic,blocking}_notifier_chain_register()

Base for merging into subsystem trees that want to benefit from the devm
variants of notifier_chain_register functions created by Eliav Farber
for the 7.4 merge window.
This commit is contained in:
Uwe Kleine-König 2026-08-31 23:27:08 +02:00
commit ebda763592
2 changed files with 112 additions and 0 deletions

View File

@ -46,6 +46,7 @@
* often but notifier_blocks will seldom be removed.
*/
struct device;
struct notifier_block;
typedef int (*notifier_fn_t)(struct notifier_block *nb,
@ -145,8 +146,14 @@ extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
struct notifier_block *nb);
int devm_atomic_notifier_chain_register(struct device *dev,
struct atomic_notifier_head *nh,
struct notifier_block *nb);
extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
struct notifier_block *nb);
int devm_blocking_notifier_chain_register(struct device *dev,
struct blocking_notifier_head *nh,
struct notifier_block *nb);
extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
struct notifier_block *nb);
extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,

View File

@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/device/devres.h>
#include <linux/kdebug.h>
#include <linux/kprobes.h>
#include <linux/export.h>
@ -197,6 +198,58 @@ int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
}
EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
struct atomic_notifier_chain_devres {
struct atomic_notifier_head *nh;
struct notifier_block *nb;
};
static void devm_atomic_notifier_chain_unregister(struct device *dev, void *res)
{
struct atomic_notifier_chain_devres *dr = res;
atomic_notifier_chain_unregister(dr->nh, dr->nb);
}
/**
* devm_atomic_notifier_chain_register - Device-managed atomic notifier registration
* @dev: Device to tie the notifier lifetime to
* @nh: Pointer to head of the atomic notifier chain
* @nb: New entry in notifier chain
*
* Adds a notifier to an atomic notifier chain and registers a cleanup
* action to automatically unregister it when @dev is unbound.
*
* Must be called in process context.
*
* Return:
* 0 on success, negative errno on error.
*/
int devm_atomic_notifier_chain_register(struct device *dev,
struct atomic_notifier_head *nh,
struct notifier_block *nb)
{
struct atomic_notifier_chain_devres *dr;
int ret;
dr = devres_alloc(devm_atomic_notifier_chain_unregister,
sizeof(*dr), GFP_KERNEL);
if (!dr)
return -ENOMEM;
ret = atomic_notifier_chain_register(nh, nb);
if (ret) {
devres_free(dr);
return ret;
}
dr->nh = nh;
dr->nb = nb;
devres_add(dev, dr);
return 0;
}
EXPORT_SYMBOL_GPL(devm_atomic_notifier_chain_register);
/**
* atomic_notifier_call_chain - Call functions in an atomic notifier chain
* @nh: Pointer to head of the atomic notifier chain
@ -349,6 +402,58 @@ int blocking_notifier_call_chain_robust(struct blocking_notifier_head *nh,
}
EXPORT_SYMBOL_GPL(blocking_notifier_call_chain_robust);
struct blocking_notifier_chain_devres {
struct blocking_notifier_head *nh;
struct notifier_block *nb;
};
static void devm_blocking_notifier_chain_unregister(struct device *dev,
void *res)
{
struct blocking_notifier_chain_devres *dr = res;
blocking_notifier_chain_unregister(dr->nh, dr->nb);
}
/**
* devm_blocking_notifier_chain_register - Device-managed blocking notifier registration
* @dev: Device to tie the notifier lifetime to
* @nh: Pointer to head of the blocking notifier chain
* @nb: New entry in notifier chain
*
* Adds a notifier to a blocking notifier chain and registers a cleanup
* action to automatically unregister it when @dev is unbound.
* Must be called in process context.
*
* Return:
* 0 on success, negative errno on error.
*/
int devm_blocking_notifier_chain_register(struct device *dev,
struct blocking_notifier_head *nh,
struct notifier_block *nb)
{
struct blocking_notifier_chain_devres *dr;
int ret;
dr = devres_alloc(devm_blocking_notifier_chain_unregister,
sizeof(*dr), GFP_KERNEL);
if (!dr)
return -ENOMEM;
ret = blocking_notifier_chain_register(nh, nb);
if (ret) {
devres_free(dr);
return ret;
}
dr->nh = nh;
dr->nb = nb;
devres_add(dev, dr);
return 0;
}
EXPORT_SYMBOL_GPL(devm_blocking_notifier_chain_register);
/**
* blocking_notifier_call_chain - Call functions in a blocking notifier chain
* @nh: Pointer to head of the blocking notifier chain