Re: [PATCH V5 7/9] dax: read holder_ops once in dax_holder_notify_failure()

From: Richard Cheng

Date: Thu Jun 11 2026 - 23:03:13 EST


On Thu, Jun 11, 2026 at 05:32:45PM +0800, John Groves wrote:
> From: John Groves <John@xxxxxxxxxx>
>
> dax_holder_notify_failure() reads dax_dev->holder_ops twice without
> READ_ONCE() -- once for the NULL check and once for the indirect
> notify_failure() call. A concurrent fs_put_dax() or kill_dax() can clear
> holder_ops between the two reads, so the check can observe a non-NULL
> pointer while the call dereferences NULL.
>

Hello John,

Thanks for this.

Reviewed-by: Richard Cheng <icheng@xxxxxxxxxx>

Small message nit, kill_dax() isn't a racing clearer.
Plus I think this only fix holder_ops double-fetch, the fs_put_dax()
race issue is separate and pre-existing.

Best regards,
Richard Cheng.

> Fetch holder_ops once into a local with READ_ONCE() so the NULL check and
> the indirect call observe the same value.
>
> Fixes: 8012b86608552 ("dax: introduce holder for dax_device")
> Suggested-by: Richard Cheng <icheng@xxxxxxxxxx>
> Signed-off-by: John Groves <john@xxxxxxxxxx>
> ---
> drivers/dax/super.c | 11 +++++++++--
> 1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/dax/super.c b/drivers/dax/super.c
> index 25cf99dd9360b..6b5ee6589e39b 100644
> --- a/drivers/dax/super.c
> +++ b/drivers/dax/super.c
> @@ -303,6 +303,7 @@ EXPORT_SYMBOL_GPL(dax_recovery_write);
> int dax_holder_notify_failure(struct dax_device *dax_dev, u64 off,
> u64 len, int mf_flags)
> {
> + const struct dax_holder_operations *ops;
> int rc, id;
>
> id = dax_read_lock();
> @@ -311,12 +312,18 @@ int dax_holder_notify_failure(struct dax_device *dax_dev, u64 off,
> goto out;
> }
>
> - if (!dax_dev->holder_ops) {
> + /*
> + * Read holder_ops once: a concurrent fs_put_dax() or kill_dax() can
> + * clear it. Without the single fetch the compiler could reload
> + * between the NULL check and the call and dereference a NULL ops.
> + */
> + ops = READ_ONCE(dax_dev->holder_ops);
> + if (!ops) {
> rc = -EOPNOTSUPP;
> goto out;
> }
>
> - rc = dax_dev->holder_ops->notify_failure(dax_dev, off, len, mf_flags);
> + rc = ops->notify_failure(dax_dev, off, len, mf_flags);
> out:
> dax_read_unlock(id);
> return rc;
> --
> 2.53.0
>
>