[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <68d45a76a36ad_1c79100a6@dwillia2-mobl4.notmuch>
Date: Wed, 24 Sep 2025 13:54:14 -0700
From: <dan.j.williams@...el.com>
To: Tzung-Bi Shih <tzungbi@...nel.org>, Benson Leung <bleung@...omium.org>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>, "Rafael J . Wysocki"
<rafael@...nel.org>, Danilo Krummrich <dakr@...nel.org>
CC: Jonathan Corbet <corbet@....net>, Shuah Khan <shuah@...nel.org>, "Dawid
Niedzwiecki" <dawidn@...gle.com>, <linux-doc@...r.kernel.org>,
<linux-kernel@...r.kernel.org>, <chrome-platform@...ts.linux.dev>,
<linux-kselftest@...r.kernel.org>, <tzungbi@...nel.org>, Laurent Pinchart
<laurent.pinchart@...asonboard.com>, Bartosz Golaszewski <brgl@...ev.pl>,
Wolfram Sang <wsa+renesas@...g-engineering.com>
Subject: Re: [PATCH v4 5/7] revocable: Add fops replacement
Tzung-Bi Shih wrote:
> Introduce revocable_replace_fops() to simplify the use of the revocable
> API with file_operations.
>
> The function, should be called from a driver's ->open(), replaces the
> fops with a wrapper that automatically handles the `try_access` and
> `withdraw_access`.
>
> When the file is closed, the wrapper's ->release() restores the original
> fops and cleanups. This centralizes the revocable logic, making drivers
> cleaner and easier to maintain.
>
> Signed-off-by: Tzung-Bi Shih <tzungbi@...nel.org>
[..]
> +/**
> + * revocable_replace_fops() - Replace the file operations to be revocable-aware.
> + *
> + * Should be used only from ->open() instances.
> + */
> +int revocable_replace_fops(struct file *filp, struct revocable_provider *rp,
> + const struct revocable_operations *rops)
> +{
> + struct fops_replacement *fr;
> +
> + fr = kzalloc(sizeof(*fr), GFP_KERNEL);
> + if (!fr)
> + return -ENOMEM;
> +
> + fr->filp = filp;
> + fr->rops = rops;
> + fr->orig_fops = filp->f_op;
> + fr->rev = revocable_alloc(rp);
> + if (!fr->rev)
> + return -ENOMEM;
> + memcpy(&fr->fops, filp->f_op, sizeof(struct file_operations));
> + scoped_guard(mutex, &fops_replacement_mutex)
> + list_add(&fr->list, &fops_replacement_list);
This list grows for every active instance? Unless I am misreading, that
looks like a scaling burden that the simple approach below does not
have.
> + fr->fops.release = revocable_fr_release;
> +
> + if (filp->f_op->read)
> + fr->fops.read = revocable_fr_read;
> + if (filp->f_op->poll)
> + fr->fops.poll = revocable_fr_poll;
> + if (filp->f_op->unlocked_ioctl)
> + fr->fops.unlocked_ioctl = revocable_fr_unlocked_ioctl;
> +
> + filp->f_op = &fr->fops;
> + return 0;
> +}
This facility is protecting the wrong resource, and I argue hides bugs
in drivers that think they need this. That matches the conclusion I came
to with my "managed_fops" attempt.
The resource that is being revoked is the device's attachment to its
driver. Whether that is dev_get_drvdata() or some other device-to-data
lookup, that is the resource that gets removed, not the fops themselves.
The only resource race with fops is whether the code text section
remains available while the fops are registered, but that lifetime scope
is not at a per-device instance scope.
revocable() could be useful for more complicated scenarios, but for
making sure that ->unlocked_ioctl(), ->poll(), and ->read() start
reliably failing, just do:
guard(rwsem_read)(&subsystem_device_registration_lock);
data = subsystem_lookup_device_relative_data(...)
if (data)
return subsystem_{ioctl,poll,read}(data, ...);
return -ENXIO;
...and revoke future subsystem_{ioctl,poll,read}() invocations by making
subsystem_lookup_device_relative_data() start failing under
guard(rwsem_write)(&subsystem_device_registration_lock).
Powered by blists - more mailing lists