mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
dax: read holder_ops once in dax_holder_notify_failure()
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() can clear holder_ops
between the two reads, so the check can observe a non-NULL pointer while
the call dereferences NULL. (kill_dax() also clears holder_ops, but only
after synchronize_srcu(), so it cannot race a reader that is inside
dax_read_lock(); fs_put_dax() does no such synchronization.)
Fetch holder_ops once into a local with READ_ONCE() so the NULL check and
the indirect call observe the same value.
Fixes: 8012b86608 ("dax: introduce holder for dax_device")
Suggested-by: Richard Cheng <icheng@nvidia.com>
Reviewed-by: Richard Cheng <icheng@nvidia.com>
Signed-off-by: John Groves <john@groves.net>
Link: https://patch.msgid.link/0100019ecc09bb56-5ecc9c6b-35ba-44f8-b112-921b01b34478-000000@email.amazonses.com
Signed-off-by: Alison Schofield <alison.schofield@intel.com>
This commit is contained in:
parent
755effecd6
commit
7ae9d15bdc
|
|
@ -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,19 @@ 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() can clear it without
|
||||
* synchronizing against readers. 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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user