aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@cse.unsw.edu.au>2005-09-09 19:23:53 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-09 19:39:12 -0400
commit0002b2718dd04da67c21f8a7830de8d95a9b0345 (patch)
treec84f916df71293e0e15643a8a07d9508d1404395
parent773f7834425e83144c95fbbc553ced3c2b74b828 (diff)
[PATCH] md: limit size of sb read/written to appropriate amount
version-1 superblocks are not (normally) 4K long, and can be of variable size. Writing the full 4K can cause corruption (but only in non-default configurations). With this patch the super-block-flavour can choose a size to read, and set a size to write based on what it finds. Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/md/md.c20
-rw-r--r--include/linux/raid/md_k.h1
2 files changed, 16 insertions, 5 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 1be3f2de396b..be7873c61b3c 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -393,7 +393,7 @@ int sync_page_io(struct block_device *bdev, sector_t sector, int size,
393 return ret; 393 return ret;
394} 394}
395 395
396static int read_disk_sb(mdk_rdev_t * rdev) 396static int read_disk_sb(mdk_rdev_t * rdev, int size)
397{ 397{
398 char b[BDEVNAME_SIZE]; 398 char b[BDEVNAME_SIZE];
399 if (!rdev->sb_page) { 399 if (!rdev->sb_page) {
@@ -404,7 +404,7 @@ static int read_disk_sb(mdk_rdev_t * rdev)
404 return 0; 404 return 0;
405 405
406 406
407 if (!sync_page_io(rdev->bdev, rdev->sb_offset<<1, MD_SB_BYTES, rdev->sb_page, READ)) 407 if (!sync_page_io(rdev->bdev, rdev->sb_offset<<1, size, rdev->sb_page, READ))
408 goto fail; 408 goto fail;
409 rdev->sb_loaded = 1; 409 rdev->sb_loaded = 1;
410 return 0; 410 return 0;
@@ -531,7 +531,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
531 sb_offset = calc_dev_sboffset(rdev->bdev); 531 sb_offset = calc_dev_sboffset(rdev->bdev);
532 rdev->sb_offset = sb_offset; 532 rdev->sb_offset = sb_offset;
533 533
534 ret = read_disk_sb(rdev); 534 ret = read_disk_sb(rdev, MD_SB_BYTES);
535 if (ret) return ret; 535 if (ret) return ret;
536 536
537 ret = -EINVAL; 537 ret = -EINVAL;
@@ -564,6 +564,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
564 564
565 rdev->preferred_minor = sb->md_minor; 565 rdev->preferred_minor = sb->md_minor;
566 rdev->data_offset = 0; 566 rdev->data_offset = 0;
567 rdev->sb_size = MD_SB_BYTES;
567 568
568 if (sb->level == LEVEL_MULTIPATH) 569 if (sb->level == LEVEL_MULTIPATH)
569 rdev->desc_nr = -1; 570 rdev->desc_nr = -1;
@@ -837,6 +838,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
837 int ret; 838 int ret;
838 sector_t sb_offset; 839 sector_t sb_offset;
839 char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; 840 char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
841 int bmask;
840 842
841 /* 843 /*
842 * Calculate the position of the superblock. 844 * Calculate the position of the superblock.
@@ -865,7 +867,10 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
865 } 867 }
866 rdev->sb_offset = sb_offset; 868 rdev->sb_offset = sb_offset;
867 869
868 ret = read_disk_sb(rdev); 870 /* superblock is rarely larger than 1K, but it can be larger,
871 * and it is safe to read 4k, so we do that
872 */
873 ret = read_disk_sb(rdev, 4096);
869 if (ret) return ret; 874 if (ret) return ret;
870 875
871 876
@@ -891,6 +896,11 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
891 rdev->preferred_minor = 0xffff; 896 rdev->preferred_minor = 0xffff;
892 rdev->data_offset = le64_to_cpu(sb->data_offset); 897 rdev->data_offset = le64_to_cpu(sb->data_offset);
893 898
899 rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256;
900 bmask = block_size(rdev->bdev)-1;
901 if (rdev->sb_size & bmask)
902 rdev-> sb_size = (rdev->sb_size | bmask)+1;
903
894 if (refdev == 0) 904 if (refdev == 0)
895 return 1; 905 return 1;
896 else { 906 else {
@@ -1375,7 +1385,7 @@ repeat:
1375 dprintk("%s ", bdevname(rdev->bdev,b)); 1385 dprintk("%s ", bdevname(rdev->bdev,b));
1376 if (!rdev->faulty) { 1386 if (!rdev->faulty) {
1377 md_super_write(mddev,rdev, 1387 md_super_write(mddev,rdev,
1378 rdev->sb_offset<<1, MD_SB_BYTES, 1388 rdev->sb_offset<<1, rdev->sb_size,
1379 rdev->sb_page); 1389 rdev->sb_page);
1380 dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", 1390 dprintk(KERN_INFO "(write) %s's sb offset: %llu\n",
1381 bdevname(rdev->bdev,b), 1391 bdevname(rdev->bdev,b),
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index 8042f55dd323..ebce949b1443 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -102,6 +102,7 @@ struct mdk_rdev_s
102 int sb_loaded; 102 int sb_loaded;
103 sector_t data_offset; /* start of data in array */ 103 sector_t data_offset; /* start of data in array */
104 sector_t sb_offset; 104 sector_t sb_offset;
105 int sb_size; /* bytes in the superblock */
105 int preferred_minor; /* autorun support */ 106 int preferred_minor; /* autorun support */
106 107
107 /* A device can be in one of three states based on two flags: 108 /* A device can be in one of three states based on two flags: