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>
This commit is contained in:
Mike Snitzer 2012-12-21 20:23:37 +00:00 committed by Alasdair G Kergon
parent d54eaa5a0f
commit 23508a96cd
1 changed files with 39 additions and 5 deletions

View File

@ -1174,7 +1174,28 @@ static void __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti)
ci->sector_count = 0;
}
static int __clone_and_map_discard(struct clone_info *ci)
typedef unsigned (*get_num_requests_fn)(struct dm_target *ti);
static unsigned get_num_discard_requests(struct dm_target *ti)
{
return ti->num_discard_requests;
}
static unsigned get_num_write_same_requests(struct dm_target *ti)
{
return ti->num_write_same_requests;
}
typedef bool (*is_split_required_fn)(struct dm_target *ti);
static bool is_split_required_for_discard(struct dm_target *ti)
{
return ti->split_discard_requests;
}
static int __clone_and_map_changing_extent_only(struct clone_info *ci,
get_num_requests_fn get_num_requests,
is_split_required_fn is_split_required)
{
struct dm_target *ti;
sector_t len;
@ -1185,15 +1206,15 @@ static int __clone_and_map_discard(struct clone_info *ci)
return -EIO;
/*
* Even though the device advertised discard support,
* that does not mean every target supports it, and
* Even though the device advertised support for this type of
* request, that does not mean every target supports it, and
* reconfiguration might also have changed that since the
* check was performed.
*/
if (!ti->num_discard_requests)
if (!get_num_requests || !get_num_requests(ti))
return -EOPNOTSUPP;
if (!ti->split_discard_requests)
if (is_split_required && !is_split_required(ti))
len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti));
else
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)
return 0;
}
static int __clone_and_map_discard(struct clone_info *ci)
{
return __clone_and_map_changing_extent_only(ci, get_num_discard_requests,
is_split_required_for_discard);
}
static int __clone_and_map_write_same(struct clone_info *ci)
{
return __clone_and_map_changing_extent_only(ci, get_num_write_same_requests, NULL);
}
static int __clone_and_map(struct clone_info *ci)
{
struct bio *bio = ci->bio;
@ -1215,6 +1247,8 @@ static int __clone_and_map(struct clone_info *ci)
if (unlikely(bio->bi_rw & REQ_DISCARD))
return __clone_and_map_discard(ci);
else if (unlikely(bio->bi_rw & REQ_WRITE_SAME))
return __clone_and_map_write_same(ci);
ti = dm_table_find_target(ci->map, ci->sector);
if (!dm_target_is_valid(ti))