dm-ebs can discard a block while a dirty dm-bufio buffer for the same block is still cached. If that buffer is later written back, stale data can be written over the discarded state.
That resurrects data that userspace explicitly discarded and breaks the expected discard semantics of the target. Flush pending dirty buffers before processing a following discard, then forget the matching bufio state and issue the discard. Keep writeback errors separate from the discard result so a flush failure is reported to the write bios that dirtied the buffers, while the discard bio reports only the discard operation's own status. Assisted-by: Codex:gpt-5.5-cyber-preview Signed-off-by: Samuel Moelius <[email protected]> --- Changes in v2 - fix how dirty bios are handled and how errors are reported drivers/md/dm-ebs-target.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/md/dm-ebs-target.c b/drivers/md/dm-ebs-target.c index 1e52bde48b91..5bdd1bf6c206 100644 --- a/drivers/md/dm-ebs-target.c +++ b/drivers/md/dm-ebs-target.c @@ -176,8 +176,8 @@ static void __ebs_forget_bio(struct ebs_c *ec, struct bio *bio) /* Worker function to process incoming bios. */ static void __ebs_process_bios(struct work_struct *ws) { - int r; - bool write = false; + int r, rr, write_r = 0; + bool dirty = false; sector_t block1, block2; struct ebs_c *ec = container_of(ws, struct ebs_c, ws); struct bio *bio; @@ -209,9 +209,15 @@ static void __ebs_process_bios(struct work_struct *ws) if (bio_op(bio) == REQ_OP_READ) r = __ebs_rw_bio(ec, REQ_OP_READ, bio); else if (bio_op(bio) == REQ_OP_WRITE) { - write = true; r = __ebs_rw_bio(ec, REQ_OP_WRITE, bio); + dirty = true; } else if (bio_op(bio) == REQ_OP_DISCARD) { + if (dirty) { + rr = dm_bufio_write_dirty_buffers(ec->bufio); + dirty = false; + if (rr && !write_r) + write_r = rr; + } __ebs_forget_bio(ec, bio); r = __ebs_discard_bio(ec, bio); } @@ -224,11 +230,15 @@ static void __ebs_process_bios(struct work_struct *ws) * We write dirty buffers after processing I/O on them * but before we endio thus addressing REQ_FUA/REQ_SYNC. */ - r = write ? dm_bufio_write_dirty_buffers(ec->bufio) : 0; + if (dirty) { + r = dm_bufio_write_dirty_buffers(ec->bufio); + if (r && !write_r) + write_r = r; + } while ((bio = bio_list_pop(&bios))) { /* Any other request is endioed. */ - if (unlikely(r && bio_op(bio) == REQ_OP_WRITE)) + if (unlikely(write_r && bio_op(bio) == REQ_OP_WRITE)) bio_io_error(bio); else bio_endio(bio); -- 2.43.0

