]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
dm cache: fix concurrent write failure in passthrough mode
authorMing-Hung Tsai <mtsai@redhat.com>
Mon, 9 Feb 2026 07:54:09 +0000 (15:54 +0800)
committerMikulas Patocka <mpatocka@redhat.com>
Mon, 2 Mar 2026 15:49:58 +0000 (16:49 +0100)
When bio prison cell lock acquisition fails due to concurrent writes to
the same block in passthrough mode, dm-cache incorrectly returns an I/O
error instead of properly handling the concurrency. This can occur in
both process and workqueue contexts when invalidate_lock() is called for
exclusive access to a data block. Fix this by deferring the write bios
to ensure proper block device behavior.

Reproduce steps:

1. Create a cache device

dmsetup create cmeta --table "0 8192 linear /dev/sdc 0"
dmsetup create cdata --table "0 131072 linear /dev/sdc 8192"
dmsetup create corig --table "0 262144 linear /dev/sdc 262144"
dd if=/dev/zero of=/dev/mapper/cmeta bs=4k count=1 oflag=direct
dmsetup create cache --table "0 262144 cache /dev/mapper/cmeta \
/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 writethrough smq 0"

2. Promote the first data block into cache

fio --filename=/dev/mapper/cache --name=populate --rw=write --bs=4k \
--direct=1 --size=64k

3. Reload the cache into passthrough mode

dmsetup suspend cache
dmsetup reload cache --table "0 262144 cache /dev/mapper/cmeta \
/dev/mapper/cdata /dev/mapper/corig 128 2 metadata2 passthrough smq 0"
dmsetup resume cache

4. Write to the first cached block concurrently. Sometimes one of the
   processes will receive I/O errors.

fio --filename=/dev/mapper/cache --name test --rw=randwrite --bs=4k \
--randrepeat=0 --direct=1 --numjobs=2 --size 64k

 <snip>
 fio-3.41
 fio: io_u error on file /dev/mapper/cache: Input/output error: write offset=4096, buflen=4096
 fio: pid=106, err=5/file:io_u.c:2008, func=io_u error, error=Input/output error
 test: (groupid=0, jobs=1): err= 0: pid=105
 test: (groupid=0, jobs=1): err= 5 (file:io_u.c:2008, func=io_u error, error=Input/output error): pid=106
 <snip>

Fixes: b29d4986d0da ("dm cache: significant rework to leverage dm-bio-prison-v2")
Signed-off-by: Ming-Hung Tsai <mtsai@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
drivers/md/dm-cache-target.c

index d3ef88b859ab36dbff24cdd341c9bf9cb5c6151e..32d22c7b9a07d61d2d4a94ce1e5dbdadf842735c 100644 (file)
@@ -1561,6 +1561,15 @@ static int invalidate_lock(struct dm_cache_migration *mg)
                            READ_WRITE_LOCK_LEVEL, prealloc, &mg->cell);
        if (r < 0) {
                free_prison_cell(cache, prealloc);
+
+               /* Defer the bio for retrying the cell lock */
+               if (mg->overwrite_bio) {
+                       struct bio *bio = mg->overwrite_bio;
+
+                       mg->overwrite_bio = NULL;
+                       defer_bio(cache, bio);
+               }
+
                invalidate_complete(mg, false);
                return r;
        }