Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm era: only resize metadata in preresume

Metadata resize shouldn't happen in the ctr. The ctr loads a temporary
(inactive) table that will only become active upon resume. That is why
resize should always be done in terms of resume. Otherwise a load (ctr)
whose inactive table never becomes active will incorrectly resize the
metadata.

Also, perform the resize directly in preresume, instead of using the
worker to do it.

The worker might run other metadata operations, e.g., it could start
digestion, before resizing the metadata. These operations will end up
using the old size.

This could lead to errors, like:

device-mapper: era: metadata_digest_transcribe_writeset: dm_array_set_value failed
device-mapper: era: process_old_eras: digest step failed, stopping digestion

The reason of the above error is that the worker started the digestion
of the archived writeset using the old, larger size.

As a result, metadata_digest_transcribe_writeset tried to write beyond
the end of the era array.

Fixes: eec40579d84873 ("dm: add era target")
Cc: stable@vger.kernel.org # v3.15+
Signed-off-by: Nikos Tsironis <ntsironis@arrikto.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>

authored by

Nikos Tsironis and committed by
Mike Snitzer
cca2c6ae 64f2d15a

+10 -11
+10 -11
drivers/md/dm-era-target.c
··· 1501 1501 } 1502 1502 era->md = md; 1503 1503 1504 - era->nr_blocks = calc_nr_blocks(era); 1505 - 1506 - r = metadata_resize(era->md, &era->nr_blocks); 1507 - if (r) { 1508 - ti->error = "couldn't resize metadata"; 1509 - era_destroy(era); 1510 - return -ENOMEM; 1511 - } 1512 - 1513 1504 era->wq = alloc_ordered_workqueue("dm-" DM_MSG_PREFIX, WQ_MEM_RECLAIM); 1514 1505 if (!era->wq) { 1515 1506 ti->error = "could not create workqueue for metadata object"; ··· 1575 1584 dm_block_t new_size = calc_nr_blocks(era); 1576 1585 1577 1586 if (era->nr_blocks != new_size) { 1578 - r = in_worker1(era, metadata_resize, &new_size); 1579 - if (r) 1587 + r = metadata_resize(era->md, &new_size); 1588 + if (r) { 1589 + DMERR("%s: metadata_resize failed", __func__); 1580 1590 return r; 1591 + } 1592 + 1593 + r = metadata_commit(era->md); 1594 + if (r) { 1595 + DMERR("%s: metadata_commit failed", __func__); 1596 + return r; 1597 + } 1581 1598 1582 1599 era->nr_blocks = new_size; 1583 1600 }