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>

authored by Mike Snitzer and committed by Alasdair G Kergon a79245b3 c96053b7

+23 -24
+23 -24
drivers/md/dm.c
··· 1193 } 1194 1195 static void __issue_target_request(struct clone_info *ci, struct dm_target *ti, 1196 - unsigned request_nr) 1197 { 1198 struct dm_target_io *tio = alloc_tio(ci, ti); 1199 struct bio *clone; ··· 1208 clone = bio_alloc_bioset(GFP_NOIO, ci->bio->bi_max_vecs, ci->md->bs); 1209 __bio_clone(clone, ci->bio); 1210 clone->bi_destructor = dm_bio_destructor; 1211 1212 __map_bio(ti, clone, tio); 1213 } 1214 1215 static void __issue_target_requests(struct clone_info *ci, struct dm_target *ti, 1216 - unsigned num_requests) 1217 { 1218 unsigned request_nr; 1219 1220 for (request_nr = 0; request_nr < num_requests; request_nr++) 1221 - __issue_target_request(ci, ti, request_nr); 1222 } 1223 1224 static int __clone_and_map_empty_barrier(struct clone_info *ci) ··· 1231 struct dm_target *ti; 1232 1233 while ((ti = dm_table_get_target(ci->map, target_nr++))) 1234 - __issue_target_requests(ci, ti, ti->num_flush_requests); 1235 1236 ci->sector_count = 0; 1237 ··· 1257 static int __clone_and_map_discard(struct clone_info *ci) 1258 { 1259 struct dm_target *ti; 1260 - sector_t max; 1261 1262 - ti = dm_table_find_target(ci->map, ci->sector); 1263 - if (!dm_target_is_valid(ti)) 1264 - return -EIO; 1265 1266 - /* 1267 - * Even though the device advertised discard support, 1268 - * reconfiguration might have changed that since the 1269 - * check was performed. 1270 - */ 1271 - 1272 - if (!ti->num_discard_requests) 1273 - return -EOPNOTSUPP; 1274 - 1275 - max = max_io_len(ci->sector, ti); 1276 - 1277 - if (ci->sector_count > max) 1278 /* 1279 - * FIXME: Handle a discard that spans two or more targets. 1280 */ 1281 - return -EOPNOTSUPP; 1282 1283 - __issue_target_requests(ci, ti, ti->num_discard_requests); 1284 1285 - ci->sector_count = 0; 1286 1287 return 0; 1288 }
··· 1193 } 1194 1195 static void __issue_target_request(struct clone_info *ci, struct dm_target *ti, 1196 + unsigned request_nr, sector_t len) 1197 { 1198 struct dm_target_io *tio = alloc_tio(ci, ti); 1199 struct bio *clone; ··· 1208 clone = bio_alloc_bioset(GFP_NOIO, ci->bio->bi_max_vecs, ci->md->bs); 1209 __bio_clone(clone, ci->bio); 1210 clone->bi_destructor = dm_bio_destructor; 1211 + if (len) { 1212 + clone->bi_sector = ci->sector; 1213 + clone->bi_size = to_bytes(len); 1214 + } 1215 1216 __map_bio(ti, clone, tio); 1217 } 1218 1219 static void __issue_target_requests(struct clone_info *ci, struct dm_target *ti, 1220 + unsigned num_requests, sector_t len) 1221 { 1222 unsigned request_nr; 1223 1224 for (request_nr = 0; request_nr < num_requests; request_nr++) 1225 + __issue_target_request(ci, ti, request_nr, len); 1226 } 1227 1228 static int __clone_and_map_empty_barrier(struct clone_info *ci) ··· 1227 struct dm_target *ti; 1228 1229 while ((ti = dm_table_get_target(ci->map, target_nr++))) 1230 + __issue_target_requests(ci, ti, ti->num_flush_requests, 0); 1231 1232 ci->sector_count = 0; 1233 ··· 1253 static int __clone_and_map_discard(struct clone_info *ci) 1254 { 1255 struct dm_target *ti; 1256 + sector_t len; 1257 1258 + do { 1259 + ti = dm_table_find_target(ci->map, ci->sector); 1260 + if (!dm_target_is_valid(ti)) 1261 + return -EIO; 1262 1263 /* 1264 + * Even though the device advertised discard support, 1265 + * reconfiguration might have changed that since the 1266 + * check was performed. 1267 */ 1268 + if (!ti->num_discard_requests) 1269 + return -EOPNOTSUPP; 1270 1271 + len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti)); 1272 1273 + __issue_target_requests(ci, ti, ti->num_discard_requests, len); 1274 + 1275 + ci->sector += len; 1276 + } while (ci->sector_count -= len); 1277 1278 return 0; 1279 }