From d2e45eace866ad229f3c27aeff1f69360a8f0ead Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 14 Aug 2003 10:06:18 -0700 Subject: [PATCH] [PATCH] Fix raid "bio too big" failures From: Neil Brown Fix "bio too big" problem with md Whenever a device is attached to an md device, we make sure the sector limits of the md device do not exceed those of the added device. --- drivers/block/ll_rw_blk.c | 15 +++++++++++++++ drivers/md/linear.c | 2 ++ drivers/md/multipath.c | 4 ++++ drivers/md/raid0.c | 3 ++- drivers/md/raid1.c | 4 ++++ include/linux/blkdev.h | 1 + 6 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 0764cd36b5790..d7b2ede867604 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -369,6 +369,20 @@ void blk_queue_hardsect_size(request_queue_t *q, unsigned short size) q->hardsect_size = size; } +/** + * blk_queue_stack_limits - inherit underlying queue limits for stacked drivers + * @t: the stacking driver (top) + * @b: the underlying device (bottom) + **/ +void blk_queue_stack_limits(request_queue_t *t, request_queue_t *b) +{ + t->max_sectors = min(t->max_sectors,b->max_sectors); + t->max_phys_segments = min(t->max_phys_segments,b->max_phys_segments); + t->max_hw_segments = min(t->max_hw_segments,b->max_hw_segments); + t->max_segment_size = min(t->max_segment_size,b->max_segment_size); + t->hardsect_size = max(t->hardsect_size,b->hardsect_size); +} + /** * blk_queue_segment_boundary - set boundary rules for segment merging * @q: the request queue for the device @@ -2804,6 +2818,7 @@ EXPORT_SYMBOL(blk_queue_max_phys_segments); EXPORT_SYMBOL(blk_queue_max_hw_segments); EXPORT_SYMBOL(blk_queue_max_segment_size); EXPORT_SYMBOL(blk_queue_hardsect_size); +EXPORT_SYMBOL(blk_queue_stack_limits); EXPORT_SYMBOL(blk_queue_segment_boundary); EXPORT_SYMBOL(blk_queue_dma_alignment); EXPORT_SYMBOL(blk_rq_map_sg); diff --git a/drivers/md/linear.c b/drivers/md/linear.c index afc5b3705a8c8..9da446a143ec5 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -114,6 +114,8 @@ static int linear_run (mddev_t *mddev) } disk->rdev = rdev; + blk_queue_stack_limits(mddev->queue, + rdev->bdev->bd_disk->queue); disk->size = rdev->size; mddev->array_size += rdev->size; diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 8d04138441015..4d19a4bd68089 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -272,6 +272,8 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) for (path=0; pathraid_disks; path++) if ((p=conf->multipaths+path)->rdev == NULL) { p->rdev = rdev; + blk_queue_stack_limits(mddev->queue, + rdev->bdev->bd_disk->queue); conf->working_disks++; rdev->raid_disk = path; rdev->in_sync = 1; @@ -409,6 +411,8 @@ static int multipath_run (mddev_t *mddev) disk = conf->multipaths + disk_idx; disk->rdev = rdev; + blk_queue_stack_limits(mddev->queue, + rdev->bdev->bd_disk->queue); if (!rdev->faulty) conf->working_disks++; } diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index a3a768082de2f..26b23d06e3d54 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -113,6 +113,8 @@ static int create_strip_zones (mddev_t *mddev) goto abort; } zone->dev[j] = rdev1; + blk_queue_stack_limits(mddev->queue, + rdev1->bdev->bd_disk->queue); if (!smallest || (rdev1->size size)) smallest = rdev1; cnt++; @@ -293,7 +295,6 @@ static int raid0_run (mddev_t *mddev) conf->hash_spacing++; } - blk_queue_max_sectors(mddev->queue, mddev->chunk_size >> 9); blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec); return 0; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 56e6030ec2f65..cb7acbfb87cf7 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -678,6 +678,8 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) for (mirror=0; mirror < mddev->raid_disks; mirror++) if ( !(p=conf->mirrors+mirror)->rdev) { p->rdev = rdev; + blk_queue_stack_limits(mddev->queue, + rdev->bdev->bd_disk->queue); p->head_position = 0; rdev->raid_disk = mirror; found = 1; @@ -1076,6 +1078,8 @@ static int run(mddev_t *mddev) disk = conf->mirrors + disk_idx; disk->rdev = rdev; + blk_queue_stack_limits(mddev->queue, + rdev->bdev->bd_disk->queue); disk->head_position = 0; if (!rdev->faulty && rdev->in_sync) conf->working_disks++; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2f272b79d9e04..a5c8772b64639 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -547,6 +547,7 @@ extern void blk_queue_max_phys_segments(request_queue_t *, unsigned short); extern void blk_queue_max_hw_segments(request_queue_t *, unsigned short); extern void blk_queue_max_segment_size(request_queue_t *, unsigned int); extern void blk_queue_hardsect_size(request_queue_t *, unsigned short); +extern void blk_queue_stack_limits(request_queue_t *t, request_queue_t *b); extern void blk_queue_segment_boundary(request_queue_t *, unsigned long); extern void blk_queue_prep_rq(request_queue_t *, prep_rq_fn *pfn); extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *); -- 2.53.0