aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMike Snitzer <snitzer@redhat.com>2010-08-11 23:14:24 -0400
committerAlasdair G Kergon <agk@redhat.com>2010-08-11 23:14:24 -0400
commita79245b3e5669dc203fec63644d988c451fe55d5 (patch)
tree8814720781708a95ac0bd23bb5232aa5ed9337bd /drivers
parentc96053b767d494d7c30e2be68097ac9defa9403f (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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/dm.c47
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
1195static void __issue_target_request(struct clone_info *ci, struct dm_target *ti, 1195static 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
1215static void __issue_target_requests(struct clone_info *ci, struct dm_target *ti, 1219static 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
1224static int __clone_and_map_empty_barrier(struct clone_info *ci) 1228static 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)
1253static int __clone_and_map_discard(struct clone_info *ci) 1257static 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}