aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <axboe@fb.com>2015-07-16 11:14:26 -0400
committerJens Axboe <axboe@fb.com>2015-07-17 10:41:53 -0400
commit0034af036554c39eefd14d835a8ec3496ac46712 (patch)
tree54a9262ca37905600872eb8638d5453a82f59520
parent2bb4cd5cc472b191a46938becb7dafdd44644329 (diff)
block: make /sys/block/<dev>/queue/discard_max_bytes writeable
Lots of devices support huge discard sizes these days. Depending on how the device handles them internally, huge discards can introduce massive latencies (hundreds of msec) on the device side. We have a sysfs file, discard_max_bytes, that advertises the max hardware supported discard size. Make this writeable, and split the settings into a soft and hard limit. This can be set from 'discard_granularity' and up to the hardware limit. Add a new sysfs file, 'discard_max_hw_bytes', that shows the hw set limit. Reviewed-by: Jeff Moyer <jmoyer@redhat.com> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--Documentation/block/queue-sysfs.txt10
-rw-r--r--block/blk-settings.c4
-rw-r--r--block/blk-sysfs.c40
-rw-r--r--include/linux/blkdev.h1
4 files changed, 53 insertions, 2 deletions
diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt
index 3a29f8914df9..e5d914845be6 100644
--- a/Documentation/block/queue-sysfs.txt
+++ b/Documentation/block/queue-sysfs.txt
@@ -20,7 +20,7 @@ This shows the size of internal allocation of the device in bytes, if
20reported by the device. A value of '0' means device does not support 20reported by the device. A value of '0' means device does not support
21the discard functionality. 21the discard functionality.
22 22
23discard_max_bytes (RO) 23discard_max_hw_bytes (RO)
24---------------------- 24----------------------
25Devices that support discard functionality may have internal limits on 25Devices that support discard functionality may have internal limits on
26the number of bytes that can be trimmed or unmapped in a single operation. 26the number of bytes that can be trimmed or unmapped in a single operation.
@@ -29,6 +29,14 @@ number of bytes that can be discarded in a single operation. Discard
29requests issued to the device must not exceed this limit. A discard_max_bytes 29requests issued to the device must not exceed this limit. A discard_max_bytes
30value of 0 means that the device does not support discard functionality. 30value of 0 means that the device does not support discard functionality.
31 31
32discard_max_bytes (RW)
33----------------------
34While discard_max_hw_bytes is the hardware limit for the device, this
35setting is the software limit. Some devices exhibit large latencies when
36large discards are issued, setting this value lower will make Linux issue
37smaller discards and potentially help reduce latencies induced by large
38discard operations.
39
32discard_zeroes_data (RO) 40discard_zeroes_data (RO)
33------------------------ 41------------------------
34When read, this file will show if the discarded block are zeroed by the 42When read, this file will show if the discarded block are zeroed by the
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 12600bfffca9..b38d8d723276 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -116,6 +116,7 @@ void blk_set_default_limits(struct queue_limits *lim)
116 lim->chunk_sectors = 0; 116 lim->chunk_sectors = 0;
117 lim->max_write_same_sectors = 0; 117 lim->max_write_same_sectors = 0;
118 lim->max_discard_sectors = 0; 118 lim->max_discard_sectors = 0;
119 lim->max_hw_discard_sectors = 0;
119 lim->discard_granularity = 0; 120 lim->discard_granularity = 0;
120 lim->discard_alignment = 0; 121 lim->discard_alignment = 0;
121 lim->discard_misaligned = 0; 122 lim->discard_misaligned = 0;
@@ -303,6 +304,7 @@ EXPORT_SYMBOL(blk_queue_chunk_sectors);
303void blk_queue_max_discard_sectors(struct request_queue *q, 304void blk_queue_max_discard_sectors(struct request_queue *q,
304 unsigned int max_discard_sectors) 305 unsigned int max_discard_sectors)
305{ 306{
307 q->limits.max_hw_discard_sectors = max_discard_sectors;
306 q->limits.max_discard_sectors = max_discard_sectors; 308 q->limits.max_discard_sectors = max_discard_sectors;
307} 309}
308EXPORT_SYMBOL(blk_queue_max_discard_sectors); 310EXPORT_SYMBOL(blk_queue_max_discard_sectors);
@@ -641,6 +643,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
641 643
642 t->max_discard_sectors = min_not_zero(t->max_discard_sectors, 644 t->max_discard_sectors = min_not_zero(t->max_discard_sectors,
643 b->max_discard_sectors); 645 b->max_discard_sectors);
646 t->max_hw_discard_sectors = min_not_zero(t->max_hw_discard_sectors,
647 b->max_hw_discard_sectors);
644 t->discard_granularity = max(t->discard_granularity, 648 t->discard_granularity = max(t->discard_granularity,
645 b->discard_granularity); 649 b->discard_granularity);
646 t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) % 650 t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) %
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 6264b382d4d1..b1f34e463c0f 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -145,12 +145,43 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag
145 return queue_var_show(q->limits.discard_granularity, page); 145 return queue_var_show(q->limits.discard_granularity, page);
146} 146}
147 147
148static ssize_t queue_discard_max_hw_show(struct request_queue *q, char *page)
149{
150 unsigned long long val;
151
152 val = q->limits.max_hw_discard_sectors << 9;
153 return sprintf(page, "%llu\n", val);
154}
155
148static ssize_t queue_discard_max_show(struct request_queue *q, char *page) 156static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
149{ 157{
150 return sprintf(page, "%llu\n", 158 return sprintf(page, "%llu\n",
151 (unsigned long long)q->limits.max_discard_sectors << 9); 159 (unsigned long long)q->limits.max_discard_sectors << 9);
152} 160}
153 161
162static ssize_t queue_discard_max_store(struct request_queue *q,
163 const char *page, size_t count)
164{
165 unsigned long max_discard;
166 ssize_t ret = queue_var_store(&max_discard, page, count);
167
168 if (ret < 0)
169 return ret;
170
171 if (max_discard & (q->limits.discard_granularity - 1))
172 return -EINVAL;
173
174 max_discard >>= 9;
175 if (max_discard > UINT_MAX)
176 return -EINVAL;
177
178 if (max_discard > q->limits.max_hw_discard_sectors)
179 max_discard = q->limits.max_hw_discard_sectors;
180
181 q->limits.max_discard_sectors = max_discard;
182 return ret;
183}
184
154static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page) 185static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page)
155{ 186{
156 return queue_var_show(queue_discard_zeroes_data(q), page); 187 return queue_var_show(queue_discard_zeroes_data(q), page);
@@ -360,9 +391,15 @@ static struct queue_sysfs_entry queue_discard_granularity_entry = {
360 .show = queue_discard_granularity_show, 391 .show = queue_discard_granularity_show,
361}; 392};
362 393
394static struct queue_sysfs_entry queue_discard_max_hw_entry = {
395 .attr = {.name = "discard_max_hw_bytes", .mode = S_IRUGO },
396 .show = queue_discard_max_hw_show,
397};
398
363static struct queue_sysfs_entry queue_discard_max_entry = { 399static struct queue_sysfs_entry queue_discard_max_entry = {
364 .attr = {.name = "discard_max_bytes", .mode = S_IRUGO }, 400 .attr = {.name = "discard_max_bytes", .mode = S_IRUGO | S_IWUSR },
365 .show = queue_discard_max_show, 401 .show = queue_discard_max_show,
402 .store = queue_discard_max_store,
366}; 403};
367 404
368static struct queue_sysfs_entry queue_discard_zeroes_data_entry = { 405static struct queue_sysfs_entry queue_discard_zeroes_data_entry = {
@@ -421,6 +458,7 @@ static struct attribute *default_attrs[] = {
421 &queue_io_opt_entry.attr, 458 &queue_io_opt_entry.attr,
422 &queue_discard_granularity_entry.attr, 459 &queue_discard_granularity_entry.attr,
423 &queue_discard_max_entry.attr, 460 &queue_discard_max_entry.attr,
461 &queue_discard_max_hw_entry.attr,
424 &queue_discard_zeroes_data_entry.attr, 462 &queue_discard_zeroes_data_entry.attr,
425 &queue_write_same_max_entry.attr, 463 &queue_write_same_max_entry.attr,
426 &queue_nonrot_entry.attr, 464 &queue_nonrot_entry.attr,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index d4068c17d0df..243f29e779ec 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -268,6 +268,7 @@ struct queue_limits {
268 unsigned int io_min; 268 unsigned int io_min;
269 unsigned int io_opt; 269 unsigned int io_opt;
270 unsigned int max_discard_sectors; 270 unsigned int max_discard_sectors;
271 unsigned int max_hw_discard_sectors;
271 unsigned int max_write_same_sectors; 272 unsigned int max_write_same_sectors;
272 unsigned int discard_granularity; 273 unsigned int discard_granularity;
273 unsigned int discard_alignment; 274 unsigned int discard_alignment;