[PATCH] block: order timestamp flag clearing before plug detachment
From: Wael HASNAOUI
Date: Mon Nov 09 2026 - 10:17:58 EST
From: Wael Hasnaoui <wael.hasnaoui@xxxxxxxxx>
blk_plug_invalidate_ts() runs when a task is switched back in and assumes
that PF_BLOCK_TS implies a non-NULL current->plug. blk_finish_plug()
clears the flag through __blk_flush_plug() before detaching the plug in
the source, but nothing prevents the compiler from reordering those
stores when the flush is inlined.
An arm64 kernel built with Android Clang r596125 and AutoFDO contains
the following sequence, where x19 is the plug and x20 is current:
str xzr, [x19, #0x20] // plug->cur_ktime = 0
ldr w8, [x20, #0x54] // current->flags
str xzr, [x20, #0xad8] // current->plug = NULL
and w8, w8, #0xdfffffff
str w8, [x20, #0x54] // clear PF_BLOCK_TS
Preemption after detaching the plug but before storing the cleared
flag exposes a NULL plug with PF_BLOCK_TS still set. When this task
resumes, blk_plug_invalidate_ts() dereferences NULL before execution can
return to the pending flag-clear store. This explains a recorded write
fault at address 0x20 in the scheduler's timestamp invalidation.
Add a compiler barrier between the flush and pointer detachment to
preserve the invariant across preemption, including when the flush is
inlined. This needs compiler ordering between accesses by the same task,
not an additional hardware memory fence.
Fixes: fad156c2af22 ("block: invalidate cached plug timestamp after task switch")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Wael Hasnaoui <wael.hasnaoui@xxxxxxxxx>
---
Based on Linux 7.4-rc2 (7475ea8b58616b33c04afb976cf0fbaad9dd63fb).
The same code is present in Android common 6.18.38.
Validation:
- The unsafe ordering is present in the installed arm64 Image. Its entire
blk_finish_plug() function matches a symbol-bearing reference ELF;
the whole-build IDs differ, so attribution used that byte match.
- A focused compile of unchanged Android common blk-core.c with Clang
r596125 and the public GKI AutoFDO profile reproduces the ordering.
With this barrier, the flag-clear store precedes pointer detachment.
Both compile without warnings under Kbuild's normal warning policy.
- A bounded model of the actual instructions reaches the recorded 0x20
fault from a valid state at two interruption points. The corrected
order passes all 64 combinations of the tested switch boundaries.
- The patch applies to both the mainline and Android common source.
Checkpatch reports no style issues; the absent local Fixes history
was checked against the public commit separately. DCO sign-off is
pending the author's review.
This is not a full-kernel runtime reproducer. A full mainline build and
on-device validation have not been performed. The saved panic does not
retain the interrupted PC, so its precise historical interleaving is
inferred. Supporting compiler/model evidence is available on request.
block/blk-core.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/block/blk-core.c b/block/blk-core.c
index 8836c70..99f79bb 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1299,6 +1299,12 @@ void blk_finish_plug(struct blk_plug *plug)
{
if (plug == current->plug) {
__blk_flush_plug(plug, false);
+ /*
+ * A preempted task invalidates its cached timestamp when it is
+ * scheduled back in. Keep the PF_BLOCK_TS clear above ordered
+ * before detaching the plug, including when the flush is inlined.
+ */
+ barrier();
current->plug = NULL;
}
}