devres: add devm_remove_action_nowarn()

devm_remove_action() warns if the action to remove does not exist
(anymore).

The Rust devres abstraction, however, has a use-case to call
devm_remove_action() at a point where it can't be guaranteed that the
corresponding action hasn't been released yet.

In particular, an instance of `Devres<T>` may be dropped after the
action has been released. So far, `Devres<T>` worked around this by
keeping the inner type alive.

Hence, add devm_remove_action_nowarn(), which returns an error code if
the action has been removed already.

A subsequent patch uses devm_remove_action_nowarn() to remove the action
when `Devres<T>` is dropped.

Signed-off-by: Danilo Krummrich <dakr@kernel.org>
Link: https://lore.kernel.org/r/20250107122609.8135-1-dakr@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Danilo Krummrich
2025-01-07 13:25:10 +01:00
committed by Greg Kroah-Hartman
parent 827ed8b159
commit f1725160fd
2 changed files with 35 additions and 6 deletions

View File

@@ -750,25 +750,38 @@ int __devm_add_action(struct device *dev, void (*action)(void *), void *data, co
EXPORT_SYMBOL_GPL(__devm_add_action);
/**
* devm_remove_action() - removes previously added custom action
* devm_remove_action_nowarn() - removes previously added custom action
* @dev: Device that owns the action
* @action: Function implementing the action
* @data: Pointer to data passed to @action implementation
*
* Removes instance of @action previously added by devm_add_action().
* Both action and data should match one of the existing entries.
*
* In contrast to devm_remove_action(), this function does not WARN() if no
* entry could have been found.
*
* This should only be used if the action is contained in an object with
* independent lifetime management, e.g. the Devres rust abstraction.
*
* Causing the warning from regular driver code most likely indicates an abuse
* of the devres API.
*
* Returns: 0 on success, -ENOENT if no entry could have been found.
*/
void devm_remove_action(struct device *dev, void (*action)(void *), void *data)
int devm_remove_action_nowarn(struct device *dev,
void (*action)(void *),
void *data)
{
struct action_devres devres = {
.data = data,
.action = action,
};
WARN_ON(devres_destroy(dev, devm_action_release, devm_action_match,
&devres));
return devres_destroy(dev, devm_action_release, devm_action_match,
&devres);
}
EXPORT_SYMBOL_GPL(devm_remove_action);
EXPORT_SYMBOL_GPL(devm_remove_action_nowarn);
/**
* devm_release_action() - release previously added custom action