From 3ec67ac1a399d576d48b0736096bcce7721fe3cf Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 9 Sep 2005 16:23:40 -0700 Subject: [PATCH] md: fix minor error in raid10 read-balancing calculation. 'this_sector' is a virtual (array) address while 'head_position' is a physical (device) address, so substraction doesn't make any sense. devs[slot].addr should be used instead of this_sector. However, this patch doesn't make much practical different to the read balancing due to the effects of later code. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/raid10.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/md/raid10.c') diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 62ebb1bc72b..7239079203e 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -538,7 +538,8 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio) } - current_distance = abs(this_sector - conf->mirrors[disk].head_position); + current_distance = abs(r10_bio->devs[slot].addr - + conf->mirrors[disk].head_position); /* Find the disk whose head is closest */ -- cgit v1.2.3-70-g09d2 From e5dcdd80a60627371f40797426273048630dc8ca Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 9 Sep 2005 16:23:41 -0700 Subject: [PATCH] md: fail IO request to md that require a barrier. md does not yet support BIO_RW_BARRIER, so be honest about it and fail (-EOPNOTSUPP) any such requests. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/linear.c | 5 +++++ drivers/md/multipath.c | 5 +++++ drivers/md/raid0.c | 5 +++++ drivers/md/raid1.c | 4 ++++ drivers/md/raid10.c | 5 +++++ drivers/md/raid5.c | 5 +++++ drivers/md/raid6main.c | 5 +++++ 7 files changed, 34 insertions(+) (limited to 'drivers/md/raid10.c') diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 8d740013d74..4991ba54336 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -238,6 +238,11 @@ static int linear_make_request (request_queue_t *q, struct bio *bio) dev_info_t *tmp_dev; sector_t block; + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } + if (bio_data_dir(bio)==WRITE) { disk_stat_inc(mddev->gendisk, writes); disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bio)); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 2d2ca7fa026..286342375fb 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -169,6 +169,11 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio) struct multipath_bh * mp_bh; struct multipath_info *multipath; + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } + mp_bh = mempool_alloc(conf->pool, GFP_NOIO); mp_bh->master_bio = bio; diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 2120710172c..f6757259ce7 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -404,6 +404,11 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio) unsigned long chunk; sector_t block, rsect; + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } + if (bio_data_dir(bio)==WRITE) { disk_stat_inc(mddev->gendisk, writes); disk_stat_add(mddev->gendisk, write_sectors, bio_sectors(bio)); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 51d9645ed09..ace41c571ae 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -555,6 +555,10 @@ static int make_request(request_queue_t *q, struct bio * bio) unsigned long flags; struct bio_list bl; + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } /* * Register the new request and wait if the reconstruction diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 7239079203e..5e0b333793d 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -669,6 +669,11 @@ static int make_request(request_queue_t *q, struct bio * bio) int i; int chunk_sects = conf->chunk_mask + 1; + if (unlikely(bio_barrier(bio))) { + bio_endio(bio, bio->bi_size, -EOPNOTSUPP); + return 0; + } + /* If this request crosses a chunk boundary, we need to * split it. This will only happen for 1 PAGE (or less) requests. */ diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 43f231a467d..ed859e08d60 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1411,6 +1411,11 @@ static int make_request (request_queue_t *q, struct bio * bi) sector_t logical_sector, last_sector; struct stripe_head *sh; + if (unlikely(bio_barrier(bi))) { + bio_endio(bi, bi->bi_size, -EOPNOTSUPP); + return 0; + } + md_write_start(mddev, bi); if (bio_data_dir(bi)==WRITE) { diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 495dee1d1e8..09cb7272c09 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -1570,6 +1570,11 @@ static int make_request (request_queue_t *q, struct bio * bi) sector_t logical_sector, last_sector; struct stripe_head *sh; + if (unlikely(bio_barrier(bi))) { + bio_endio(bi, bi->bi_size, -EOPNOTSUPP); + return 0; + } + md_write_start(mddev, bi); if (bio_data_dir(bi)==WRITE) { -- cgit v1.2.3-70-g09d2 From 6d508242b231cb6e6803faaef54456abe846edb8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 9 Sep 2005 16:24:03 -0700 Subject: [PATCH] md: fix raid10 assembly when too many devices are missing If you try to assemble an array with too many missing devices, raid10 will now reject the attempt, instead of allowing it. Also check when hot-adding a drive and refuse the hot-add if the array is beyond hope. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/raid10.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'drivers/md/raid10.c') diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 5e0b333793d..834bf0f8622 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -906,6 +906,27 @@ static void close_sync(conf_t *conf) conf->r10buf_pool = NULL; } +/* check if there are enough drives for + * every block to appear on atleast one + */ +static int enough(conf_t *conf) +{ + int first = 0; + + do { + int n = conf->copies; + int cnt = 0; + while (n--) { + if (conf->mirrors[first].rdev) + cnt++; + first = (first+1) % conf->raid_disks; + } + if (cnt == 0) + return 0; + } while (first != 0); + return 1; +} + static int raid10_spare_active(mddev_t *mddev) { int i; @@ -944,6 +965,8 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) * very different from resync */ return 0; + if (!enough(conf)) + return 0; for (mirror=0; mirror < mddev->raid_disks; mirror++) if ( !(p=conf->mirrors+mirror)->rdev) { @@ -1684,9 +1707,10 @@ static int run(mddev_t *mddev) init_waitqueue_head(&conf->wait_idle); init_waitqueue_head(&conf->wait_resume); - if (!conf->working_disks) { - printk(KERN_ERR "raid10: no operational mirrors for %s\n", - mdname(mddev)); + /* need to check that every block has at least one working mirror */ + if (!enough(conf)) { + printk(KERN_ERR "raid10: not enough operational mirrors for %s\n", + mdname(mddev)); goto out_free_conf; } -- cgit v1.2.3-70-g09d2 From 87fc767b832ef5a681a0ff9d203c3289bc3be2bf Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 9 Sep 2005 16:24:04 -0700 Subject: [PATCH] md: fix BUG when raid10 rebuilds without enough drives This shouldn't be a BUG. We should cope. Signed-off-by: Neil Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/raid10.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/md/raid10.c') diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 834bf0f8622..5bd1e9ec899 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1474,7 +1474,13 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i } } if (j == conf->copies) { - BUG(); + /* Cannot recover, so abort the recovery */ + put_buf(r10_bio); + r10_bio = rb2; + if (!test_and_set_bit(MD_RECOVERY_ERR, &mddev->recovery)) + printk(KERN_INFO "raid10: %s: insufficient working devices for recovery.\n", + mdname(mddev)); + break; } } if (biolist == NULL) { -- cgit v1.2.3-70-g09d2