diff options
| author | Mike Snitzer <snitzer@redhat.com> | 2012-12-21 15:23:37 -0500 |
|---|---|---|
| committer | Alasdair G Kergon <agk@redhat.com> | 2012-12-21 15:23:37 -0500 |
| commit | 23508a96cd2e857d57044a2ed7d305f2d9daf441 (patch) | |
| tree | 149ead46c45a0fdd159fb32a6bfb6439eae3d652 | |
| parent | d54eaa5a0fde0a202e4e91f200f818edcef15bee (diff) | |
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>
| -rw-r--r-- | drivers/md/dm.c | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 77e6eff41cae..5401cdce0fc5 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
| @@ -1174,7 +1174,28 @@ static void __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti) | |||
| 1174 | ci->sector_count = 0; | 1174 | ci->sector_count = 0; |
| 1175 | } | 1175 | } |
| 1176 | 1176 | ||
| 1177 | static int __clone_and_map_discard(struct clone_info *ci) | 1177 | typedef unsigned (*get_num_requests_fn)(struct dm_target *ti); |
| 1178 | |||
| 1179 | static unsigned get_num_discard_requests(struct dm_target *ti) | ||
| 1180 | { | ||
| 1181 | return ti->num_discard_requests; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | static unsigned get_num_write_same_requests(struct dm_target *ti) | ||
| 1185 | { | ||
| 1186 | return ti->num_write_same_requests; | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | typedef bool (*is_split_required_fn)(struct dm_target *ti); | ||
| 1190 | |||
| 1191 | static bool is_split_required_for_discard(struct dm_target *ti) | ||
| 1192 | { | ||
| 1193 | return ti->split_discard_requests; | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | static int __clone_and_map_changing_extent_only(struct clone_info *ci, | ||
| 1197 | get_num_requests_fn get_num_requests, | ||
| 1198 | is_split_required_fn is_split_required) | ||
| 1178 | { | 1199 | { |
| 1179 | struct dm_target *ti; | 1200 | struct dm_target *ti; |
| 1180 | sector_t len; | 1201 | sector_t len; |
| @@ -1185,15 +1206,15 @@ static int __clone_and_map_discard(struct clone_info *ci) | |||
| 1185 | return -EIO; | 1206 | return -EIO; |
| 1186 | 1207 | ||
| 1187 | /* | 1208 | /* |
| 1188 | * Even though the device advertised discard support, | 1209 | * Even though the device advertised support for this type of |
| 1189 | * that does not mean every target supports it, and | 1210 | * request, that does not mean every target supports it, and |
| 1190 | * reconfiguration might also have changed that since the | 1211 | * reconfiguration might also have changed that since the |
| 1191 | * check was performed. | 1212 | * check was performed. |
| 1192 | */ | 1213 | */ |
| 1193 | if (!ti->num_discard_requests) | 1214 | if (!get_num_requests || !get_num_requests(ti)) |
| 1194 | return -EOPNOTSUPP; | 1215 | return -EOPNOTSUPP; |
| 1195 | 1216 | ||
| 1196 | if (!ti->split_discard_requests) | 1217 | if (is_split_required && !is_split_required(ti)) |
| 1197 | len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti)); | 1218 | len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti)); |
| 1198 | else | 1219 | else |
| 1199 | len = min(ci->sector_count, max_io_len(ci->sector, ti)); | 1220 | 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) | |||
| 1206 | return 0; | 1227 | return 0; |
| 1207 | } | 1228 | } |
| 1208 | 1229 | ||
| 1230 | static int __clone_and_map_discard(struct clone_info *ci) | ||
| 1231 | { | ||
| 1232 | return __clone_and_map_changing_extent_only(ci, get_num_discard_requests, | ||
| 1233 | is_split_required_for_discard); | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | static int __clone_and_map_write_same(struct clone_info *ci) | ||
| 1237 | { | ||
| 1238 | return __clone_and_map_changing_extent_only(ci, get_num_write_same_requests, NULL); | ||
| 1239 | } | ||
| 1240 | |||
| 1209 | static int __clone_and_map(struct clone_info *ci) | 1241 | static int __clone_and_map(struct clone_info *ci) |
| 1210 | { | 1242 | { |
| 1211 | struct bio *bio = ci->bio; | 1243 | struct bio *bio = ci->bio; |
| @@ -1215,6 +1247,8 @@ static int __clone_and_map(struct clone_info *ci) | |||
| 1215 | 1247 | ||
| 1216 | if (unlikely(bio->bi_rw & REQ_DISCARD)) | 1248 | if (unlikely(bio->bi_rw & REQ_DISCARD)) |
| 1217 | return __clone_and_map_discard(ci); | 1249 | return __clone_and_map_discard(ci); |
| 1250 | else if (unlikely(bio->bi_rw & REQ_WRITE_SAME)) | ||
| 1251 | return __clone_and_map_write_same(ci); | ||
| 1218 | 1252 | ||
| 1219 | ti = dm_table_find_target(ci->map, ci->sector); | 1253 | ti = dm_table_find_target(ci->map, ci->sector); |
| 1220 | if (!dm_target_is_valid(ti)) | 1254 | if (!dm_target_is_valid(ti)) |
