From: Neil Brown This patch compiles and looks ok, but I haven't tested it (but then I don't get bio-too-big errors). 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. mighth) we'll never know.... 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 -puN drivers/block/ll_rw_blk.c~bio-too-big-fix drivers/block/ll_rw_blk.c --- 25/drivers/block/ll_rw_blk.c~bio-too-big-fix 2003-08-01 01:57:44.000000000 -0700 +++ 25-akpm/drivers/block/ll_rw_blk.c 2003-08-01 01:57:44.000000000 -0700 @@ -370,6 +370,20 @@ void blk_queue_hardsect_size(request_que } /** + * 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 * @mask: the memory boundary mask @@ -2764,6 +2778,7 @@ EXPORT_SYMBOL(blk_queue_max_phys_segment 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 -puN drivers/md/linear.c~bio-too-big-fix drivers/md/linear.c --- 25/drivers/md/linear.c~bio-too-big-fix 2003-08-01 01:57:44.000000000 -0700 +++ 25-akpm/drivers/md/linear.c 2003-08-01 01:57:44.000000000 -0700 @@ -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 -puN drivers/md/multipath.c~bio-too-big-fix drivers/md/multipath.c --- 25/drivers/md/multipath.c~bio-too-big-fix 2003-08-01 01:57:44.000000000 -0700 +++ 25-akpm/drivers/md/multipath.c 2003-08-01 01:57:44.000000000 -0700 @@ -272,6 +272,8 @@ static int multipath_add_disk(mddev_t *m 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 -puN drivers/md/raid0.c~bio-too-big-fix drivers/md/raid0.c --- 25/drivers/md/raid0.c~bio-too-big-fix 2003-08-01 01:57:44.000000000 -0700 +++ 25-akpm/drivers/md/raid0.c 2003-08-01 01:57:44.000000000 -0700 @@ -113,6 +113,8 @@ static int create_strip_zones (mddev_t * 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 -puN drivers/md/raid1.c~bio-too-big-fix drivers/md/raid1.c --- 25/drivers/md/raid1.c~bio-too-big-fix 2003-08-01 01:57:44.000000000 -0700 +++ 25-akpm/drivers/md/raid1.c 2003-08-01 01:57:44.000000000 -0700 @@ -678,6 +678,8 @@ static int raid1_add_disk(mddev_t *mddev 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 -puN include/linux/blkdev.h~bio-too-big-fix include/linux/blkdev.h --- 25/include/linux/blkdev.h~bio-too-big-fix 2003-08-01 01:57:44.000000000 -0700 +++ 25-akpm/include/linux/blkdev.h 2003-08-01 01:57:44.000000000 -0700 @@ -549,6 +549,7 @@ extern void blk_queue_max_phys_segments( 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 *); _