Commit f1725160 authored by Danilo Krummrich's avatar Danilo Krummrich Committed by Greg Kroah-Hartman
Browse files

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: default avatarDanilo Krummrich <dakr@kernel.org>
Link: https://lore.kernel.org/r/20250107122609.8135-1-dakr@kernel.org


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 827ed8b1
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -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
+17 −1
Original line number Diff line number Diff line
@@ -399,7 +399,23 @@ void __iomem *devm_of_iomap(struct device *dev,
#endif

/* allows to add/remove a custom action to devres stack */
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);

/**
 * devm_remove_action() - 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.
 */
static inline
void devm_remove_action(struct device *dev, void (*action)(void *), void *data)
{
	WARN_ON(devm_remove_action_nowarn(dev, action, data));
}

void devm_release_action(struct device *dev, void (*action)(void *), void *data);

int __devm_add_action(struct device *dev, void (*action)(void *), void *data, const char *name);