[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAMRc=MeO9vD0SA1ZjPP_K-0FT8ePTNNoSRqfewQRc5dMR6-SBA@mail.gmail.com>
Date: Wed, 4 Feb 2026 14:12:20 +0100
From: Bartosz Golaszewski <brgl@...nel.org>
To: Tzung-Bi Shih <tzungbi@...nel.org>
Cc: Benson Leung <bleung@...omium.org>, Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
"Rafael J . Wysocki" <rafael@...nel.org>, Danilo Krummrich <dakr@...nel.org>, Linus Walleij <linusw@...nel.org>,
Jonathan Corbet <corbet@....net>, Shuah Khan <shuah@...nel.org>, linux-doc@...r.kernel.org,
linux-kernel@...r.kernel.org, chrome-platform@...ts.linux.dev,
linux-kselftest@...r.kernel.org,
Laurent Pinchart <laurent.pinchart@...asonboard.com>,
Wolfram Sang <wsa+renesas@...g-engineering.com>, Simona Vetter <simona.vetter@...ll.ch>,
Dan Williams <dan.j.williams@...el.com>, Jason Gunthorpe <jgg@...dia.com>, linux-gpio@...r.kernel.org
Subject: Re: [PATCH v7 1/3] revocable: Revocable resource management
On Fri, Jan 16, 2026 at 9:03 AM Tzung-Bi Shih <tzungbi@...nel.org> wrote:
>
> Some resources can be removed asynchronously, for example, resources
> provided by a hot-pluggable device like USB. When holding a reference
> to such a resource, it's possible for the resource to be removed and
> its memory freed, leading to use-after-free errors on subsequent access.
>
> The "revocable" mechanism addresses this by establishing a weak reference
> to a resource that might be freed at any time. It allows a resource
> consumer to safely attempt to access the resource, guaranteeing that the
> access is valid for the duration of its use, or it fails safely if the
> resource has already been revoked.
>
> The implementation uses a provider/consumer model built on Sleepable
> RCU (SRCU) to guarantee safe memory access:
>
> - A resource provider, such as a driver for a hot-pluggable device,
> allocates a struct revocable_provider and initializes it with a pointer
> to the resource.
>
> - A resource consumer that wants to access the resource allocates a
> struct revocable which acts as a handle containing a reference to the
> provider.
>
> - To access the resource, the consumer uses revocable_try_access().
> This function enters an SRCU read-side critical section and returns
> the pointer to the resource. If the provider has already freed the
> resource, it returns NULL. After use, the consumer calls
> revocable_withdraw_access() to exit the SRCU critical section. The
> REVOCABLE_TRY_ACCESS_WITH() and REVOCABLE_TRY_ACCESS_SCOPED() are
> convenient helpers for doing that.
>
> - When the provider needs to remove the resource, it calls
> revocable_provider_revoke(). This function sets the internal resource
> pointer to NULL and then calls synchronize_srcu() to wait for all
> current readers to finish before the resource can be completely torn
> down.
>
> Acked-by: Danilo Krummrich <dakr@...nel.org>
> Signed-off-by: Tzung-Bi Shih <tzungbi@...nel.org>
> ---
[snip]
> diff --git a/include/linux/revocable.h b/include/linux/revocable.h
> new file mode 100644
> index 000000000000..659ba01c58db
> --- /dev/null
> +++ b/include/linux/revocable.h
> @@ -0,0 +1,69 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright 2026 Google LLC
> + */
> +
> +#ifndef __LINUX_REVOCABLE_H
> +#define __LINUX_REVOCABLE_H
> +
> +#include <linux/compiler.h>
> +#include <linux/cleanup.h>
> +
> +struct device;
> +struct revocable;
> +struct revocable_provider;
> +
> +struct revocable_provider *revocable_provider_alloc(void *res);
> +void revocable_provider_revoke(struct revocable_provider *rp);
> +struct revocable_provider *devm_revocable_provider_alloc(struct device *dev,
> + void *res);
> +
> +struct revocable *revocable_alloc(struct revocable_provider *rp);
> +void revocable_free(struct revocable *rev);
> +void *revocable_try_access(struct revocable *rev) __acquires(&rev->rp->srcu);
> +void revocable_withdraw_access(struct revocable *rev) __releases(&rev->rp->srcu);
> +
> +DEFINE_FREE(access_rev, struct revocable *, if (_T) revocable_withdraw_access(_T))
> +
> +/**
> + * REVOCABLE_TRY_ACCESS_WITH() - A helper for accessing revocable resource
> + * @_rev: The consumer's ``struct revocable *`` handle.
> + * @_res: A pointer variable that will be assigned the resource.
> + *
> + * The macro simplifies the access-release cycle for consumers, ensuring that
> + * revocable_withdraw_access() is always called, even in the case of an early
> + * exit.
> + *
> + * It creates a local variable in the current scope. @_res is populated with
> + * the result of revocable_try_access(). The consumer code **must** check if
> + * @_res is ``NULL`` before using it. The revocable_withdraw_access() function
> + * is automatically called when the scope is exited.
> + *
> + * Note: It shares the same issue with guard() in cleanup.h. No goto statements
> + * are allowed before the helper. Otherwise, the compiler fails with
> + * "jump bypasses initialization of variable with __attribute__((cleanup))".
> + */
> +#define REVOCABLE_TRY_ACCESS_WITH(_rev, _res) \
> + struct revocable *__UNIQUE_ID(name) __free(access_rev) = _rev; \
> + _res = revocable_try_access(_rev)
> +
> +#define _REVOCABLE_TRY_ACCESS_SCOPED(_rev, _label, _res) \
> + for (struct revocable *__UNIQUE_ID(name) __free(access_rev) = _rev; \
> + (_res = revocable_try_access(_rev)) || true; ({ goto _label; })) \
> + if (0) { \
> +_label: \
> + break; \
> + } else
> +
> +/**
> + * REVOCABLE_TRY_ACCESS_SCOPED() - A helper for accessing revocable resource
> + * @_rev: The consumer's ``struct revocable *`` handle.
> + * @_res: A pointer variable that will be assigned the resource.
> + *
> + * Similar to REVOCABLE_TRY_ACCESS_WITH() but with an explicit scope from a
> + * temporary ``for`` loop.
> + */
> +#define REVOCABLE_TRY_ACCESS_SCOPED(_rev, _res) \
Seeing this code used in GPIO, I would suggest a coding-style change
before it makes its way into other places:
revocable_try_access_with() looks better and is in line with most
other macros. There's no reason for capitalisation IMO and it makes
the code using it look like there was some issue with it, as if this
was a WARN() or something.
I'd suggest changing all these macros to using lowercase and queuing
it for v7.0.
Bartosz
> + _REVOCABLE_TRY_ACCESS_SCOPED(_rev, __UNIQUE_ID(label), _res)
> +
> +#endif /* __LINUX_REVOCABLE_H */
> --
> 2.52.0.457.g6b5491de43-goog
>
Powered by blists - more mailing lists