Skip to content

Commit

Permalink
dm log writes: make sure super sector log updates are written in order
Browse files Browse the repository at this point in the history
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.

Fixes: 0e9cebe ("dm: add log writes target")
Cc: stable@vger.kernel.org
Signed-off-by: zhangyi (F) <yi.zhang@huawei.com>
Suggested-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
  • Loading branch information
zhangyi (F) authored and Mike Snitzer committed Jun 25, 2019
1 parent 10c9c8e commit 211ad4b
Showing 1 changed file with 21 additions and 2 deletions.
23 changes: 21 additions & 2 deletions drivers/md/dm-log-writes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit 211ad4b

Please sign in to comment.