|
@@ -824,6 +824,14 @@ void disable_write_same(struct mapped_device *md)
|
|
|
limits->max_write_same_sectors = 0;
|
|
|
}
|
|
|
|
|
|
+void disable_write_zeroes(struct mapped_device *md)
|
|
|
+{
|
|
|
+ struct queue_limits *limits = dm_get_queue_limits(md);
|
|
|
+
|
|
|
+ /* device doesn't really support WRITE ZEROES, disable it */
|
|
|
+ limits->max_write_zeroes_sectors = 0;
|
|
|
+}
|
|
|
+
|
|
|
static void clone_endio(struct bio *bio)
|
|
|
{
|
|
|
int error = bio->bi_error;
|
|
@@ -850,9 +858,14 @@ static void clone_endio(struct bio *bio)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (unlikely(r == -EREMOTEIO && (bio_op(bio) == REQ_OP_WRITE_SAME) &&
|
|
|
- !bdev_get_queue(bio->bi_bdev)->limits.max_write_same_sectors))
|
|
|
- disable_write_same(md);
|
|
|
+ if (unlikely(r == -EREMOTEIO)) {
|
|
|
+ if (bio_op(bio) == REQ_OP_WRITE_SAME &&
|
|
|
+ !bdev_get_queue(bio->bi_bdev)->limits.max_write_same_sectors)
|
|
|
+ disable_write_same(md);
|
|
|
+ if (bio_op(bio) == REQ_OP_WRITE_ZEROES &&
|
|
|
+ !bdev_get_queue(bio->bi_bdev)->limits.max_write_zeroes_sectors)
|
|
|
+ disable_write_zeroes(md);
|
|
|
+ }
|
|
|
|
|
|
free_tio(tio);
|
|
|
dec_pending(io, error);
|
|
@@ -1201,6 +1214,11 @@ static unsigned get_num_write_same_bios(struct dm_target *ti)
|
|
|
return ti->num_write_same_bios;
|
|
|
}
|
|
|
|
|
|
+static unsigned get_num_write_zeroes_bios(struct dm_target *ti)
|
|
|
+{
|
|
|
+ return ti->num_write_zeroes_bios;
|
|
|
+}
|
|
|
+
|
|
|
typedef bool (*is_split_required_fn)(struct dm_target *ti);
|
|
|
|
|
|
static bool is_split_required_for_discard(struct dm_target *ti)
|
|
@@ -1255,6 +1273,11 @@ static int __send_write_same(struct clone_info *ci)
|
|
|
return __send_changing_extent_only(ci, get_num_write_same_bios, NULL);
|
|
|
}
|
|
|
|
|
|
+static int __send_write_zeroes(struct clone_info *ci)
|
|
|
+{
|
|
|
+ return __send_changing_extent_only(ci, get_num_write_zeroes_bios, NULL);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Select the correct strategy for processing a non-flush bio.
|
|
|
*/
|
|
@@ -1269,6 +1292,8 @@ static int __split_and_process_non_flush(struct clone_info *ci)
|
|
|
return __send_discard(ci);
|
|
|
else if (unlikely(bio_op(bio) == REQ_OP_WRITE_SAME))
|
|
|
return __send_write_same(ci);
|
|
|
+ else if (unlikely(bio_op(bio) == REQ_OP_WRITE_ZEROES))
|
|
|
+ return __send_write_zeroes(ci);
|
|
|
|
|
|
ti = dm_table_find_target(ci->map, ci->sector);
|
|
|
if (!dm_target_is_valid(ti))
|