diff options
author | Mike Snitzer <snitzer@redhat.com> | 2010-08-03 11:30:41 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-08-03 11:30:41 +1000 |
commit | 11f41b00be2b18c787a8dc5a167024a2c472e76f (patch) | |
tree | 26ff857bc4065674af5ac40407bf09822ccdce41 /drivers/md | |
parent | 1d67305f1465cfebbb7d6701fa58222eb4bda946 (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/md')
-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 da8b8feaffd2..8b464dd60589 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1185,7 +1185,7 @@ static struct dm_target_io *alloc_tio(struct clone_info *ci, } static void __issue_target_request(struct clone_info *ci, struct dm_target *ti, - unsigned request_nr) + unsigned request_nr, sector_t len) { struct dm_target_io *tio = alloc_tio(ci, ti); struct bio *clone; @@ -1200,17 +1200,21 @@ static void __issue_target_request(struct clone_info *ci, struct dm_target *ti, clone = bio_alloc_bioset(GFP_NOIO, ci->bio->bi_max_vecs, ci->md->bs); __bio_clone(clone, ci->bio); clone->bi_destructor = dm_bio_destructor; + if (len) { + clone->bi_sector = ci->sector; + clone->bi_size = to_bytes(len); + } __map_bio(ti, clone, tio); } static void __issue_target_requests(struct clone_info *ci, struct dm_target *ti, - unsigned num_requests) + unsigned num_requests, sector_t len) { unsigned request_nr; for (request_nr = 0; request_nr < num_requests; request_nr++) - __issue_target_request(ci, ti, request_nr); + __issue_target_request(ci, ti, request_nr, len); } static int __clone_and_map_empty_barrier(struct clone_info *ci) @@ -1219,7 +1223,7 @@ static int __clone_and_map_empty_barrier(struct clone_info *ci) struct dm_target *ti; while ((ti = dm_table_get_target(ci->map, target_nr++))) - __issue_target_requests(ci, ti, ti->num_flush_requests); + __issue_target_requests(ci, ti, ti->num_flush_requests, 0); ci->sector_count = 0; @@ -1245,32 +1249,27 @@ static void __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti) static int __clone_and_map_discard(struct clone_info *ci) { struct dm_target *ti; - sector_t max; + sector_t len; - ti = dm_table_find_target(ci->map, ci->sector); - if (!dm_target_is_valid(ti)) - return -EIO; - - /* - * Even though the device advertised discard support, - * reconfiguration might have changed that since the - * check was performed. - */ + do { + ti = dm_table_find_target(ci->map, ci->sector); + if (!dm_target_is_valid(ti)) + return -EIO; - if (!ti->num_discard_requests) - return -EOPNOTSUPP; - - max = max_io_len(ci->sector, ti); - - if (ci->sector_count > max) /* - * FIXME: Handle a discard that spans two or more targets. + * Even though the device advertised discard support, + * reconfiguration might have changed that since the + * check was performed. */ - return -EOPNOTSUPP; + if (!ti->num_discard_requests) + return -EOPNOTSUPP; - __issue_target_requests(ci, ti, ti->num_discard_requests); + len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti)); - ci->sector_count = 0; + __issue_target_requests(ci, ti, ti->num_discard_requests, len); + + ci->sector += len; + } while (ci->sector_count -= len); return 0; } |