diff options
author | Mike Snitzer <snitzer@redhat.com> | 2012-12-21 15:23:37 -0500 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2012-12-21 15:23:37 -0500 |
commit | 23508a96cd2e857d57044a2ed7d305f2d9daf441 (patch) | |
tree | 149ead46c45a0fdd159fb32a6bfb6439eae3d652 | |
parent | d54eaa5a0fde0a202e4e91f200f818edcef15bee (diff) |
dm: add WRITE SAME support
WRITE SAME bios have a payload that contain a single page. When
cloning WRITE SAME bios DM has no need to modify the bi_io_vec
attributes (and doing so would be detrimental). DM need only alter the
start and end of the WRITE SAME bio accordingly.
Rather than duplicate __clone_and_map_discard, factor out a common
function that is also used by __clone_and_map_write_same.
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
-rw-r--r-- | drivers/md/dm.c | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 77e6eff41cae..5401cdce0fc5 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -1174,7 +1174,28 @@ static void __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti) | |||
1174 | ci->sector_count = 0; | 1174 | ci->sector_count = 0; |
1175 | } | 1175 | } |
1176 | 1176 | ||
1177 | static int __clone_and_map_discard(struct clone_info *ci) | 1177 | typedef unsigned (*get_num_requests_fn)(struct dm_target *ti); |
1178 | |||
1179 | static unsigned get_num_discard_requests(struct dm_target *ti) | ||
1180 | { | ||
1181 | return ti->num_discard_requests; | ||
1182 | } | ||
1183 | |||
1184 | static unsigned get_num_write_same_requests(struct dm_target *ti) | ||
1185 | { | ||
1186 | return ti->num_write_same_requests; | ||
1187 | } | ||
1188 | |||
1189 | typedef bool (*is_split_required_fn)(struct dm_target *ti); | ||
1190 | |||
1191 | static bool is_split_required_for_discard(struct dm_target *ti) | ||
1192 | { | ||
1193 | return ti->split_discard_requests; | ||
1194 | } | ||
1195 | |||
1196 | static int __clone_and_map_changing_extent_only(struct clone_info *ci, | ||
1197 | get_num_requests_fn get_num_requests, | ||
1198 | is_split_required_fn is_split_required) | ||
1178 | { | 1199 | { |
1179 | struct dm_target *ti; | 1200 | struct dm_target *ti; |
1180 | sector_t len; | 1201 | sector_t len; |
@@ -1185,15 +1206,15 @@ static int __clone_and_map_discard(struct clone_info *ci) | |||
1185 | return -EIO; | 1206 | return -EIO; |
1186 | 1207 | ||
1187 | /* | 1208 | /* |
1188 | * Even though the device advertised discard support, | 1209 | * Even though the device advertised support for this type of |
1189 | * that does not mean every target supports it, and | 1210 | * request, that does not mean every target supports it, and |
1190 | * reconfiguration might also have changed that since the | 1211 | * reconfiguration might also have changed that since the |
1191 | * check was performed. | 1212 | * check was performed. |
1192 | */ | 1213 | */ |
1193 | if (!ti->num_discard_requests) | 1214 | if (!get_num_requests || !get_num_requests(ti)) |
1194 | return -EOPNOTSUPP; | 1215 | return -EOPNOTSUPP; |
1195 | 1216 | ||
1196 | if (!ti->split_discard_requests) | 1217 | if (is_split_required && !is_split_required(ti)) |
1197 | len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti)); | 1218 | len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti)); |
1198 | else | 1219 | else |
1199 | len = min(ci->sector_count, max_io_len(ci->sector, ti)); | 1220 | len = min(ci->sector_count, max_io_len(ci->sector, ti)); |
@@ -1206,6 +1227,17 @@ static int __clone_and_map_discard(struct clone_info *ci) | |||
1206 | return 0; | 1227 | return 0; |
1207 | } | 1228 | } |
1208 | 1229 | ||
1230 | static int __clone_and_map_discard(struct clone_info *ci) | ||
1231 | { | ||
1232 | return __clone_and_map_changing_extent_only(ci, get_num_discard_requests, | ||
1233 | is_split_required_for_discard); | ||
1234 | } | ||
1235 | |||
1236 | static int __clone_and_map_write_same(struct clone_info *ci) | ||
1237 | { | ||
1238 | return __clone_and_map_changing_extent_only(ci, get_num_write_same_requests, NULL); | ||
1239 | } | ||
1240 | |||
1209 | static int __clone_and_map(struct clone_info *ci) | 1241 | static int __clone_and_map(struct clone_info *ci) |
1210 | { | 1242 | { |
1211 | struct bio *bio = ci->bio; | 1243 | struct bio *bio = ci->bio; |
@@ -1215,6 +1247,8 @@ static int __clone_and_map(struct clone_info *ci) | |||
1215 | 1247 | ||
1216 | if (unlikely(bio->bi_rw & REQ_DISCARD)) | 1248 | if (unlikely(bio->bi_rw & REQ_DISCARD)) |
1217 | return __clone_and_map_discard(ci); | 1249 | return __clone_and_map_discard(ci); |
1250 | else if (unlikely(bio->bi_rw & REQ_WRITE_SAME)) | ||
1251 | return __clone_and_map_write_same(ci); | ||
1218 | 1252 | ||
1219 | ti = dm_table_find_target(ci->map, ci->sector); | 1253 | ti = dm_table_find_target(ci->map, ci->sector); |
1220 | if (!dm_target_is_valid(ti)) | 1254 | if (!dm_target_is_valid(ti)) |