+++ /dev/null
-Subject: block: fix setting of max_segment_size and seg_boundary mask
-From: Milan Broz <mbroz@redhat.com>
-Date: Wed Dec 3 12:55:55 2008 +0100:
-Git: 0e435ac26e3f951d83338ed3d4ab7dc0fe0055bc
-
-Fix setting of max_segment_size and seg_boundary mask for stacked md/dm
-devices.
-
-When stacking devices (LVM over MD over SCSI) some of the request queue
-parameters are not set up correctly in some cases by default, namely
-max_segment_size and and seg_boundary mask.
-
-If you create MD device over SCSI, these attributes are zeroed.
-
-Problem become when there is over this mapping next device-mapper mapping
-- queue attributes are set in DM this way:
-
-request_queue max_segment_size seg_boundary_mask
-SCSI 65536 0xffffffff
-MD RAID1 0 0
-LVM 65536 -1 (64bit)
-
-Unfortunately bio_add_page (resp. bio_phys_segments) calculates number of
-physical segments according to these parameters.
-
-During the generic_make_request() is segment cout recalculated and can
-increase bio->bi_phys_segments count over the allowed limit. (After
-bio_clone() in stack operation.)
-
-Thi is specially problem in CCISS driver, where it produce OOPS here
-
- BUG_ON(creq->nr_phys_segments > MAXSGENTRIES);
-
-(MAXSEGENTRIES is 31 by default.)
-
-Sometimes even this command is enough to cause oops:
-
- dd iflag=direct if=/dev/<vg>/<lv> of=/dev/null bs=128000 count=10
-
-This command generates bios with 250 sectors, allocated in 32 4k-pages
-(last page uses only 1024 bytes).
-
-For LVM layer, it allocates bio with 31 segments (still OK for CCISS),
-unfortunatelly on lower layer it is recalculated to 32 segments and this
-violates CCISS restriction and triggers BUG_ON().
-
-The patch tries to fix it by:
-
- * initializing attributes above in queue request constructor
- blk_queue_make_request()
-
- * make sure that blk_queue_stack_limits() inherits setting
-
- (DM uses its own function to set the limits because it
- blk_queue_stack_limits() was introduced later. It should probably switch
- to use generic stack limit function too.)
-
- * sets the default seg_boundary value in one place (blkdev.h)
-
- * use this mask as default in DM (instead of -1, which differs in 64bit)
-
-Bugs related to this:
-https://bugzilla.redhat.com/show_bug.cgi?id=471639
-http://bugzilla.kernel.org/show_bug.cgi?id=8672
-
-Signed-off-by: Milan Broz <mbroz@redhat.com>
-Reviewed-by: Alasdair G Kergon <agk@redhat.com>
-Cc: Neil Brown <neilb@suse.de>
-Cc: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-Cc: Tejun Heo <htejun@gmail.com>
-Cc: Mike Miller <mike.miller@hp.com>
-Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-Signed-off-by: Hannes Reinecke <hare@suse.de>
-
----
- block/blk-core.c | 2 +-
- block/blk-settings.c | 4 ++++
- drivers/md/dm-table.c | 2 +-
- include/linux/blkdev.h | 2 ++
- 4 files changed, 8 insertions(+), 2 deletions(-)
-
---- a/block/blk-core.c
-+++ b/block/blk-core.c
-@@ -596,7 +596,7 @@ blk_init_queue_node(request_fn_proc *rfn
- 1 << QUEUE_FLAG_STACKABLE);
- q->queue_lock = lock;
-
-- blk_queue_segment_boundary(q, 0xffffffff);
-+ blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK);
-
- blk_queue_make_request(q, __make_request);
- blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
---- a/block/blk-settings.c
-+++ b/block/blk-settings.c
-@@ -125,6 +125,9 @@ void blk_queue_make_request(struct reque
- q->nr_requests = BLKDEV_MAX_RQ;
- blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
- blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
-+ blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK);
-+ blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
-+
- q->make_request_fn = mfn;
- q->backing_dev_info.ra_pages =
- (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
-@@ -314,6 +317,7 @@ void blk_queue_stack_limits(struct reque
- /* zero is "infinity" */
- t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
- t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
-+ t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, b->seg_boundary_mask);
-
- 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);
---- a/drivers/md/dm-table.c
-+++ b/drivers/md/dm-table.c
-@@ -687,7 +687,7 @@ static void check_for_valid_limits(struc
- if (!rs->max_segment_size)
- rs->max_segment_size = MAX_SEGMENT_SIZE;
- if (!rs->seg_boundary_mask)
-- rs->seg_boundary_mask = -1;
-+ rs->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
- if (!rs->bounce_pfn)
- rs->bounce_pfn = -1;
- }
---- a/include/linux/blkdev.h
-+++ b/include/linux/blkdev.h
-@@ -908,6 +908,8 @@ extern void blk_set_cmd_filter_defaults(
-
- #define MAX_SEGMENT_SIZE 65536
-
-+#define BLK_SEG_BOUNDARY_MASK 0xFFFFFFFFUL
-+
- #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist)
-
- static inline int queue_hardsect_size(struct request_queue *q)