lkml.org 
[lkml]   [2019]   [Jul]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 20/43] dm log writes: make sure super sector log updates are written in order
    Date
    From: zhangyi (F) <yi.zhang@huawei.com>

    commit 211ad4b733037f66f9be0a79eade3da7ab11cbb8 upstream.

    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: 0e9cebe724597 ("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>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/md/dm-log-writes.c | 23 +++++++++++++++++++++--
    1 file changed, 21 insertions(+), 2 deletions(-)

    --- a/drivers/md/dm-log-writes.c
    +++ b/drivers/md/dm-log-writes.c
    @@ -57,6 +57,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.
    @@ -112,6 +113,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 {
    @@ -177,6 +179,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.
    @@ -212,7 +222,8 @@ static int write_metadata(struct log_wri
    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);

    @@ -334,11 +345,18 @@ static int log_super(struct log_writes_c
    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;
    }

    @@ -447,6 +465,7 @@ static int log_writes_ctr(struct dm_targ
    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);


    \
     
     \ /
      Last update: 2019-07-02 10:10    [W:4.121 / U:0.144 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site