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.
Unified · Split
| @@ -1174,7 +1174,28 @@ static void __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti) · 1173 unmodified lines | ||
| 1174 | 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 | 1200 | struct dm_target *ti; |
| 1180 | 1201 | sector_t len; |
| @@ -1185,15 +1206,15 @@ static int __clone_and_map_discard(struct clone_info *ci) · 4 unmodified lines | ||
| 1185 | 1206 | return -EIO; |
| 1186 | 1207 | |
| 1187 | 1208 | /* |
| 1188 | − * Even though the device advertised discard support, | |
| 1189 | − * that does not mean every target supports it, and | |
| 1209 | + * Even though the device advertised support for this type of | |
| 1210 | + * request, that does not mean every target supports it, and | |
| 1190 | 1211 | * reconfiguration might also have changed that since the |
| 1191 | 1212 | * check was performed. |
| 1192 | 1213 | */ |
| 1193 | − if (!ti->num_discard_requests) | |
| 1214 | + if (!get_num_requests || !get_num_requests(ti)) | |
| 1194 | 1215 | return -EOPNOTSUPP; |
| 1195 | 1216 | |
| 1196 | − if (!ti->split_discard_requests) | |
| 1217 | + if (is_split_required && !is_split_required(ti)) | |
| 1197 | 1218 | len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti)); |
| 1198 | 1219 | else |
| 1199 | 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) · 6 unmodified lines | ||
| 1206 | 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 | 1241 | static int __clone_and_map(struct clone_info *ci) |
| 1210 | 1242 | { |
| 1211 | 1243 | struct bio *bio = ci->bio; |
| @@ -1215,6 +1247,8 @@ static int __clone_and_map(struct clone_info *ci) · 3 unmodified lines | ||
| 1215 | 1247 | |
| 1216 | 1248 | if (unlikely(bio->bi_rw & REQ_DISCARD)) |
| 1217 | 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 | 1253 | ti = dm_table_find_target(ci->map, ci->sector); |
| 1220 | 1254 | if (!dm_target_is_valid(ti)) |