aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2013-07-17 01:19:29 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-04 04:50:54 -0400
commit8afb90da9f16abc5e577318544419bfcf3565391 (patch)
tree1ae562b8f0ea6ca10fe3db9264a004e716d778e9
parent1d83ab8548ff19bad94dcae62ba13ea476974e7f (diff)
md/raid1: fix bio handling problems in process_checks()
commit 30bc9b53878a9921b02e3b5bc4283ac1c6de102a upstream. Recent change to use bio_copy_data() in raid1 when repairing an array is faulty. The underlying may have changed the bio in various ways using bio_advance and these need to be undone not just for the 'sbio' which is being copied to, but also the 'pbio' (primary) which is being copied from. So perform the reset on all bios that were read from and do it early. This also ensure that the sbio->bi_io_vec[j].bv_len passed to memcmp is correct. This fixes a crash during a 'check' of a RAID1 array. The crash was introduced in 3.10 so this is suitable for 3.10-stable. Reported-by: Joe Lawrence <joe.lawrence@stratus.com> Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/md/raid1.c53
1 files changed, 30 insertions, 23 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 6e17f8181c4b..6f4824426e86 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1848,6 +1848,36 @@ static int process_checks(struct r1bio *r1_bio)
1848 int i; 1848 int i;
1849 int vcnt; 1849 int vcnt;
1850 1850
1851 /* Fix variable parts of all bios */
1852 vcnt = (r1_bio->sectors + PAGE_SIZE / 512 - 1) >> (PAGE_SHIFT - 9);
1853 for (i = 0; i < conf->raid_disks * 2; i++) {
1854 int j;
1855 int size;
1856 struct bio *b = r1_bio->bios[i];
1857 if (b->bi_end_io != end_sync_read)
1858 continue;
1859 /* fixup the bio for reuse */
1860 bio_reset(b);
1861 b->bi_vcnt = vcnt;
1862 b->bi_size = r1_bio->sectors << 9;
1863 b->bi_sector = r1_bio->sector +
1864 conf->mirrors[i].rdev->data_offset;
1865 b->bi_bdev = conf->mirrors[i].rdev->bdev;
1866 b->bi_end_io = end_sync_read;
1867 b->bi_private = r1_bio;
1868
1869 size = b->bi_size;
1870 for (j = 0; j < vcnt ; j++) {
1871 struct bio_vec *bi;
1872 bi = &b->bi_io_vec[j];
1873 bi->bv_offset = 0;
1874 if (size > PAGE_SIZE)
1875 bi->bv_len = PAGE_SIZE;
1876 else
1877 bi->bv_len = size;
1878 size -= PAGE_SIZE;
1879 }
1880 }
1851 for (primary = 0; primary < conf->raid_disks * 2; primary++) 1881 for (primary = 0; primary < conf->raid_disks * 2; primary++)
1852 if (r1_bio->bios[primary]->bi_end_io == end_sync_read && 1882 if (r1_bio->bios[primary]->bi_end_io == end_sync_read &&
1853 test_bit(BIO_UPTODATE, &r1_bio->bios[primary]->bi_flags)) { 1883 test_bit(BIO_UPTODATE, &r1_bio->bios[primary]->bi_flags)) {
@@ -1856,12 +1886,10 @@ static int process_checks(struct r1bio *r1_bio)
1856 break; 1886 break;
1857 } 1887 }
1858 r1_bio->read_disk = primary; 1888 r1_bio->read_disk = primary;
1859 vcnt = (r1_bio->sectors + PAGE_SIZE / 512 - 1) >> (PAGE_SHIFT - 9);
1860 for (i = 0; i < conf->raid_disks * 2; i++) { 1889 for (i = 0; i < conf->raid_disks * 2; i++) {
1861 int j; 1890 int j;
1862 struct bio *pbio = r1_bio->bios[primary]; 1891 struct bio *pbio = r1_bio->bios[primary];
1863 struct bio *sbio = r1_bio->bios[i]; 1892 struct bio *sbio = r1_bio->bios[i];
1864 int size;
1865 1893
1866 if (sbio->bi_end_io != end_sync_read) 1894 if (sbio->bi_end_io != end_sync_read)
1867 continue; 1895 continue;
@@ -1887,27 +1915,6 @@ static int process_checks(struct r1bio *r1_bio)
1887 rdev_dec_pending(conf->mirrors[i].rdev, mddev); 1915 rdev_dec_pending(conf->mirrors[i].rdev, mddev);
1888 continue; 1916 continue;
1889 } 1917 }
1890 /* fixup the bio for reuse */
1891 bio_reset(sbio);
1892 sbio->bi_vcnt = vcnt;
1893 sbio->bi_size = r1_bio->sectors << 9;
1894 sbio->bi_sector = r1_bio->sector +
1895 conf->mirrors[i].rdev->data_offset;
1896 sbio->bi_bdev = conf->mirrors[i].rdev->bdev;
1897 sbio->bi_end_io = end_sync_read;
1898 sbio->bi_private = r1_bio;
1899
1900 size = sbio->bi_size;
1901 for (j = 0; j < vcnt ; j++) {
1902 struct bio_vec *bi;
1903 bi = &sbio->bi_io_vec[j];
1904 bi->bv_offset = 0;
1905 if (size > PAGE_SIZE)
1906 bi->bv_len = PAGE_SIZE;
1907 else
1908 bi->bv_len = size;
1909 size -= PAGE_SIZE;
1910 }
1911 1918
1912 bio_copy_data(sbio, pbio); 1919 bio_copy_data(sbio, pbio);
1913 } 1920 }