Commit 65ee21eb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-5.2/dm-fixes-2' of...

Merge tag 'for-5.2/dm-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper fixes from Mike Snitzer:

 - Fix incorrect uses of kstrndup and DM logging macros in DM's early
   init code.

 - Fix DM log-writes target's handling of super block sectors so updates
   are made in order through use of completion.

 - Fix DM core's argument splitting code to avoid undefined behaviour
   reported as a side-effect of UBSAN analysis on ppc64le.

 - Fix DM verity target to limit the amount of error messages that can
   result from a corrupt block being found.

* tag 'for-5.2/dm-fixes-2' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm verity: use message limit for data block corruption message
  dm table: don't copy from a NULL pointer in realloc_argv()
  dm log writes: make sure super sector log updates are written in order
  dm init: remove trailing newline from calls to DMERR() and DMINFO()
  dm init: fix incorrect uses of kstrndup()
parents 7a702b4e 2eba4e64
...@@ -140,8 +140,8 @@ static char __init *dm_parse_table_entry(struct dm_device *dev, char *str) ...@@ -140,8 +140,8 @@ static char __init *dm_parse_table_entry(struct dm_device *dev, char *str)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
/* target_args */ /* target_args */
dev->target_args_array[n] = kstrndup(field[3], GFP_KERNEL, dev->target_args_array[n] = kstrndup(field[3], DM_MAX_STR_SIZE,
DM_MAX_STR_SIZE); GFP_KERNEL);
if (!dev->target_args_array[n]) if (!dev->target_args_array[n])
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -272,10 +272,10 @@ static int __init dm_init_init(void) ...@@ -272,10 +272,10 @@ static int __init dm_init_init(void)
return 0; return 0;
if (strlen(create) >= DM_MAX_STR_SIZE) { if (strlen(create) >= DM_MAX_STR_SIZE) {
DMERR("Argument is too big. Limit is %d\n", DM_MAX_STR_SIZE); DMERR("Argument is too big. Limit is %d", DM_MAX_STR_SIZE);
return -EINVAL; return -EINVAL;
} }
str = kstrndup(create, GFP_KERNEL, DM_MAX_STR_SIZE); str = kstrndup(create, DM_MAX_STR_SIZE, GFP_KERNEL);
if (!str) if (!str)
return -ENOMEM; return -ENOMEM;
...@@ -283,7 +283,7 @@ static int __init dm_init_init(void) ...@@ -283,7 +283,7 @@ static int __init dm_init_init(void)
if (r) if (r)
goto out; goto out;
DMINFO("waiting for all devices to be available before creating mapped devices\n"); DMINFO("waiting for all devices to be available before creating mapped devices");
wait_for_device_probe(); wait_for_device_probe();
list_for_each_entry(dev, &devices, list) { list_for_each_entry(dev, &devices, list) {
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#define WRITE_LOG_VERSION 1ULL #define WRITE_LOG_VERSION 1ULL
#define WRITE_LOG_MAGIC 0x6a736677736872ULL #define WRITE_LOG_MAGIC 0x6a736677736872ULL
#define WRITE_LOG_SUPER_SECTOR 0
/* /*
* The disk format for this is braindead simple. * The disk format for this is braindead simple.
...@@ -115,6 +116,7 @@ struct log_writes_c { ...@@ -115,6 +116,7 @@ struct log_writes_c {
struct list_head logging_blocks; struct list_head logging_blocks;
wait_queue_head_t wait; wait_queue_head_t wait;
struct task_struct *log_kthread; struct task_struct *log_kthread;
struct completion super_done;
}; };
struct pending_block { struct pending_block {
...@@ -180,6 +182,14 @@ static void log_end_io(struct bio *bio) ...@@ -180,6 +182,14 @@ static void log_end_io(struct bio *bio)
bio_put(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 * Meant to be called if there is an error, it will free all the pages
* associated with the block. * associated with the block.
...@@ -215,7 +225,8 @@ static int write_metadata(struct log_writes_c *lc, void *entry, ...@@ -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_size = 0;
bio->bi_iter.bi_sector = sector; bio->bi_iter.bi_sector = sector;
bio_set_dev(bio, lc->logdev->bdev); 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->bi_private = lc;
bio_set_op_attrs(bio, REQ_OP_WRITE, 0); bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
...@@ -418,11 +429,18 @@ static int log_super(struct log_writes_c *lc) ...@@ -418,11 +429,18 @@ static int log_super(struct log_writes_c *lc)
super.nr_entries = cpu_to_le64(lc->logged_entries); super.nr_entries = cpu_to_le64(lc->logged_entries);
super.sectorsize = cpu_to_le32(lc->sectorsize); 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"); DMERR("Couldn't write super");
return -1; 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; return 0;
} }
...@@ -531,6 +549,7 @@ static int log_writes_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -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->unflushed_blocks);
INIT_LIST_HEAD(&lc->logging_blocks); INIT_LIST_HEAD(&lc->logging_blocks);
init_waitqueue_head(&lc->wait); init_waitqueue_head(&lc->wait);
init_completion(&lc->super_done);
atomic_set(&lc->io_blocks, 0); atomic_set(&lc->io_blocks, 0);
atomic_set(&lc->pending_blocks, 0); atomic_set(&lc->pending_blocks, 0);
......
...@@ -561,7 +561,7 @@ static char **realloc_argv(unsigned *size, char **old_argv) ...@@ -561,7 +561,7 @@ static char **realloc_argv(unsigned *size, char **old_argv)
gfp = GFP_NOIO; gfp = GFP_NOIO;
} }
argv = kmalloc_array(new_size, sizeof(*argv), gfp); argv = kmalloc_array(new_size, sizeof(*argv), gfp);
if (argv) { if (argv && old_argv) {
memcpy(argv, old_argv, *size * sizeof(*argv)); memcpy(argv, old_argv, *size * sizeof(*argv));
*size = new_size; *size = new_size;
} }
......
...@@ -235,8 +235,8 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type, ...@@ -235,8 +235,8 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
BUG(); BUG();
} }
DMERR("%s: %s block %llu is corrupted", v->data_dev->name, type_str, DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,
block); type_str, block);
if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS) if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
DMERR("%s: reached maximum errors", v->data_dev->name); DMERR("%s: reached maximum errors", v->data_dev->name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment