dm: table detect io beyond device

This patch fixes a panic on shrinking a DM device if there is
outstanding I/O to the part of the device that is being removed.
(Normally this doesn't happen - a filesystem would be resized first,
for example.)

The bug is that __clone_and_map() assumes dm_table_find_target()
always returns a valid pointer. It may fail if a bio arrives from the
block layer but its target sector is no longer included in the DM
btree.

This patch appends an empty entry to table->targets[] which will
be returned by a lookup beyond the end of the device.

After calling dm_table_find_target(), __clone_and_map() and target_message()
check for this condition using
dm_target_is_valid().

Sample test script to trigger oops:

authored by Jun'ichi Nomura and committed by Alasdair G Kergon 512875bd fbdcf18d

+32 -14
+3 -7
drivers/md/dm-ioctl.c
··· 1250 1250 if (!table) 1251 1251 goto out_argv; 1252 1252 1253 - if (tmsg->sector >= dm_table_get_size(table)) { 1253 + ti = dm_table_find_target(table, tmsg->sector); 1254 + if (!dm_target_is_valid(ti)) { 1254 1255 DMWARN("Target message sector outside device."); 1255 1256 r = -EINVAL; 1256 - goto out_table; 1257 - } 1258 - 1259 - ti = dm_table_find_target(table, tmsg->sector); 1260 - if (ti->type->message) 1257 + } else if (ti->type->message) 1261 1258 r = ti->type->message(ti, argc, argv); 1262 1259 else { 1263 1260 DMWARN("Target type does not support messages"); 1264 1261 r = -EINVAL; 1265 1262 } 1266 1263 1267 - out_table: 1268 1264 dm_table_put(table); 1269 1265 out_argv: 1270 1266 kfree(argv);
+6 -1
drivers/md/dm-table.c
··· 189 189 190 190 /* 191 191 * Allocate both the target array and offset array at once. 192 + * Append an empty entry to catch sectors beyond the end of 193 + * the device. 192 194 */ 193 - n_highs = (sector_t *) dm_vcalloc(num, sizeof(struct dm_target) + 195 + n_highs = (sector_t *) dm_vcalloc(num + 1, sizeof(struct dm_target) + 194 196 sizeof(sector_t)); 195 197 if (!n_highs) 196 198 return -ENOMEM; ··· 869 867 870 868 /* 871 869 * Search the btree for the correct target. 870 + * 871 + * Caller should check returned pointer with dm_target_is_valid() 872 + * to trap I/O beyond end of device. 872 873 */ 873 874 struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector) 874 875 {
+18 -6
drivers/md/dm.c
··· 672 672 return clone; 673 673 } 674 674 675 - static void __clone_and_map(struct clone_info *ci) 675 + static int __clone_and_map(struct clone_info *ci) 676 676 { 677 677 struct bio *clone, *bio = ci->bio; 678 - struct dm_target *ti = dm_table_find_target(ci->map, ci->sector); 679 - sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti); 678 + struct dm_target *ti; 679 + sector_t len = 0, max; 680 680 struct dm_target_io *tio; 681 + 682 + ti = dm_table_find_target(ci->map, ci->sector); 683 + if (!dm_target_is_valid(ti)) 684 + return -EIO; 685 + 686 + max = max_io_len(ci->md, ci->sector, ti); 681 687 682 688 /* 683 689 * Allocate a target io object. ··· 742 736 do { 743 737 if (offset) { 744 738 ti = dm_table_find_target(ci->map, ci->sector); 739 + if (!dm_target_is_valid(ti)) 740 + return -EIO; 741 + 745 742 max = max_io_len(ci->md, ci->sector, ti); 746 743 747 744 tio = alloc_tio(ci->md); ··· 768 759 769 760 ci->idx++; 770 761 } 762 + 763 + return 0; 771 764 } 772 765 773 766 /* ··· 778 767 static int __split_bio(struct mapped_device *md, struct bio *bio) 779 768 { 780 769 struct clone_info ci; 770 + int error = 0; 781 771 782 772 ci.map = dm_get_table(md); 783 773 if (unlikely(!ci.map)) ··· 796 784 ci.idx = bio->bi_idx; 797 785 798 786 start_io_acct(ci.io); 799 - while (ci.sector_count) 800 - __clone_and_map(&ci); 787 + while (ci.sector_count && !error) 788 + error = __clone_and_map(&ci); 801 789 802 790 /* drop the extra reference count */ 803 - dec_pending(ci.io, 0); 791 + dec_pending(ci.io, error); 804 792 dm_table_put(ci.map); 805 793 806 794 return 0;
+5
drivers/md/dm.h
··· 112 112 int dm_table_any_congested(struct dm_table *t, int bdi_bits); 113 113 void dm_table_unplug_all(struct dm_table *t); 114 114 115 + /* 116 + * To check the return value from dm_table_find_target(). 117 + */ 118 + #define dm_target_is_valid(t) ((t)->table) 119 + 115 120 /*----------------------------------------------------------------- 116 121 * A registry of target types. 117 122 *---------------------------------------------------------------*/