Skip to content

Commit 0034af0

Browse files
committed
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 <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 2bb4cd5 commit 0034af0

File tree

4 files changed

+53
-2
lines changed

4 files changed

+53
-2
lines changed

Documentation/block/queue-sysfs.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ This shows the size of internal allocation of the device in bytes, if
2020
reported by the device. A value of '0' means device does not support
2121
the discard functionality.
2222

23-
discard_max_bytes (RO)
23+
discard_max_hw_bytes (RO)
2424
----------------------
2525
Devices that support discard functionality may have internal limits on
2626
the 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
2929
requests issued to the device must not exceed this limit. A discard_max_bytes
3030
value of 0 means that the device does not support discard functionality.
3131

32+
discard_max_bytes (RW)
33+
----------------------
34+
While discard_max_hw_bytes is the hardware limit for the device, this
35+
setting is the software limit. Some devices exhibit large latencies when
36+
large discards are issued, setting this value lower will make Linux issue
37+
smaller discards and potentially help reduce latencies induced by large
38+
discard operations.
39+
3240
discard_zeroes_data (RO)
3341
------------------------
3442
When read, this file will show if the discarded block are zeroed by the

block/blk-settings.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ void blk_set_default_limits(struct queue_limits *lim)
116116
lim->chunk_sectors = 0;
117117
lim->max_write_same_sectors = 0;
118118
lim->max_discard_sectors = 0;
119+
lim->max_hw_discard_sectors = 0;
119120
lim->discard_granularity = 0;
120121
lim->discard_alignment = 0;
121122
lim->discard_misaligned = 0;
@@ -303,6 +304,7 @@ EXPORT_SYMBOL(blk_queue_chunk_sectors);
303304
void blk_queue_max_discard_sectors(struct request_queue *q,
304305
unsigned int max_discard_sectors)
305306
{
307+
q->limits.max_hw_discard_sectors = max_discard_sectors;
306308
q->limits.max_discard_sectors = max_discard_sectors;
307309
}
308310
EXPORT_SYMBOL(blk_queue_max_discard_sectors);
@@ -641,6 +643,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
641643

642644
t->max_discard_sectors = min_not_zero(t->max_discard_sectors,
643645
b->max_discard_sectors);
646+
t->max_hw_discard_sectors = min_not_zero(t->max_hw_discard_sectors,
647+
b->max_hw_discard_sectors);
644648
t->discard_granularity = max(t->discard_granularity,
645649
b->discard_granularity);
646650
t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) %

block/blk-sysfs.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,43 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag
145145
return queue_var_show(q->limits.discard_granularity, page);
146146
}
147147

148+
static 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+
148156
static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
149157
{
150158
return sprintf(page, "%llu\n",
151159
(unsigned long long)q->limits.max_discard_sectors << 9);
152160
}
153161

162+
static 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+
154185
static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page)
155186
{
156187
return queue_var_show(queue_discard_zeroes_data(q), page);
@@ -360,9 +391,15 @@ static struct queue_sysfs_entry queue_discard_granularity_entry = {
360391
.show = queue_discard_granularity_show,
361392
};
362393

394+
static 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+
363399
static 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 },
365401
.show = queue_discard_max_show,
402+
.store = queue_discard_max_store,
366403
};
367404

368405
static struct queue_sysfs_entry queue_discard_zeroes_data_entry = {
@@ -421,6 +458,7 @@ static struct attribute *default_attrs[] = {
421458
&queue_io_opt_entry.attr,
422459
&queue_discard_granularity_entry.attr,
423460
&queue_discard_max_entry.attr,
461+
&queue_discard_max_hw_entry.attr,
424462
&queue_discard_zeroes_data_entry.attr,
425463
&queue_write_same_max_entry.attr,
426464
&queue_nonrot_entry.attr,

include/linux/blkdev.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ struct queue_limits {
268268
unsigned int io_min;
269269
unsigned int io_opt;
270270
unsigned int max_discard_sectors;
271+
unsigned int max_hw_discard_sectors;
271272
unsigned int max_write_same_sectors;
272273
unsigned int discard_granularity;
273274
unsigned int discard_alignment;

0 commit comments

Comments
 (0)