Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5349b17c authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Greg Kroah-Hartman
Browse files

dm integrity: fix flush with external metadata device



[ Upstream commit 9b5948267adc9e689da609eb61cf7ed49cae5fa8 ]

With external metadata device, flush requests are not passed down to the
data device.

Fix this by submitting the flush request in dm_integrity_flush_buffers. In
order to not degrade performance, we overlap the data device flush with
the metadata device flush.

Reported-by: default avatarLukas Straub <lukasstraub2@web.de>
Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent c553300f
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -1446,6 +1446,12 @@ sector_t dm_bufio_get_device_size(struct dm_bufio_client *c)
}
EXPORT_SYMBOL_GPL(dm_bufio_get_device_size);

struct dm_io_client *dm_bufio_get_dm_io_client(struct dm_bufio_client *c)
{
	return c->dm_io;
}
EXPORT_SYMBOL_GPL(dm_bufio_get_dm_io_client);

sector_t dm_bufio_get_block_number(struct dm_buffer *b)
{
	return b->block;
+48 −8
Original line number Diff line number Diff line
@@ -1343,12 +1343,52 @@ static int dm_integrity_rw_tag(struct dm_integrity_c *ic, unsigned char *tag, se
	return 0;
}

static void dm_integrity_flush_buffers(struct dm_integrity_c *ic)
struct flush_request {
	struct dm_io_request io_req;
	struct dm_io_region io_reg;
	struct dm_integrity_c *ic;
	struct completion comp;
};

static void flush_notify(unsigned long error, void *fr_)
{
	struct flush_request *fr = fr_;
	if (unlikely(error != 0))
		dm_integrity_io_error(fr->ic, "flusing disk cache", -EIO);
	complete(&fr->comp);
}

static void dm_integrity_flush_buffers(struct dm_integrity_c *ic, bool flush_data)
{
	int r;

	struct flush_request fr;

	if (!ic->meta_dev)
		flush_data = false;
	if (flush_data) {
		fr.io_req.bi_op = REQ_OP_WRITE,
		fr.io_req.bi_op_flags = REQ_PREFLUSH | REQ_SYNC,
		fr.io_req.mem.type = DM_IO_KMEM,
		fr.io_req.mem.ptr.addr = NULL,
		fr.io_req.notify.fn = flush_notify,
		fr.io_req.notify.context = &fr;
		fr.io_req.client = dm_bufio_get_dm_io_client(ic->bufio),
		fr.io_reg.bdev = ic->dev->bdev,
		fr.io_reg.sector = 0,
		fr.io_reg.count = 0,
		fr.ic = ic;
		init_completion(&fr.comp);
		r = dm_io(&fr.io_req, 1, &fr.io_reg, NULL);
		BUG_ON(r);
	}

	r = dm_bufio_write_dirty_buffers(ic->bufio);
	if (unlikely(r))
		dm_integrity_io_error(ic, "writing tags", r);

	if (flush_data)
		wait_for_completion(&fr.comp);
}

static void sleep_on_endio_wait(struct dm_integrity_c *ic)
@@ -2077,7 +2117,7 @@ static void integrity_commit(struct work_struct *w)
	flushes = bio_list_get(&ic->flush_bio_list);
	if (unlikely(ic->mode != 'J')) {
		spin_unlock_irq(&ic->endio_wait.lock);
		dm_integrity_flush_buffers(ic);
		dm_integrity_flush_buffers(ic, true);
		goto release_flush_bios;
	}

@@ -2287,7 +2327,7 @@ static void do_journal_write(struct dm_integrity_c *ic, unsigned write_start,
	complete_journal_op(&comp);
	wait_for_completion_io(&comp.comp);

	dm_integrity_flush_buffers(ic);
	dm_integrity_flush_buffers(ic, true);
}

static void integrity_writer(struct work_struct *w)
@@ -2329,7 +2369,7 @@ static void recalc_write_super(struct dm_integrity_c *ic)
{
	int r;

	dm_integrity_flush_buffers(ic);
	dm_integrity_flush_buffers(ic, false);
	if (dm_integrity_failed(ic))
		return;

@@ -2532,7 +2572,7 @@ static void bitmap_flush_work(struct work_struct *work)
	unsigned long limit;
	struct bio *bio;

	dm_integrity_flush_buffers(ic);
	dm_integrity_flush_buffers(ic, false);

	range.logical_sector = 0;
	range.n_sectors = ic->provided_data_sectors;
@@ -2541,7 +2581,7 @@ static void bitmap_flush_work(struct work_struct *work)
	add_new_range_and_wait(ic, &range);
	spin_unlock_irq(&ic->endio_wait.lock);

	dm_integrity_flush_buffers(ic);
	dm_integrity_flush_buffers(ic, true);
	if (ic->meta_dev)
		blkdev_issue_flush(ic->dev->bdev, GFP_NOIO, NULL);

@@ -2812,11 +2852,11 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
		if (ic->meta_dev)
			queue_work(ic->writer_wq, &ic->writer_work);
		drain_workqueue(ic->writer_wq);
		dm_integrity_flush_buffers(ic);
		dm_integrity_flush_buffers(ic, true);
	}

	if (ic->mode == 'B') {
		dm_integrity_flush_buffers(ic);
		dm_integrity_flush_buffers(ic, true);
#if 1
		/* set to 0 to test bitmap replay code */
		init_journal(ic, 0, ic->journal_sections, 0);
+1 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ void dm_bufio_set_minimum_buffers(struct dm_bufio_client *c, unsigned n);

unsigned dm_bufio_get_block_size(struct dm_bufio_client *c);
sector_t dm_bufio_get_device_size(struct dm_bufio_client *c);
struct dm_io_client *dm_bufio_get_dm_io_client(struct dm_bufio_client *c);
sector_t dm_bufio_get_block_number(struct dm_buffer *b);
void *dm_bufio_get_block_data(struct dm_buffer *b);
void *dm_bufio_get_aux_data(struct dm_buffer *b);