diff options
author | Mike Snitzer <snitzer@redhat.com> | 2010-08-11 23:14:24 -0400 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2010-08-11 23:14:24 -0400 |
commit | a79245b3e5669dc203fec63644d988c451fe55d5 (patch) | |
tree | 8814720781708a95ac0bd23bb5232aa5ed9337bd | |
parent | c96053b767d494d7c30e2be68097ac9defa9403f (diff) |
dm: split discard requests on target boundaries
Update __clone_and_map_discard to loop across all targets in a DM
device's table when it processes a discard bio. If a discard crosses a
target boundary it must be split accordingly.
Update __issue_target_requests and __issue_target_request to allow a
cloned discard bio to have a custom start sector and size.
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
-rw-r--r-- | drivers/md/dm.c | 47 |
1 files changed, 23 insertions, 24 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 561313a7dac2..ac384b2a6a33 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -1193,7 +1193,7 @@ static struct dm_target_io *alloc_tio(struct clone_info *ci, | |||
1193 | } | 1193 | } |
1194 | 1194 | ||
1195 | static void __issue_target_request(struct clone_info *ci, struct dm_target *ti, | 1195 | static void __issue_target_request(struct clone_info *ci, struct dm_target *ti, |
1196 | unsigned request_nr) | 1196 | unsigned request_nr, sector_t len) |
1197 | { | 1197 | { |
1198 | struct dm_target_io *tio = alloc_tio(ci, ti); | 1198 | struct dm_target_io *tio = alloc_tio(ci, ti); |
1199 | struct bio *clone; | 1199 | struct bio *clone; |
@@ -1208,17 +1208,21 @@ static void __issue_target_request(struct clone_info *ci, struct dm_target *ti, | |||
1208 | clone = bio_alloc_bioset(GFP_NOIO, ci->bio->bi_max_vecs, ci->md->bs); | 1208 | clone = bio_alloc_bioset(GFP_NOIO, ci->bio->bi_max_vecs, ci->md->bs); |
1209 | __bio_clone(clone, ci->bio); | 1209 | __bio_clone(clone, ci->bio); |
1210 | clone->bi_destructor = dm_bio_destructor; | 1210 | clone->bi_destructor = dm_bio_destructor; |
1211 | if (len) { | ||
1212 | clone->bi_sector = ci->sector; | ||
1213 | clone->bi_size = to_bytes(len); | ||
1214 | } | ||
1211 | 1215 | ||
1212 | __map_bio(ti, clone, tio); | 1216 | __map_bio(ti, clone, tio); |
1213 | } | 1217 | } |
1214 | 1218 | ||
1215 | static void __issue_target_requests(struct clone_info *ci, struct dm_target *ti, | 1219 | static void __issue_target_requests(struct clone_info *ci, struct dm_target *ti, |
1216 | unsigned num_requests) | 1220 | unsigned num_requests, sector_t len) |
1217 | { | 1221 | { |
1218 | unsigned request_nr; | 1222 | unsigned request_nr; |
1219 | 1223 | ||
1220 | for (request_nr = 0; request_nr < num_requests; request_nr++) | 1224 | for (request_nr = 0; request_nr < num_requests; request_nr++) |
1221 | __issue_target_request(ci, ti, request_nr); | 1225 | __issue_target_request(ci, ti, request_nr, len); |
1222 | } | 1226 | } |
1223 | 1227 | ||
1224 | static int __clone_and_map_empty_barrier(struct clone_info *ci) | 1228 | static int __clone_and_map_empty_barrier(struct clone_info *ci) |
@@ -1227,7 +1231,7 @@ static int __clone_and_map_empty_barrier(struct clone_info *ci) | |||
1227 | struct dm_target *ti; | 1231 | struct dm_target *ti; |
1228 | 1232 | ||
1229 | while ((ti = dm_table_get_target(ci->map, target_nr++))) | 1233 | while ((ti = dm_table_get_target(ci->map, target_nr++))) |
1230 | __issue_target_requests(ci, ti, ti->num_flush_requests); | 1234 | __issue_target_requests(ci, ti, ti->num_flush_requests, 0); |
1231 | 1235 | ||
1232 | ci->sector_count = 0; | 1236 | ci->sector_count = 0; |
1233 | 1237 | ||
@@ -1253,32 +1257,27 @@ static void __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti) | |||
1253 | static int __clone_and_map_discard(struct clone_info *ci) | 1257 | static int __clone_and_map_discard(struct clone_info *ci) |
1254 | { | 1258 | { |
1255 | struct dm_target *ti; | 1259 | struct dm_target *ti; |
1256 | sector_t max; | 1260 | sector_t len; |
1257 | 1261 | ||
1258 | ti = dm_table_find_target(ci->map, ci->sector); | 1262 | do { |
1259 | if (!dm_target_is_valid(ti)) | 1263 | ti = dm_table_find_target(ci->map, ci->sector); |
1260 | return -EIO; | 1264 | if (!dm_target_is_valid(ti)) |
1261 | 1265 | return -EIO; | |
1262 | /* | ||
1263 | * Even though the device advertised discard support, | ||
1264 | * reconfiguration might have changed that since the | ||
1265 | * check was performed. | ||
1266 | */ | ||
1267 | 1266 | ||
1268 | if (!ti->num_discard_requests) | ||
1269 | return -EOPNOTSUPP; | ||
1270 | |||
1271 | max = max_io_len(ci->sector, ti); | ||
1272 | |||
1273 | if (ci->sector_count > max) | ||
1274 | /* | 1267 | /* |
1275 | * FIXME: Handle a discard that spans two or more targets. | 1268 | * Even though the device advertised discard support, |
1269 | * reconfiguration might have changed that since the | ||
1270 | * check was performed. | ||
1276 | */ | 1271 | */ |
1277 | return -EOPNOTSUPP; | 1272 | if (!ti->num_discard_requests) |
1273 | return -EOPNOTSUPP; | ||
1278 | 1274 | ||
1279 | __issue_target_requests(ci, ti, ti->num_discard_requests); | 1275 | len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti)); |
1280 | 1276 | ||
1281 | ci->sector_count = 0; | 1277 | __issue_target_requests(ci, ti, ti->num_discard_requests, len); |
1278 | |||
1279 | ci->sector += len; | ||
1280 | } while (ci->sector_count -= len); | ||
1282 | 1281 | ||
1283 | return 0; | 1282 | return 0; |
1284 | } | 1283 | } |