aboutsummaryrefslogtreecommitdiffstats
path: root/debian/patches/bugfix/all/dm-Deal-with-merge_bvec_fn-in-component-devices-bett.patch
blob: aa8c0eacc895de7c49390c107abae843eb6d156f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
From: Ben Hutchings <ben@decadent.org.uk>
Date: Sun, 28 Nov 2010 23:46:46 +0000
Subject: [PATCH] dm: Deal with merge_bvec_fn in component devices better

This is analogous to commit 627a2d3c29427637f4c5d31ccc7fcbd8d312cd71,
which does the same for md-devices at the top of the stack.  The
following explanation is taken from that commit.  Thanks to Neil Brown
<neilb@suse.de> for the advice.

If a component device has a merge_bvec_fn then as we never call it
we must ensure we never need to.  Currently this is done by setting
max_sector to 1 PAGE, however this does not stop a bio being created
with several sub-page iovecs that would violate the merge_bvec_fn.

So instead set max_segments to 1 and set the segment boundary to the
same as a page boundary to ensure there is only ever one single-page
segment of IO requested at a time.

This can particularly be an issue when 'xen' is used as it is
known to submit multiple small buffers in a single bio.

Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -511,14 +511,15 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
 		       (unsigned long long) start << SECTOR_SHIFT);
 
 	/*
-	 * Check if merge fn is supported.
-	 * If not we'll force DM to use PAGE_SIZE or
-	 * smaller I/O, just to be safe.
+	 * If we don't call merge_bvec_fn, we must never risk
+	 * violating it, so limit max_phys_segments to 1 lying within
+	 * a single page.
 	 */
+	if (q->merge_bvec_fn && !ti->type->merge) {
+		limits->max_segments = 1;
+		limits->seg_boundary_mask = PAGE_CACHE_SIZE - 1;
+	}
 
-	if (q->merge_bvec_fn && !ti->type->merge)
-		blk_limits_max_hw_sectors(limits,
-					  (unsigned int) (PAGE_SIZE >> 9));
 	return 0;
 }
 EXPORT_SYMBOL_GPL(dm_set_device_limits);