diff options
-rw-r--r-- | drivers/md/dm-core.h | 1 | ||||
-rw-r--r-- | drivers/md/dm-io.c | 8 | ||||
-rw-r--r-- | drivers/md/dm-linear.c | 1 | ||||
-rw-r--r-- | drivers/md/dm-mpath.c | 1 | ||||
-rw-r--r-- | drivers/md/dm-rq.c | 11 | ||||
-rw-r--r-- | drivers/md/dm-stripe.c | 2 | ||||
-rw-r--r-- | drivers/md/dm-table.c | 30 | ||||
-rw-r--r-- | drivers/md/dm.c | 31 | ||||
-rw-r--r-- | include/linux/device-mapper.h | 6 |
9 files changed, 83 insertions, 8 deletions
diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 136fda3ff9e5..fea5bd52ada8 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h | |||
@@ -132,6 +132,7 @@ void dm_init_md_queue(struct mapped_device *md); | |||
132 | void dm_init_normal_md_queue(struct mapped_device *md); | 132 | void dm_init_normal_md_queue(struct mapped_device *md); |
133 | int md_in_flight(struct mapped_device *md); | 133 | int md_in_flight(struct mapped_device *md); |
134 | void disable_write_same(struct mapped_device *md); | 134 | void disable_write_same(struct mapped_device *md); |
135 | void disable_write_zeroes(struct mapped_device *md); | ||
135 | 136 | ||
136 | static inline struct completion *dm_get_completion_from_kobject(struct kobject *kobj) | 137 | static inline struct completion *dm_get_completion_from_kobject(struct kobject *kobj) |
137 | { | 138 | { |
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index b808cbe22678..3702e502466d 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c | |||
@@ -312,9 +312,12 @@ static void do_region(int op, int op_flags, unsigned region, | |||
312 | */ | 312 | */ |
313 | if (op == REQ_OP_DISCARD) | 313 | if (op == REQ_OP_DISCARD) |
314 | special_cmd_max_sectors = q->limits.max_discard_sectors; | 314 | special_cmd_max_sectors = q->limits.max_discard_sectors; |
315 | else if (op == REQ_OP_WRITE_ZEROES) | ||
316 | special_cmd_max_sectors = q->limits.max_write_zeroes_sectors; | ||
315 | else if (op == REQ_OP_WRITE_SAME) | 317 | else if (op == REQ_OP_WRITE_SAME) |
316 | special_cmd_max_sectors = q->limits.max_write_same_sectors; | 318 | special_cmd_max_sectors = q->limits.max_write_same_sectors; |
317 | if ((op == REQ_OP_DISCARD || op == REQ_OP_WRITE_SAME) && | 319 | if ((op == REQ_OP_DISCARD || op == REQ_OP_WRITE_ZEROES || |
320 | op == REQ_OP_WRITE_SAME) && | ||
318 | special_cmd_max_sectors == 0) { | 321 | special_cmd_max_sectors == 0) { |
319 | dec_count(io, region, -EOPNOTSUPP); | 322 | dec_count(io, region, -EOPNOTSUPP); |
320 | return; | 323 | return; |
@@ -330,6 +333,7 @@ static void do_region(int op, int op_flags, unsigned region, | |||
330 | */ | 333 | */ |
331 | switch (op) { | 334 | switch (op) { |
332 | case REQ_OP_DISCARD: | 335 | case REQ_OP_DISCARD: |
336 | case REQ_OP_WRITE_ZEROES: | ||
333 | num_bvecs = 0; | 337 | num_bvecs = 0; |
334 | break; | 338 | break; |
335 | case REQ_OP_WRITE_SAME: | 339 | case REQ_OP_WRITE_SAME: |
@@ -347,7 +351,7 @@ static void do_region(int op, int op_flags, unsigned region, | |||
347 | bio_set_op_attrs(bio, op, op_flags); | 351 | bio_set_op_attrs(bio, op, op_flags); |
348 | store_io_and_region_in_bio(bio, io, region); | 352 | store_io_and_region_in_bio(bio, io, region); |
349 | 353 | ||
350 | if (op == REQ_OP_DISCARD) { | 354 | if (op == REQ_OP_DISCARD || op == REQ_OP_WRITE_ZEROES) { |
351 | num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining); | 355 | num_sectors = min_t(sector_t, special_cmd_max_sectors, remaining); |
352 | bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT; | 356 | bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT; |
353 | remaining -= num_sectors; | 357 | remaining -= num_sectors; |
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 4788b0b989a9..e17fd44ceef5 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c | |||
@@ -59,6 +59,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
59 | ti->num_flush_bios = 1; | 59 | ti->num_flush_bios = 1; |
60 | ti->num_discard_bios = 1; | 60 | ti->num_discard_bios = 1; |
61 | ti->num_write_same_bios = 1; | 61 | ti->num_write_same_bios = 1; |
62 | ti->num_write_zeroes_bios = 1; | ||
62 | ti->private = lc; | 63 | ti->private = lc; |
63 | return 0; | 64 | return 0; |
64 | 65 | ||
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 7f223dbed49f..ab55955ed704 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c | |||
@@ -1103,6 +1103,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) | |||
1103 | ti->num_flush_bios = 1; | 1103 | ti->num_flush_bios = 1; |
1104 | ti->num_discard_bios = 1; | 1104 | ti->num_discard_bios = 1; |
1105 | ti->num_write_same_bios = 1; | 1105 | ti->num_write_same_bios = 1; |
1106 | ti->num_write_zeroes_bios = 1; | ||
1106 | if (m->queue_mode == DM_TYPE_BIO_BASED) | 1107 | if (m->queue_mode == DM_TYPE_BIO_BASED) |
1107 | ti->per_io_data_size = multipath_per_bio_data_size(); | 1108 | ti->per_io_data_size = multipath_per_bio_data_size(); |
1108 | else | 1109 | else |
diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index d19af1d21f4c..e60f1b6845be 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c | |||
@@ -298,9 +298,14 @@ static void dm_done(struct request *clone, int error, bool mapped) | |||
298 | r = rq_end_io(tio->ti, clone, error, &tio->info); | 298 | r = rq_end_io(tio->ti, clone, error, &tio->info); |
299 | } | 299 | } |
300 | 300 | ||
301 | if (unlikely(r == -EREMOTEIO && (req_op(clone) == REQ_OP_WRITE_SAME) && | 301 | if (unlikely(r == -EREMOTEIO)) { |
302 | !clone->q->limits.max_write_same_sectors)) | 302 | if (req_op(clone) == REQ_OP_WRITE_SAME && |
303 | disable_write_same(tio->md); | 303 | !clone->q->limits.max_write_same_sectors) |
304 | disable_write_same(tio->md); | ||
305 | if (req_op(clone) == REQ_OP_WRITE_ZEROES && | ||
306 | !clone->q->limits.max_write_zeroes_sectors) | ||
307 | disable_write_zeroes(tio->md); | ||
308 | } | ||
304 | 309 | ||
305 | if (r <= 0) | 310 | if (r <= 0) |
306 | /* The target wants to complete the I/O */ | 311 | /* The target wants to complete the I/O */ |
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 28193a57bf47..5ef49c121d99 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c | |||
@@ -169,6 +169,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
169 | ti->num_flush_bios = stripes; | 169 | ti->num_flush_bios = stripes; |
170 | ti->num_discard_bios = stripes; | 170 | ti->num_discard_bios = stripes; |
171 | ti->num_write_same_bios = stripes; | 171 | ti->num_write_same_bios = stripes; |
172 | ti->num_write_zeroes_bios = stripes; | ||
172 | 173 | ||
173 | sc->chunk_size = chunk_size; | 174 | sc->chunk_size = chunk_size; |
174 | if (chunk_size & (chunk_size - 1)) | 175 | if (chunk_size & (chunk_size - 1)) |
@@ -293,6 +294,7 @@ static int stripe_map(struct dm_target *ti, struct bio *bio) | |||
293 | return DM_MAPIO_REMAPPED; | 294 | return DM_MAPIO_REMAPPED; |
294 | } | 295 | } |
295 | if (unlikely(bio_op(bio) == REQ_OP_DISCARD) || | 296 | if (unlikely(bio_op(bio) == REQ_OP_DISCARD) || |
297 | unlikely(bio_op(bio) == REQ_OP_WRITE_ZEROES) || | ||
296 | unlikely(bio_op(bio) == REQ_OP_WRITE_SAME)) { | 298 | unlikely(bio_op(bio) == REQ_OP_WRITE_SAME)) { |
297 | target_bio_nr = dm_bio_get_target_bio_nr(bio); | 299 | target_bio_nr = dm_bio_get_target_bio_nr(bio); |
298 | BUG_ON(target_bio_nr >= sc->stripes); | 300 | BUG_ON(target_bio_nr >= sc->stripes); |
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 3ad16d9c9d5a..5cd665c91ead 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -1533,6 +1533,34 @@ static bool dm_table_supports_write_same(struct dm_table *t) | |||
1533 | return true; | 1533 | return true; |
1534 | } | 1534 | } |
1535 | 1535 | ||
1536 | static int device_not_write_zeroes_capable(struct dm_target *ti, struct dm_dev *dev, | ||
1537 | sector_t start, sector_t len, void *data) | ||
1538 | { | ||
1539 | struct request_queue *q = bdev_get_queue(dev->bdev); | ||
1540 | |||
1541 | return q && !q->limits.max_write_zeroes_sectors; | ||
1542 | } | ||
1543 | |||
1544 | static bool dm_table_supports_write_zeroes(struct dm_table *t) | ||
1545 | { | ||
1546 | struct dm_target *ti; | ||
1547 | unsigned i = 0; | ||
1548 | |||
1549 | while (i < dm_table_get_num_targets(t)) { | ||
1550 | ti = dm_table_get_target(t, i++); | ||
1551 | |||
1552 | if (!ti->num_write_zeroes_bios) | ||
1553 | return false; | ||
1554 | |||
1555 | if (!ti->type->iterate_devices || | ||
1556 | ti->type->iterate_devices(ti, device_not_write_zeroes_capable, NULL)) | ||
1557 | return false; | ||
1558 | } | ||
1559 | |||
1560 | return true; | ||
1561 | } | ||
1562 | |||
1563 | |||
1536 | static int device_discard_capable(struct dm_target *ti, struct dm_dev *dev, | 1564 | static int device_discard_capable(struct dm_target *ti, struct dm_dev *dev, |
1537 | sector_t start, sector_t len, void *data) | 1565 | sector_t start, sector_t len, void *data) |
1538 | { | 1566 | { |
@@ -1603,6 +1631,8 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, | |||
1603 | 1631 | ||
1604 | if (!dm_table_supports_write_same(t)) | 1632 | if (!dm_table_supports_write_same(t)) |
1605 | q->limits.max_write_same_sectors = 0; | 1633 | q->limits.max_write_same_sectors = 0; |
1634 | if (!dm_table_supports_write_zeroes(t)) | ||
1635 | q->limits.max_write_zeroes_sectors = 0; | ||
1606 | 1636 | ||
1607 | if (dm_table_all_devices_attribute(t, queue_supports_sg_merge)) | 1637 | if (dm_table_all_devices_attribute(t, queue_supports_sg_merge)) |
1608 | queue_flag_clear_unlocked(QUEUE_FLAG_NO_SG_MERGE, q); | 1638 | queue_flag_clear_unlocked(QUEUE_FLAG_NO_SG_MERGE, q); |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index cd93a3b9ceca..8bf397729bbd 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -824,6 +824,14 @@ void disable_write_same(struct mapped_device *md) | |||
824 | limits->max_write_same_sectors = 0; | 824 | limits->max_write_same_sectors = 0; |
825 | } | 825 | } |
826 | 826 | ||
827 | void disable_write_zeroes(struct mapped_device *md) | ||
828 | { | ||
829 | struct queue_limits *limits = dm_get_queue_limits(md); | ||
830 | |||
831 | /* device doesn't really support WRITE ZEROES, disable it */ | ||
832 | limits->max_write_zeroes_sectors = 0; | ||
833 | } | ||
834 | |||
827 | static void clone_endio(struct bio *bio) | 835 | static void clone_endio(struct bio *bio) |
828 | { | 836 | { |
829 | int error = bio->bi_error; | 837 | int error = bio->bi_error; |
@@ -850,9 +858,14 @@ static void clone_endio(struct bio *bio) | |||
850 | } | 858 | } |
851 | } | 859 | } |
852 | 860 | ||
853 | if (unlikely(r == -EREMOTEIO && (bio_op(bio) == REQ_OP_WRITE_SAME) && | 861 | if (unlikely(r == -EREMOTEIO)) { |
854 | !bdev_get_queue(bio->bi_bdev)->limits.max_write_same_sectors)) | 862 | if (bio_op(bio) == REQ_OP_WRITE_SAME && |
855 | disable_write_same(md); | 863 | !bdev_get_queue(bio->bi_bdev)->limits.max_write_same_sectors) |
864 | disable_write_same(md); | ||
865 | if (bio_op(bio) == REQ_OP_WRITE_ZEROES && | ||
866 | !bdev_get_queue(bio->bi_bdev)->limits.max_write_zeroes_sectors) | ||
867 | disable_write_zeroes(md); | ||
868 | } | ||
856 | 869 | ||
857 | free_tio(tio); | 870 | free_tio(tio); |
858 | dec_pending(io, error); | 871 | dec_pending(io, error); |
@@ -1201,6 +1214,11 @@ static unsigned get_num_write_same_bios(struct dm_target *ti) | |||
1201 | return ti->num_write_same_bios; | 1214 | return ti->num_write_same_bios; |
1202 | } | 1215 | } |
1203 | 1216 | ||
1217 | static unsigned get_num_write_zeroes_bios(struct dm_target *ti) | ||
1218 | { | ||
1219 | return ti->num_write_zeroes_bios; | ||
1220 | } | ||
1221 | |||
1204 | typedef bool (*is_split_required_fn)(struct dm_target *ti); | 1222 | typedef bool (*is_split_required_fn)(struct dm_target *ti); |
1205 | 1223 | ||
1206 | static bool is_split_required_for_discard(struct dm_target *ti) | 1224 | static bool is_split_required_for_discard(struct dm_target *ti) |
@@ -1255,6 +1273,11 @@ static int __send_write_same(struct clone_info *ci) | |||
1255 | return __send_changing_extent_only(ci, get_num_write_same_bios, NULL); | 1273 | return __send_changing_extent_only(ci, get_num_write_same_bios, NULL); |
1256 | } | 1274 | } |
1257 | 1275 | ||
1276 | static int __send_write_zeroes(struct clone_info *ci) | ||
1277 | { | ||
1278 | return __send_changing_extent_only(ci, get_num_write_zeroes_bios, NULL); | ||
1279 | } | ||
1280 | |||
1258 | /* | 1281 | /* |
1259 | * Select the correct strategy for processing a non-flush bio. | 1282 | * Select the correct strategy for processing a non-flush bio. |
1260 | */ | 1283 | */ |
@@ -1269,6 +1292,8 @@ static int __split_and_process_non_flush(struct clone_info *ci) | |||
1269 | return __send_discard(ci); | 1292 | return __send_discard(ci); |
1270 | else if (unlikely(bio_op(bio) == REQ_OP_WRITE_SAME)) | 1293 | else if (unlikely(bio_op(bio) == REQ_OP_WRITE_SAME)) |
1271 | return __send_write_same(ci); | 1294 | return __send_write_same(ci); |
1295 | else if (unlikely(bio_op(bio) == REQ_OP_WRITE_ZEROES)) | ||
1296 | return __send_write_zeroes(ci); | ||
1272 | 1297 | ||
1273 | ti = dm_table_find_target(ci->map, ci->sector); | 1298 | ti = dm_table_find_target(ci->map, ci->sector); |
1274 | if (!dm_target_is_valid(ti)) | 1299 | if (!dm_target_is_valid(ti)) |
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index a7e6903866fd..3829bee2302a 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h | |||
@@ -255,6 +255,12 @@ struct dm_target { | |||
255 | unsigned num_write_same_bios; | 255 | unsigned num_write_same_bios; |
256 | 256 | ||
257 | /* | 257 | /* |
258 | * The number of WRITE ZEROES bios that will be submitted to the target. | ||
259 | * The bio number can be accessed with dm_bio_get_target_bio_nr. | ||
260 | */ | ||
261 | unsigned num_write_zeroes_bios; | ||
262 | |||
263 | /* | ||
258 | * The minimum number of extra bytes allocated in each io for the | 264 | * The minimum number of extra bytes allocated in each io for the |
259 | * target to use. | 265 | * target to use. |
260 | */ | 266 | */ |