Revert "revocable: Revocable resource management"
Subsystems (3)
Johan Hovold
maintainerv2 cover Revert "revocable: Revocable resource management"
I was surprised to learn that the revocable functionality was merged the other week given the community feedback on list and at LPC, but not least since there are no users of it, which we are supposed to require to be able to evaluate it properly.
The chromeos ec driver issue which motivated this work turned out not to need it as was found during review. And the example gpiolib conversion was posted the very same morning that this was merged which hardly provides enough time for evaluation (even if Bartosz quickly reported a performance regression).
Turns out there are correctness issues with both the gpiolib conversion and the revocable design itself that can lead to use-after-free and hung tasks (see
[1] and [2]).
And as was pointed out repeatedly during review, and again at the day of the merge, this does not look like the right interface for the chardev unplug issue.
Despite the last-minute attempt at addressing the issues mentioned above incrementally, the revocable design is still fundamentally flawed (see patch 3/3).
We have processes like requiring a user before merging a new interface so that issues like these can be identified and the soundness of an API be evaluated. They also give a sense of when things are expected to happen, which allows our scarce reviewers to manage their time (e.g. to not be forced to drop everything else they are doing when things are merged prematurely).
There really is no reason to exempt any new interface from this regardless of whether one likes the underlying concept or not.
Revert the revocable implementation until a redesign has been proposed and evaluated properly.
Johan
[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/[email protected]/
Changes in v2:
- revert also the incremental changes in driver-core-next
- explain why the latest revocable design is still fundamentally broken
Johan Hovold (3):
Revert "selftests: revocable: Add kselftest cases" Revert "revocable: Add Kunit test cases" Revert "revocable: Revocable resource management"
.../driver-api/driver-model/index.rst | 1 - .../driver-api/driver-model/revocable.rst | 149 --------- MAINTAINERS | 9 - drivers/base/Kconfig | 8 - drivers/base/Makefile | 3 - drivers/base/revocable.c | 225 -------------- drivers/base/revocable_test.c | 284 ------------------ include/linux/revocable.h | 89 ------ .../selftests/drivers/base/revocable/Makefile | 7 - .../drivers/base/revocable/revocable_test.c | 136 --------- .../drivers/base/revocable/test-revocable.sh | 39 --- .../base/revocable/test_modules/Makefile | 10 - .../revocable/test_modules/revocable_test.c | 187 ------------ 13 files changed, 1147 deletions(-) delete mode 100644 Documentation/driver-api/driver-model/revocable.rst delete mode 100644 drivers/base/revocable.c delete mode 100644 drivers/base/revocable_test.c delete mode 100644 include/linux/revocable.h delete mode 100644 tools/testing/selftests/drivers/base/revocable/Makefile delete mode 100644 tools/testing/selftests/drivers/base/revocable/revocable_test.c delete mode 100755 tools/testing/selftests/drivers/base/revocable/test-revocable.sh delete mode 100644 tools/testing/selftests/drivers/base/revocable/test_modules/Makefile delete mode 100644 tools/testing/selftests/drivers/base/revocable/test_modules/revocable_test.c
Signature · 1 line
2.52.0
Johan Hovold
maintainerPATCH v2 1/3 Revert "selftests: revocable: Add kselftest cases"
This reverts commit 9d4502fef00fa7a798d3c0806d4da4466a7ffc6f.
The new revocable functionality is fundamentally broken and at a minimum needs to be redesigned.
Drop the revocable selftests to allow the implementation to be reverted.
--- MAINTAINERS | 1 - .../selftests/drivers/base/revocable/Makefile | 7 - .../drivers/base/revocable/revocable_test.c | 136 ------------- .../drivers/base/revocable/test-revocable.sh | 39 ---- .../base/revocable/test_modules/Makefile | 10 - .../revocable/test_modules/revocable_test.c | 187 ------------------ 6 files changed, 380 deletions(-) delete mode 100644 tools/testing/selftests/drivers/base/revocable/Makefile delete mode 100644 tools/testing/selftests/drivers/base/revocable/revocable_test.c delete mode 100755 tools/testing/selftests/drivers/base/revocable/test-revocable.sh delete mode 100644 tools/testing/selftests/drivers/base/revocable/test_modules/Makefile delete mode 100644 tools/testing/selftests/drivers/base/revocable/test_modules/revocable_test.c
MAINTAINERS +0 -1
@@ -22392,7 +22392,6 @@ S: Maintained F: drivers/base/revocable.c F: drivers/base/revocable_test.c F: include/linux/revocable.h -F: tools/testing/selftests/drivers/base/revocable/ RFKILL M: Johannes Berg <[email protected]>
tools/testing/selftests/drivers/base/revocable/Makefile deleted +0 -7
@@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -TEST_GEN_MODS_DIR := test_modules -TEST_GEN_PROGS_EXTENDED := revocable_test -TEST_PROGS := test-revocable.sh - -include ../../../lib.mk
tools/testing/selftests/drivers/base/revocable/revocable_test.c deleted +0 -136
136 lines not on this page · raw message
tools/testing/selftests/drivers/base/revocable/test-revocable.sh deleted +0 -39
@@ -1,39 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: GPL-2.0 - -mod_name="revocable_test" -ksft_fail=1 -ksft_skip=4 - -if [ "$(id -u)" -ne 0 ]; then - echo "$0: Must be run as root" - exit "$ksft_skip" -fi - -if ! which insmod > /dev/null 2>&1; then - echo "$0: Need insmod" - exit "$ksft_skip" -fi - -if ! which rmmod > /dev/null 2>&1; then - echo "$0: Need rmmod" - exit "$ksft_skip" -fi - -insmod test_modules/"${mod_name}".ko - -if [ ! -d /sys/kernel/debug/revocable_test/ ]; then - mount -t debugfs none /sys/kernel/debug/ - - if [ ! -d /sys/kernel/debug/revocable_test/ ]; then - echo "$0: Error mounting debugfs" - exit "$ksft_fail" - fi -fi - -./revocable_test -ret=$? - -rmmod "${mod_name}" - -exit "${ret}"
tools/testing/selftests/drivers/base/revocable/test_modules/Makefile deleted +0 -10
@@ -1,10 +0,0 @@ -TESTMODS_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))) -KDIR ?= /lib/modules/$(shell uname -r)/build - -obj-m += revocable_test.o - -all: - $(Q)$(MAKE) -C $(KDIR) M=$(TESTMODS_DIR) - -clean: - $(Q)$(MAKE) -C $(KDIR) M=$(TESTMODS_DIR) clean
tools/testing/selftests/drivers/base/revocable/test_modules/revocable_test.c deleted +0 -187
187 lines not on this page · raw message
Signature · 1 line
2.52.0
Johan Hovold
maintainerPATCH v2 2/3 Revert "revocable: Add Kunit test cases"
In reply to Johan HovoldThis reverts commit cd7693419bb5abd91ad2f407dab69c480e417a61.
The new revocable functionality is fundamentally broken and at a minimum needs to be redesigned.
Drop the revocable Kunit tests to allow the implementation to be reverted.
--- MAINTAINERS | 1 - drivers/base/Kconfig | 8 - drivers/base/Makefile | 3 - drivers/base/revocable_test.c | 284 ---------------------------------- 4 files changed, 296 deletions(-) delete mode 100644 drivers/base/revocable_test.c
MAINTAINERS +0 -1
@@ -22390,7 +22390,6 @@ M: Tzung-Bi Shih <[email protected]> L: [email protected] S: Maintained F: drivers/base/revocable.c -F: drivers/base/revocable_test.c F: include/linux/revocable.h RFKILL
drivers/base/Kconfig +0 -8
@@ -250,11 +250,3 @@ config FW_DEVLINK_SYNC_STATE_TIMEOUT work on. endmenu - -# Kunit test cases -config REVOCABLE_KUNIT_TEST - tristate "Kunit tests for revocable" if !KUNIT_ALL_TESTS - depends on KUNIT && BROKEN - default KUNIT_ALL_TESTS - help - Kunit tests for the revocable API.
drivers/base/Makefile +0 -3
@@ -35,6 +35,3 @@ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG # define_trace.h needs to know how to find our header CFLAGS_trace.o := -I$(src) obj-$(CONFIG_TRACING) += trace.o - -# Kunit test cases -obj-$(CONFIG_REVOCABLE_KUNIT_TEST) += revocable_test.o
drivers/base/revocable_test.c deleted +0 -284
284 lines not on this page · raw message
Signature · 1 line
2.52.0
Johan Hovold
maintainerPATCH v2 3/3 Revert "revocable: Revocable resource management"
In reply to Johan HovoldThis reverts commit 62eb557580eb2177cf16c3fd2b6efadff297b29a.
The revocable implementation uses two separate abstractions, struct revocable_provider and struct revocable, in order to store the SRCU read lock index which must be passed unaltered to srcu_read_unlock() in the same context when a resource is no longer needed.
With the merged revocable API, multiple threads could however share the same struct revocable and therefore potentially overwrite the SRCU index of another thread which can cause the SRCU synchronisation in revocable_provider_revoke() to never complete. [1]
An example revocable conversion of the gpiolib code also turned out to be fundamentally flawed and could lead to use-after-free. [2]
An attempt to address both issues was quickly put together and merged, but revocable is still fundamentally broken. [3]
Specifically, the latest design relies on RCU for storing a pointer to the revocable provider, but since the resource can be shared by value (e.g. as in the now reverted selftests) this does not work at all and can also lead to use-after-free:
static void revocable_provider_release(struct kref *kref)
{
struct revocable_provider *rp = container_of(kref,
struct revocable_provider, kref);
cleanup_srcu_struct(&rp->srcu);
kfree_rcu(rp, rcu);
}
void revocable_provider_revoke(struct revocable_provider __rcu **rp_ptr)
{
struct revocable_provider *rp;
rp = rcu_replace_pointer(*rp_ptr, NULL, 1);
...
kref_put(&rp->kref, revocable_provider_release);
}
int revocable_init(struct revocable_provider __rcu *_rp,
struct revocable *rev)
{
struct revocable_provider *rp;
...
scoped_guard(rcu) {
rp = rcu_dereference(_rp);
if (!rp)
return -ENODEV;
if (!kref_get_unless_zero(&rp->kref))
return -ENODEV;
}
...
}
producer:
priv->rp = revocable_provider_alloc(&priv->res);
// pass priv->rp by value to consumer
revocable_provider_revoke(&priv->rp);
consumer:
struct revocable_provider __rcu *rp = filp->private_data;
struct revocable *rev;
revocable_init(rp, &rev);as _rp would still be non-NULL in revocable_init() regardless of whether the producer has revoked the resource and set its pointer to NULL.
Essentially revocable still relies on having a pointer to reference counted driver data which holds the revocable provider, which makes all the RCU protection unnecessary along with most of the current revocable design and implementation.
As the above shows, and as has been pointed out repeatedly elsewhere, these kind of issues are not something that should be addressed incrementally. [4]
Revert the revocable implementation until a redesign has been proposed and evaluated properly.
--- .../driver-api/driver-model/index.rst | 1 - .../driver-api/driver-model/revocable.rst | 149 ------------ MAINTAINERS | 7 - drivers/base/revocable.c | 225 ------------------ include/linux/revocable.h | 89 ------- 5 files changed, 471 deletions(-) delete mode 100644 Documentation/driver-api/driver-model/revocable.rst delete mode 100644 drivers/base/revocable.c delete mode 100644 include/linux/revocable.h
Documentation/driver-api/driver-model/index.rst +0 -1
@@ -14,7 +14,6 @@ Driver Model overview platform porting - revocable .. only:: subproject and html
Documentation/driver-api/driver-model/revocable.rst deleted +0 -149
149 lines not on this page · raw message
MAINTAINERS +0 -7
@@ -22385,13 +22385,6 @@ F: include/uapi/linux/rseq.h F: kernel/rseq.c F: tools/testing/selftests/rseq/ -REVOCABLE RESOURCE MANAGEMENT -M: Tzung-Bi Shih <[email protected]> -L: [email protected] -S: Maintained -F: drivers/base/revocable.c -F: include/linux/revocable.h - RFKILL M: Johannes Berg <[email protected]> L: [email protected]
drivers/base/revocable.c deleted +0 -225
225 lines not on this page · raw message
include/linux/revocable.h deleted +0 -89
89 lines not on this page · raw message
Signature · 1 line
2.52.0
Quoted 4 lines · Johan Hovold
Specifically, the latest design relies on RCU for storing a pointer to the revocable provider, but since the resource can be shared by value (e.g. as in the now reverted selftests) this does not work at all and can also lead to use-after-free:
[...]
Quoted 13 lines
producer: priv->rp = revocable_provider_alloc(&priv->res); // pass priv->rp by value to consumer revocable_provider_revoke(&priv->rp); consumer: struct revocable_provider __rcu *rp = filp->private_data; struct revocable *rev; revocable_init(rp, &rev);
Quoted 2 lines
as
_rpwould still be non-NULL inrevocable_init()regardless of whether the producer has revoked the resource and set its pointer to NULL.
You're right to point out the issue with copying the pointer of revocable provider. If a consumer stores this pointer directly, rcu_replace_pointer() in the producer's revocable_provider_revoke() will not affect the consumer's copy. I understand this concern.
The intention was never for consumers to cache the pointer of revocable provider long-term. The design relies on consumers obtaining the current valid provider pointer at the point of access.
In the latest GPIO transition series [5], the usage pattern has been refined to avoid locally storing the pointer of revocable provider. Instead, it's fetched from a source of truth when needed.
I agree that the risks and correct usage patterns need to be much clearer. I'll update the Documentation and the selftests to explicitly highlight this limitation and demonstrate the proper way to interact with the API, avoiding the storage of the provider pointer by value in consumer contexts.
Quoted 4 lines
Essentially revocable still relies on having a pointer to reference counted driver data which holds the revocable provider, which makes all the RCU protection unnecessary along with most of the current revocable design and implementation.
(I'm assuming you are referring to the example in [6].)
I'm not sure I follow your reasoning. Per my understanding:
- The reference counted driver data (e.g. gdev in the GPIO example) is to ensure the pointer of revocable provider isn't freed.
- The RCU protects the pointer value from concurrent access and updates during the revocation process [7].
These seem to address different aspects. Could you provide more context on why you see the RCU protection as redundant?
[5] https://lore.kernel.org/all/[email protected]
[6] https://lore.kernel.org/all/[email protected]
[7] https://lore.kernel.org/all/[email protected]
Danilo Krummrich
maintainerQuoted 22 lines · Tzung-Bi Shih
Quoted 4 lines · Johan Hovold
Specifically, the latest design relies on RCU for storing a pointer to the revocable provider, but since the resource can be shared by value (e.g. as in the now reverted selftests) this does not work at all and can also lead to use-after-free:
[...]
Quoted 13 lines
producer: priv->rp = revocable_provider_alloc(&priv->res); // pass priv->rp by value to consumer revocable_provider_revoke(&priv->rp); consumer: struct revocable_provider __rcu *rp = filp->private_data; struct revocable *rev; revocable_init(rp, &rev);Quoted 2 lines
as
_rpwould still be non-NULL inrevocable_init()regardless of whether the producer has revoked the resource and set its pointer to NULL.
Quoted 8 lines
You're right to point out the issue with copying the pointer of revocable provider. If a consumer stores this pointer directly,
rcu_replace_pointer()in the producer'srevocable_provider_revoke()will not affect the consumer's copy. I understand this concern.The intention was never for consumers to cache the pointer of revocable provider long-term. The design relies on consumers obtaining the current valid provider pointer at the point of access.
Yeah, I think this part is not a bug in the API, but I think revocable_init() should be
int revocable_init(struct revocable_provider __rcu **_rp, ...)
instead of
int revocable_init(struct revocable_provider __rcu *_rp, ...)
for the same reason revocable_provider_revoke() takes a double pointer.
Otherwise this seems racy:
int revocable_init(struct revocable_provider __rcu *_rp, struct revocable *rev)
{
struct revocable_provider *rp;
if (!_rp)
return -ENODEV;
/*
* If revocable_provider_revoke() is called concurrently at this
* point, _rp is not affectd by rcu_replace_pointer().
*
* Additionally, nothing prevents a concurrent kfree_rcu() from
* freeing the revocable provider before we enter the RCU
* read-side critical section below.
*/
/*
* Enter a read-side critical section.
*
* This prevents kfree_rcu() from freeing the struct revocable_provider
* memory, for the duration of this scope.
*/
scoped_guard(rcu) {
...
}Do I miss anything?
Quoted 39 lines · Danilo Krummrich
should be
int
revocable_init(struct revocable_provider __rcu **_rp, ...)instead of
int
revocable_init(struct revocable_provider __rcu *_rp, ...)for the same reason
revocable_provider_revoke()takes a double pointer.Otherwise this seems racy:
int revocable_init(struct revocable_provider __rcu *_rp, struct revocable *rev) { struct revocable_provider *rp; if (!_rp) return -ENODEV; /* * If revocable_provider_revoke() is called concurrently at this * point, _rp is not affectd by rcu_replace_pointer(). * * Additionally, nothing prevents a concurrent kfree_rcu() from * freeing the revocable provider before we enter the RCU * read-side critical section below. */ /* * Enter a read-side critical section. * * This prevents kfree_rcu() from freeing the struct revocable_provider * memory, for the duration of this scope. */ scoped_guard(rcu) { ... }
Quoted 1 line
Do I miss anything?
You're right. Will fix that.
Johan Hovold
maintainerQuoted 22 lines · Tzung-Bi Shih
Quoted 4 lines · Johan Hovold
Specifically, the latest design relies on RCU for storing a pointer to the revocable provider, but since the resource can be shared by value (e.g. as in the now reverted selftests) this does not work at all and can also lead to use-after-free:
[...]
Quoted 13 lines
producer: priv->rp = revocable_provider_alloc(&priv->res); // pass priv->rp by value to consumer revocable_provider_revoke(&priv->rp); consumer: struct revocable_provider __rcu *rp = filp->private_data; struct revocable *rev; revocable_init(rp, &rev);Quoted 2 lines
as
_rpwould still be non-NULL inrevocable_init()regardless of whether the producer has revoked the resource and set its pointer to NULL.
Quoted 8 lines
You're right to point out the issue with copying the pointer of revocable provider. If a consumer stores this pointer directly,
rcu_replace_pointer()in the producer'srevocable_provider_revoke()will not affect the consumer's copy. I understand this concern.The intention was never for consumers to cache the pointer of revocable provider long-term. The design relies on consumers obtaining the current valid provider pointer at the point of access.
But that is not what the selftest does currently, nor is it what you need for your initial motivation for this which was miscdev where you don't have any reference counted driver data to store the pointer in.
Quoted 3 lines
In the latest GPIO transition series [5], the usage pattern has been refined to avoid locally storing the pointer of revocable provider. Instead, it's fetched from a source of truth when needed.
Right, but then you don't need all the RCU stuff. And revocable becomes just a convoluted abstraction for a lock and flag (as was pointed out early on).
Quoted 4 lines
I agree that the risks and correct usage patterns need to be much clearer. I'll update the Documentation and the selftests to explicitly highlight this limitation and demonstrate the proper way to interact with the API, avoiding the storage of the provider pointer by value in consumer contexts.
And again, that's precisely why we need to evaluate the API in a non-trivial context *before* merging yet another version of this.
Quoted 7 lines
Quoted 4 lines
Essentially revocable still relies on having a pointer to reference counted driver data which holds the revocable provider, which makes all the RCU protection unnecessary along with most of the current revocable design and implementation.
(I'm assuming you are referring to the example in [6].)
Quoted 8 lines
I'm not sure I follow your reasoning. Per my understanding:
- The reference counted driver data (e.g.gdevin the GPIO example) is to ensure the pointer of revocable provider isn't freed.
- The RCU protects the pointer value from concurrent access and updates during the revocation process [7].These seem to address different aspects. Could you provide more context on why you see the RCU protection as redundant?
I wasn't thinking of any particular example.
The struct revocable_provider is already reference counted and you don't need anything more than that as long as you only take another reference in a context where you already hold a reference. (And struct revocable_provider should be renamed struct revocable).
SRCU is what prevents the race against revoke, no need for RCU.
But this is designing yet another version of revocable. And that should be done out-of-tree.
Johan
Quoted 28 lines · Johan Hovold
Quoted 27 lines · Tzung-Bi Shih
Quoted 4 lines · Johan Hovold
Specifically, the latest design relies on RCU for storing a pointer to the revocable provider, but since the resource can be shared by value (e.g. as in the now reverted selftests) this does not work at all and can also lead to use-after-free:
[...]
Quoted 13 lines
producer: priv->rp = revocable_provider_alloc(&priv->res); // pass priv->rp by value to consumer revocable_provider_revoke(&priv->rp); consumer: struct revocable_provider __rcu *rp = filp->private_data; struct revocable *rev; revocable_init(rp, &rev);Quoted 2 lines
as
_rpwould still be non-NULL inrevocable_init()regardless of whether the producer has revoked the resource and set its pointer to NULL.You're right to point out the issue with copying the pointer of revocable provider. If a consumer stores this pointer directly,
rcu_replace_pointer()in the producer'srevocable_provider_revoke()will not affect the consumer's copy. I understand this concern.
Quoted 5 lines
Quoted 3 lines
The intention was never for consumers to cache the pointer of revocable provider long-term. The design relies on consumers obtaining the current valid provider pointer at the point of access.
But that is not what the selftest does currently, nor is it what you
Understood. As mentioned in my previous email, I'll update the selftests to reflect this. The test case somehow is simplified to setup the scenario it wants to test.
Quoted 2 lines
need for your initial motivation for this which was miscdev where you don't have any reference counted driver data to store the pointer in.
You're right that cros_ec_chardev.c needs to be adjusted before using the version of revocable.
Quoted 8 lines
Quoted 4 lines
In the latest GPIO transition series [5], the usage pattern has been refined to avoid locally storing the pointer of revocable provider. Instead, it's fetched from a source of truth when needed.
Right, but then you don't need all the RCU stuff. And revocable becomes just a convoluted abstraction for a lock and flag (as was pointed out early on).
I'm not sure if I understand you: as we're discussing about the stale pointer of revocable provider consumers might cache here, do you mean it doesn't need RCU at all to protect the race you reported in
https://lore.kernel.org/all/[email protected]/?
Quoted 22 lines
Quoted 5 lines
I agree that the risks and correct usage patterns need to be much clearer. I'll update the Documentation and the selftests to explicitly highlight this limitation and demonstrate the proper way to interact with the API, avoiding the storage of the provider pointer by value in consumer contexts.
And again, that's precisely why we need to evaluate the API in a non-trivial context *before* merging yet another version of this.
Quoted 13 lines
Quoted 4 lines
Essentially revocable still relies on having a pointer to reference counted driver data which holds the revocable provider, which makes all the RCU protection unnecessary along with most of the current revocable design and implementation.
(I'm assuming you are referring to the example in [6].)
I'm not sure I follow your reasoning. Per my understanding:
- The reference counted driver data (e.g.gdevin the GPIO example) is to ensure the pointer of revocable provider isn't freed.
- The RCU protects the pointer value from concurrent access and updates during the revocation process [7].
Quoted 8 lines
Quoted 2 lines
These seem to address different aspects. Could you provide more context on why you see the RCU protection as redundant?
I wasn't thinking of any particular example.
The struct
revocable_provideris already reference counted and you don't need anything more than that as long as you only take another reference in a context where you already hold a reference. (And struct
The reference count in struct revocable_provider can't protect the race reported https://lore.kernel.org/all/[email protected]/.
Quoted 1 line
revocable_providershould be renamed struct revocable).
Probably no, struct revocable is for consumer handle. It needs somewhere to store the SRCU index.
Quoted 2 lines
SRCU is what prevents the race against revoke, no need for RCU.
No, without the RCU, it can't prevent the race between revoking and creating a new consumer handle.
Quoted 6 lines
But this is designing yet another version of revocable. And that should be done out-of-tree.
Johan
Johan Hovold
maintainerQuoted 18 lines · Tzung-Bi Shih
Quoted 7 lines · Johan Hovold
Quoted 5 lines · Tzung-Bi Shih
You're right to point out the issue with copying the pointer of revocable provider. If a consumer stores this pointer directly,
rcu_replace_pointer()in the producer'srevocable_provider_revoke()will not affect the consumer's copy. I understand this concern.Quoted 5 lines
Quoted 3 lines
The intention was never for consumers to cache the pointer of revocable provider long-term. The design relies on consumers obtaining the current valid provider pointer at the point of access.
But that is not what the selftest does currently, nor is it what you
Understood. As mentioned in my previous email, I'll update the selftests to reflect this. The test case somehow is simplified to setup the scenario it wants to test.
Quoted 5 lines
Quoted 2 lines
need for your initial motivation for this which was miscdev where you don't have any reference counted driver data to store the pointer in.
You're right that
cros_ec_chardev.cneeds to be adjusted before using the version of revocable.
That's part of the problem here. It's unclear what problem or problems you're trying to solve. You started off with the miscdev issue, this thing morphed into something else, and now everything is just a big mess with unclear semantics and a totally confused implementation.
Look, I'm not blaming you for how we ended up here. This thing should not have been merged until there was a general agreement on the usefulness of the API (which requires a problem statement and use case).
The right people clearly didn't look at this in any detail since they did not expect it to be merged any time soon.
And it's just unfair to you to have to redesign the whole thing under time pressure a few days before the merge window opens. New code is supposed to be ready weeks in advance, not be created and merged only days before.
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
In the latest GPIO transition series [5], the usage pattern has been refined to avoid locally storing the pointer of revocable provider. Instead, it's fetched from a source of truth when needed.
Quoted 8 lines
Quoted 3 lines
Right, but then you don't need all the RCU stuff. And revocable becomes just a convoluted abstraction for a lock and flag (as was pointed out early on).
I'm not sure if I understand you: as we're discussing about the stale pointer of revocable provider consumers might cache here, do you mean it doesn't need RCU at all to protect the race you reported in
https://lore.kernel.org/all/[email protected]/?
Right. It's not needed. You have a refcounted structure and you can use the refcount to prevent it from going away.
Quoted 24 lines
Quoted 24 lines
Quoted 4 lines
I agree that the risks and correct usage patterns need to be much clearer. I'll update the Documentation and the selftests to explicitly highlight this limitation and demonstrate the proper way to interact with the API, avoiding the storage of the provider pointer by value in consumer contexts.
And again, that's precisely why we need to evaluate the API in a non-trivial context *before* merging yet another version of this.
Quoted 15 lines
Quoted 4 lines
Essentially revocable still relies on having a pointer to reference counted driver data which holds the revocable provider, which makes all the RCU protection unnecessary along with most of the current revocable design and implementation.
(I'm assuming you are referring to the example in [6].)
I'm not sure I follow your reasoning. Per my understanding:
- The reference counted driver data (e.g.gdevin the GPIO example) is to ensure the pointer of revocable provider isn't freed.
- The RCU protects the pointer value from concurrent access and updates during the revocation process [7].These seem to address different aspects. Could you provide more context on why you see the RCU protection as redundant?
Quoted 8 lines
Quoted 5 lines
I wasn't thinking of any particular example.
The struct
revocable_provideris already reference counted and you don't need anything more than that as long as you only take another reference in a context where you already hold a reference. (And structThe reference count in struct
revocable_providercan't protect the race reported https://lore.kernel.org/all/[email protected]/.
Yes, it can. You just need to make sure you hold a reference. And redesign the API to let you do so.
Quoted 4 lines
Quoted 1 line
revocable_providershould be renamed struct revocable).Probably no, struct revocable is for consumer handle. It needs somewhere to store the SRCU index.
Yeah, you'd need to store the SRCU index elsewhere (e.g. int, typedef, context struct).
Quoted 4 lines
Quoted 1 line
SRCU is what prevents the race against revoke, no need for RCU.
No, without the RCU, it can't prevent the race between revoking and creating a new consumer handle.
Yes, it can. You just need to take a step back and redesign this thing again.
Quoted 2 lines
Quoted 2 lines
But this is designing yet another version of revocable. And that should be done out-of-tree.
And that should be done out-of-tree.
Johan
Greg Kroah-Hartman
maintainerQuoted 28 lines · Johan Hovold
I was surprised to learn that the revocable functionality was merged the other week given the community feedback on list and at LPC, but not least since there are no users of it, which we are supposed to require to be able to evaluate it properly.
The chromeos ec driver issue which motivated this work turned out not to need it as was found during review. And the example gpiolib conversion was posted the very same morning that this was merged which hardly provides enough time for evaluation (even if Bartosz quickly reported a performance regression).
Turns out there are correctness issues with both the gpiolib conversion and the revocable design itself that can lead to use-after-free and hung tasks (see
[1] and [2]).And as was pointed out repeatedly during review, and again at the day of the merge, this does not look like the right interface for the chardev unplug issue.
Despite the last-minute attempt at addressing the issues mentioned above incrementally, the revocable design is still fundamentally flawed (see patch 3/3).
We have processes like requiring a user before merging a new interface so that issues like these can be identified and the soundness of an API be evaluated. They also give a sense of when things are expected to happen, which allows our scarce reviewers to manage their time (e.g. to not be forced to drop everything else they are doing when things are merged prematurely).
Quoted 5 lines
There really is no reason to exempt any new interface from this regardless of whether one likes the underlying concept or not.
Revert the revocable implementation until a redesign has been proposed and evaluated properly.
After thinking about this a lot, and talking it over with Danilo a bit, I've applied this series that reverts these changes.
Kernel developers / maintainers are only "allowed" one major argument / fight a year, and I really don't want to burn my 2026 usage so early in the year :)
Tzung-Bi, can you take the feedback here, and what you have learned from the gpio patch series, and rework this into a "clean" patch series for us to review and comment on for future releases? That should give us all a baseline on which to work off of, without having to worry about the different versions/fixes floating around at the moment.
thanks,
greg k-h
Quoted 42 lines · Greg Kroah-Hartman
Quoted 28 lines · Johan Hovold
I was surprised to learn that the revocable functionality was merged the other week given the community feedback on list and at LPC, but not least since there are no users of it, which we are supposed to require to be able to evaluate it properly.
The chromeos ec driver issue which motivated this work turned out not to need it as was found during review. And the example gpiolib conversion was posted the very same morning that this was merged which hardly provides enough time for evaluation (even if Bartosz quickly reported a performance regression).
Turns out there are correctness issues with both the gpiolib conversion and the revocable design itself that can lead to use-after-free and hung tasks (see
[1] and [2]).And as was pointed out repeatedly during review, and again at the day of the merge, this does not look like the right interface for the chardev unplug issue.
Despite the last-minute attempt at addressing the issues mentioned above incrementally, the revocable design is still fundamentally flawed (see patch 3/3).
We have processes like requiring a user before merging a new interface so that issues like these can be identified and the soundness of an API be evaluated. They also give a sense of when things are expected to happen, which allows our scarce reviewers to manage their time (e.g. to not be forced to drop everything else they are doing when things are merged prematurely).
Quoted 5 lines
There really is no reason to exempt any new interface from this regardless of whether one likes the underlying concept or not.
Revert the revocable implementation until a redesign has been proposed and evaluated properly.
After thinking about this a lot, and talking it over with Danilo a bit, I've applied this series that reverts these changes.
Kernel developers / maintainers are only "allowed" one major argument / fight a year, and I really don't want to burn my 2026 usage so early in the year :)
Quoted 5 lines
Tzung-Bi, can you take the feedback here, and what you have learned from the gpio patch series, and rework this into a "clean" patch series for us to review and comment on for future releases? That should give us all a baseline on which to work off of, without having to worry about the different versions/fixes floating around at the moment.
Acknowledged. I'll start reworking this into a unified series that incorporates the feedback and lessons learned.
Quoted 43 lines · Greg Kroah-Hartman
Quoted 28 lines · Johan Hovold
I was surprised to learn that the revocable functionality was merged the other week given the community feedback on list and at LPC, but not least since there are no users of it, which we are supposed to require to be able to evaluate it properly.
The chromeos ec driver issue which motivated this work turned out not to need it as was found during review. And the example gpiolib conversion was posted the very same morning that this was merged which hardly provides enough time for evaluation (even if Bartosz quickly reported a performance regression).
Turns out there are correctness issues with both the gpiolib conversion and the revocable design itself that can lead to use-after-free and hung tasks (see
[1] and [2]).And as was pointed out repeatedly during review, and again at the day of the merge, this does not look like the right interface for the chardev unplug issue.
Despite the last-minute attempt at addressing the issues mentioned above incrementally, the revocable design is still fundamentally flawed (see patch 3/3).
We have processes like requiring a user before merging a new interface so that issues like these can be identified and the soundness of an API be evaluated. They also give a sense of when things are expected to happen, which allows our scarce reviewers to manage their time (e.g. to not be forced to drop everything else they are doing when things are merged prematurely).
Quoted 5 lines
There really is no reason to exempt any new interface from this regardless of whether one likes the underlying concept or not.
Revert the revocable implementation until a redesign has been proposed and evaluated properly.
After thinking about this a lot, and talking it over with Danilo a bit, I've applied this series that reverts these changes.
Kernel developers / maintainers are only "allowed" one major argument / fight a year, and I really don't want to burn my 2026 usage so early in the year :)
Quoted 6 lines
Tzung-Bi, can you take the feedback here, and what you have learned from the gpio patch series, and rework this into a "clean" patch series for us to review and comment on for future releases? That should give us all a baseline on which to work off of, without having to worry about the different versions/fixes floating around at the moment.
I think it's a good decision. I definitely want to see it upstream but it needs a serious rework and I think it should go upstream together with the first user. I'm fine with it being the GPIO subsystem and happy to help with reviewing and development.
Bartosz