In dm-table.c::dm_create_table(), the size of the array allocated for t->highs *must* be a multiple of KEYS_PER_NODE. If not, dm-table.c::high() may index off the end of an array, causing fields in t->index to be initialized incorrectly, which will eventually lead to I/O errors or segfaults due to bad return pointers from dm_table_find_target(). To verify this, use dmsetup to create exactly 12 small linear devices, each 10 sectors long. Then create another device that concatenates all 12 of these devices together. Do a simple dd to this device and it will either cause I/O errors, or possibly segfault the kernel. Here are the mapping files I used for my test: Filename Mapping child00 0 10 linear /dev/hdd9 0 child01 0 10 linear /dev/hdd9 10 child02 0 10 linear /dev/hdd9 20 child03 0 10 linear /dev/hdd9 30 child04 0 10 linear /dev/hdd9 40 child05 0 10 linear /dev/hdd9 50 child06 0 10 linear /dev/hdd9 60 child07 0 10 linear /dev/hdd9 70 child08 0 10 linear /dev/hdd9 80 child09 0 10 linear /dev/hdd9 90 child10 0 10 linear /dev/hdd9 100 child11 0 10 linear /dev/hdd9 110 link 0 10 linear /dev/mapper/child00 0 10 10 linear /dev/mapper/child01 0 20 10 linear /dev/mapper/child02 0 30 10 linear /dev/mapper/child03 0 40 10 linear /dev/mapper/child04 0 50 10 linear /dev/mapper/child05 0 60 10 linear /dev/mapper/child06 0 70 10 linear /dev/mapper/child07 0 80 10 linear /dev/mapper/child08 0 90 10 linear /dev/mapper/child09 0 100 10 linear /dev/mapper/child10 0 110 10 linear /dev/mapper/child11 0 dd if=/dev/zero of=/dev/mapper/link bs=512 This command fails at sector 80 on my machine. The test requires exactly 12 or 13 devices in the "link" device. Here are two patches to fix the bug. The first is against device-mapper-1.00.05, and the second is against Joe's 2.4.23-pre7-dm3 patchset (which have different versions of dm_table_create). -- Kevin Corry kevcorry@xxxxxxxxxx http://evms.sourceforge.net/
--- a/drivers/md/dm-table.c 1 Oct 2003 21:48:54 -0000 +++ b/drivers/md/dm-table.c 24 Oct 2003 17:20:08 -0000 @@ -162,6 +162,8 @@ if (!num_targets) num_targets = KEYS_PER_NODE; + num_targets = dm_round_up(num_targets, KEYS_PER_NODE); + if (alloc_targets(t, num_targets)) { kfree(t); t = NULL;
--- a/drivers/md/dm-table.c 2003-10-24 13:21:29.000000000 -0500 +++ b/drivers/md/dm-table.c 2003-10-24 13:31:55.000000000 -0500 @@ -123,6 +123,7 @@ INIT_LIST_HEAD(&t->devices); atomic_set(&t->holders, 1); + num_targets = dm_round_up(num_targets, KEYS_PER_NODE); /* allocate both the target array and offset array at once */ t->highs = (sector_t *) vcalloc(sizeof(struct dm_target) +