FAILED: patch "[PATCH] dm log writes: make sure super sector log updates are written" failed to apply to 4.9-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.9-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 211ad4b733037f66f9be0a79eade3da7ab11cbb8 Mon Sep 17 00:00:00 2001
From: "zhangyi (F)" <[email protected]>
Date: Wed, 5 Jun 2019 21:27:08 +0800
Subject: [PATCH] dm log writes: make sure super sector log updates are written
in order
Currently, although we submit super bios in order (and super.nr_entries is incremented by each logged entry), submit_bio() is async so each super sector may not be written to log device in order and then the final nr_entries may be smaller than it should be.
This problem can be reproduced by the xfstests generic/455 with ext4:
QA output created by 455
-Silence is golden
+mark 'end' does not exist
Fix this by serializing submission of super sectors to make sure each is written to the log disk in order.
drivers/md/dm-log-writes.c +21 -2
@@ -60,6 +60,7 @@#define WRITE_LOG_VERSION 1ULL#define WRITE_LOG_MAGIC 0x6a736677736872ULL +#define WRITE_LOG_SUPER_SECTOR 0/* * The disk format for this is braindead simple.
@@ -115,6 +116,7 @@ struct log_writes_c {struct list_head logging_blocks;wait_queue_head_t wait;struct task_struct *log_kthread; +struct completion super_done; };struct pending_block {
@@ -180,6 +182,14 @@ static void log_end_io(struct bio *bio)bio_put (bio); } +static void log_end_super (struct bio *bio) +{ +struct log_writes_c *lc = bio->bi_private; + +complete (&lc->super_done); +log_end_io (bio); +} +/* * Meant to be called if there is an error, it will free all the pages * associated with the block.
@@ -215,7 +225,8 @@ static int write_metadata(struct log_writes_c *lc, void *entry, bio->bi_iter.bi_size =0 ; bio->bi_iter.bi_sector = sector;bio_set_dev (bio, lc->logdev->bdev); - bio->bi_end_io = log_end_io; + bio->bi_end_io = (sector ==WRITE_LOG_SUPER_SECTOR ) ? + log_end_super : log_end_io; bio->bi_private = lc;bio_set_op_attrs (bio,REQ_OP_WRITE ,0 );
@@ -418,11 +429,18 @@ static int log_super(struct log_writes_c *lc) super.nr_entries =cpu_to_le64 (lc->logged_entries); super.sectorsize =cpu_to_le32 (lc->sectorsize); -if (write_metadata (lc, &super,sizeof (super),NULL ,0 ,0 )) { +if (write_metadata (lc, &super,sizeof (super),NULL ,0 , +WRITE_LOG_SUPER_SECTOR )) {DMERR ("Couldn't write super" );return -1 ; } +/* +* Super sector should be writen in-order, otherwise the +* nr_entries could be rewritten incorrectly by an old bio. +*/ +wait_for_completion_io (&lc->super_done); +return 0 ; }
@@ -531,6 +549,7 @@ static int log_writes_ctr(struct dm_target *ti, unsigned int argc, char **argv)INIT_LIST_HEAD (&lc->unflushed_blocks);INIT_LIST_HEAD (&lc->logging_blocks);init_waitqueue_head (&lc->wait); +init_completion (&lc->super_done);atomic_set (&lc->io_blocks,0 );atomic_set (&lc->pending_blocks,0 );