From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794064368; b=J7tRkBtmimTCndymt1dzBwy4IPgXvvUzd1EvA5s+T1BAlCWuuOL3TSqkMTfan1Or/ig+ j6cnh1gDGmB04RR3SkNPgZvfIIIGd9hi9RqyTg0hN8mRejQfPDzUsXWZD0bDdVI7RPua2 qX6Zdqw02pPRjuTcPto9aDzbenrGSBON6R8RSJsYuZtc7EliKHqBPMzuFXcLGOxltiGK1 8IFQYH404PRBUlotLZSffLKqFBaC9Yi0Ju/KFf/svZwY/QGvhzdO5R+agHRqTsHP379C5 r9dxrsRmTiMHbpL05ulCU3pHIimmyMSafQFOtUrflJO5Dd5i6Vw8Lvxd7dDwAo5PqnA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794064368; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Transfer-Encoding; bh=vNw+NP2NnofG5PCjpEpms16Y0Ky5bSpim2n85B9GoTE=; b=aB63SkGTvyQ/XDOyspSe0mM8KuLGDrAB42yD5/qdtaFQaqvFNH2/YRQi8Q/w3p704OzY i+8kaXWFK7HFu+UcKX1jG0XsMwnkS6MG3RSdCilccnMmAuyBYc+VySOYV8ffiBmvytWdu Pps0bKra1yyb++qbpX+JSn7PpIAhH36Z8MTgCOUOHWuYdwrA6R5TLk83z+2LDgdm1oSyL BwWQB9nU/MpT623oI0ies6mNQdZU5E+KXdqoOAvvfp+DmiWK6ruIMRt/WjtGL8oDnGeut CEN+jw6iWdi3CNpC+x0X22ZSsn4GG0Yt6GUSU+MUS4YzMwPbJ/ZM2UgEo30KZgN1vJw== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=JX5rRSrZ; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BB99C606B899; Sat, 7 Nov 2026 15:12:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=JX5rRSrZ Received: by smtp.kernel.org (Postfix) with ESMTPSA id 69EFF1F0089F; Sat, 7 Nov 2026 15:12:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794064367; bh=vNw+NP2NnofG5PCjpEpms16Y0Ky5bSpim2n85B9GoTE=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=JX5rRSrZEZ6/QQmKxkL8YHwrdzxJIfEy50gyEk5d/sTvkQAXdpezbBQtQaUv4xWo6 rTGfKL5NXh4dPDcxohAsgwvUdFVgy0L53jiijEdymJlEGf008InzaM1vlTkaCBTjJk jN3llEbrL50RE5xqbf7XKKhkCzA57AFPKorFDgCc= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Mikulas Patocka , Sasha Levin Subject: [PATCH 7.3 0421/1257] dm-writecache: fix REQ_FUA processing Date: Sat, 7 Nov 2026 08:45:17 -0500 Message-ID: <20261107134951.130874014@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261107134939.434104957@linuxfoundation.org> References: <20261107134939.434104957@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: stable@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Mikulas Patocka [ Upstream commit c0df022cb0fa2bbee74bd9b90c66790bcd4e3050 ] REQ_FUA did not flush metadata in SSD mode, this commit fixes it. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org Fixes: c1005322ff02 ("dm writecache: handle REQ_FUA") Assisted-by: Claude:claude-opus-5 Assisted-by: Codex:gpt-6-sol Signed-off-by: Sasha Levin --- drivers/md/dm-writecache.c | 45 +++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/drivers/md/dm-writecache.c b/drivers/md/dm-writecache.c index 302ebed4e6ceb..75287f1667fdc 100644 --- a/drivers/md/dm-writecache.c +++ b/drivers/md/dm-writecache.c @@ -194,6 +194,7 @@ struct dm_writecache { struct task_struct *endio_thread; struct task_struct *flush_thread; + spinlock_t flush_list_lock; struct bio_list flush_list; struct dm_kcopyd_client *dm_kcopyd; @@ -1288,9 +1289,11 @@ static int writecache_flush_thread(void *data) struct bio *bio; wc_lock(wc); + spin_lock_irq(&wc->flush_list_lock); bio = bio_list_pop(&wc->flush_list); if (!bio) { set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(&wc->flush_list_lock); wc_unlock(wc); if (unlikely(kthread_should_stop())) { @@ -1301,6 +1304,7 @@ static int writecache_flush_thread(void *data) schedule(); continue; } + spin_unlock_irq(&wc->flush_list_lock); if (bio_op(bio) == REQ_OP_DISCARD) { writecache_discard(wc, bio->bi_iter.bi_sector, @@ -1322,9 +1326,12 @@ static int writecache_flush_thread(void *data) static void writecache_offload_bio(struct dm_writecache *wc, struct bio *bio) { + unsigned long flags; + spin_lock_irqsave(&wc->flush_list_lock, flags); if (bio_list_empty(&wc->flush_list)) wake_up_process(wc->flush_thread); bio_list_add(&wc->flush_list, bio); + spin_unlock_irqrestore(&wc->flush_list_lock, flags); } enum wc_map_op { @@ -1436,6 +1443,8 @@ static void writecache_bio_copy_ssd(struct dm_writecache *wc, struct bio *bio, static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio *bio) { struct wc_entry *e; + enum wc_map_op ret = WC_MAP_SUBMIT; + bool need_flush = false; do { bool found_entry = false; @@ -1472,7 +1481,8 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio writecache_map_remap_origin(wc, bio, e); wc->stats.writes_around += bio->bi_iter.bi_size >> wc->block_size_bits; wc->stats.writes += bio->bi_iter.bi_size >> wc->block_size_bits; - return WC_MAP_REMAP_ORIGIN; + ret = WC_MAP_REMAP_ORIGIN; + goto flush_pmem_and_ret; } wc->stats.writes_blocked_on_freelist++; writecache_wait_on_freelist(wc); @@ -1486,21 +1496,25 @@ static enum wc_map_op writecache_map_write(struct dm_writecache *wc, struct bio if (WC_MODE_PMEM(wc)) { bio_copy_block(wc, bio, memory_data(wc, e)); wc->stats.writes++; + need_flush = true; } else { writecache_bio_copy_ssd(wc, bio, e, search_used); return WC_MAP_REMAP; } } while (bio->bi_iter.bi_size); - if (unlikely(bio->bi_opf & REQ_FUA || wc->uncommitted_blocks >= wc->autocommit_blocks)) { - writecache_flush(wc); - if (writecache_has_error(wc)) - bio->bi_status = BLK_STS_IOERR; - } else { - writecache_schedule_autocommit(wc); +flush_pmem_and_ret: + if (need_flush) { + if (unlikely(bio->bi_opf & REQ_FUA || wc->uncommitted_blocks >= wc->autocommit_blocks)) { + writecache_flush(wc); + if (writecache_has_error(wc)) + ret = WC_MAP_ERROR; + } else { + writecache_schedule_autocommit(wc); + } } - return WC_MAP_SUBMIT; + return ret; } static enum wc_map_op writecache_map_flush(struct dm_writecache *wc, struct bio *bio) @@ -1590,7 +1604,10 @@ static int writecache_map(struct dm_target *ti, struct bio *bio) case WC_MAP_REMAP: /* make sure that writecache_end_io decrements bio_in_progress: */ - bio->bi_private = (void *)1; + if (unlikely(bio->bi_opf & REQ_FUA) && bio_op(bio) == REQ_OP_WRITE) + bio->bi_private = (void *)3; + else + bio->bi_private = (void *)1; atomic_inc(&wc->bio_in_progress[bio_data_dir(bio)]); wc_unlock(wc); return DM_MAPIO_REMAPPED; @@ -1620,12 +1637,19 @@ static int writecache_end_io(struct dm_target *ti, struct bio *bio, blk_status_t { struct dm_writecache *wc = ti->private; - if (bio->bi_private == (void *)1) { + if (bio->bi_private == (void *)1 || bio->bi_private == (void *)3) { int dir = bio_data_dir(bio); + bool fua = bio->bi_private == (void *)3; if (atomic_dec_and_test(&wc->bio_in_progress[dir])) if (unlikely(waitqueue_active(&wc->bio_in_progress_wait[dir]))) wake_up(&wc->bio_in_progress_wait[dir]); + + if (fua && likely(*status == BLK_STS_OK)) { + bio->bi_private = NULL; + writecache_offload_bio(wc, bio); + return DM_ENDIO_INCOMPLETE; + } } else if (bio->bi_private == (void *)2) { dm_iot_io_end(&wc->iot, 1); } @@ -2522,6 +2546,7 @@ static int writecache_ctr(struct dm_target *ti, unsigned int argc, char **argv) wc->memory_map_size -= (uint64_t)wc->start_sector << SECTOR_SHIFT; + spin_lock_init(&wc->flush_list_lock); bio_list_init(&wc->flush_list); wc->flush_thread = kthread_run(writecache_flush_thread, wc, "dm_writecache_flush"); if (IS_ERR(wc->flush_thread)) { -- 2.53.0