aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2009-11-10 05:50:21 -0500
committerJens Axboe <jens.axboe@oracle.com>2009-11-10 05:50:21 -0500
commit86b37281411cf1e9bc0a6b5406c45edb7bd9ea5d (patch)
tree729db57dd52054af1bc16b4afb131093dfc9d255 /block
parentcf7c25cf91f632a3528669fc0876e1fc8355ff9b (diff)
block: Expose discard granularity
While SSDs track block usage on a per-sector basis, RAID arrays often have allocation blocks that are bigger. Allow the discard granularity and alignment to be set and teach the topology stacking logic how to handle them. Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-settings.c46
-rw-r--r--block/blk-sysfs.c22
-rw-r--r--block/genhd.c12
3 files changed, 70 insertions, 10 deletions
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 66d4aa8799b7..7f986cafacd5 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -96,7 +96,10 @@ void blk_set_default_limits(struct queue_limits *lim)
96 lim->max_segment_size = MAX_SEGMENT_SIZE; 96 lim->max_segment_size = MAX_SEGMENT_SIZE;
97 lim->max_sectors = BLK_DEF_MAX_SECTORS; 97 lim->max_sectors = BLK_DEF_MAX_SECTORS;
98 lim->max_hw_sectors = INT_MAX; 98 lim->max_hw_sectors = INT_MAX;
99 lim->max_discard_sectors = SAFE_MAX_SECTORS; 99 lim->max_discard_sectors = 0;
100 lim->discard_granularity = 0;
101 lim->discard_alignment = 0;
102 lim->discard_misaligned = 0;
100 lim->logical_block_size = lim->physical_block_size = lim->io_min = 512; 103 lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
101 lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT); 104 lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT);
102 lim->alignment_offset = 0; 105 lim->alignment_offset = 0;
@@ -488,6 +491,16 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
488} 491}
489EXPORT_SYMBOL(blk_queue_stack_limits); 492EXPORT_SYMBOL(blk_queue_stack_limits);
490 493
494static unsigned int lcm(unsigned int a, unsigned int b)
495{
496 if (a && b)
497 return (a * b) / gcd(a, b);
498 else if (b)
499 return b;
500
501 return a;
502}
503
491/** 504/**
492 * blk_stack_limits - adjust queue_limits for stacked devices 505 * blk_stack_limits - adjust queue_limits for stacked devices
493 * @t: the stacking driver limits (top) 506 * @t: the stacking driver limits (top)
@@ -502,6 +515,10 @@ EXPORT_SYMBOL(blk_queue_stack_limits);
502int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, 515int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
503 sector_t offset) 516 sector_t offset)
504{ 517{
518 int ret;
519
520 ret = 0;
521
505 t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); 522 t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
506 t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); 523 t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
507 t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn); 524 t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn);
@@ -531,7 +548,13 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
531 if (offset && 548 if (offset &&
532 (offset & (b->physical_block_size - 1)) != b->alignment_offset) { 549 (offset & (b->physical_block_size - 1)) != b->alignment_offset) {
533 t->misaligned = 1; 550 t->misaligned = 1;
534 return -1; 551 ret = -1;
552 }
553
554 if (offset &&
555 (offset & (b->discard_granularity - 1)) != b->discard_alignment) {
556 t->discard_misaligned = 1;
557 ret = -1;
535 } 558 }
536 559
537 /* If top has no alignment offset, inherit from bottom */ 560 /* If top has no alignment offset, inherit from bottom */
@@ -539,23 +562,26 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
539 t->alignment_offset = 562 t->alignment_offset =
540 b->alignment_offset & (b->physical_block_size - 1); 563 b->alignment_offset & (b->physical_block_size - 1);
541 564
565 if (!t->discard_alignment)
566 t->discard_alignment =
567 b->discard_alignment & (b->discard_granularity - 1);
568
542 /* Top device aligned on logical block boundary? */ 569 /* Top device aligned on logical block boundary? */
543 if (t->alignment_offset & (t->logical_block_size - 1)) { 570 if (t->alignment_offset & (t->logical_block_size - 1)) {
544 t->misaligned = 1; 571 t->misaligned = 1;
545 return -1; 572 ret = -1;
546 } 573 }
547 574
548 /* Find lcm() of optimal I/O size */ 575 /* Find lcm() of optimal I/O size and granularity */
549 if (t->io_opt && b->io_opt) 576 t->io_opt = lcm(t->io_opt, b->io_opt);
550 t->io_opt = (t->io_opt * b->io_opt) / gcd(t->io_opt, b->io_opt); 577 t->discard_granularity = lcm(t->discard_granularity,
551 else if (b->io_opt) 578 b->discard_granularity);
552 t->io_opt = b->io_opt;
553 579
554 /* Verify that optimal I/O size is a multiple of io_min */ 580 /* Verify that optimal I/O size is a multiple of io_min */
555 if (t->io_min && t->io_opt % t->io_min) 581 if (t->io_min && t->io_opt % t->io_min)
556 return -1; 582 ret = -1;
557 583
558 return 0; 584 return ret;
559} 585}
560EXPORT_SYMBOL(blk_stack_limits); 586EXPORT_SYMBOL(blk_stack_limits);
561 587
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 8a6d81afb284..3147145edc15 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -126,6 +126,16 @@ static ssize_t queue_io_opt_show(struct request_queue *q, char *page)
126 return queue_var_show(queue_io_opt(q), page); 126 return queue_var_show(queue_io_opt(q), page);
127} 127}
128 128
129static ssize_t queue_discard_granularity_show(struct request_queue *q, char *page)
130{
131 return queue_var_show(q->limits.discard_granularity, page);
132}
133
134static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
135{
136 return queue_var_show(q->limits.max_discard_sectors << 9, page);
137}
138
129static ssize_t 139static ssize_t
130queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) 140queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
131{ 141{
@@ -293,6 +303,16 @@ static struct queue_sysfs_entry queue_io_opt_entry = {
293 .show = queue_io_opt_show, 303 .show = queue_io_opt_show,
294}; 304};
295 305
306static struct queue_sysfs_entry queue_discard_granularity_entry = {
307 .attr = {.name = "discard_granularity", .mode = S_IRUGO },
308 .show = queue_discard_granularity_show,
309};
310
311static struct queue_sysfs_entry queue_discard_max_entry = {
312 .attr = {.name = "discard_max_bytes", .mode = S_IRUGO },
313 .show = queue_discard_max_show,
314};
315
296static struct queue_sysfs_entry queue_nonrot_entry = { 316static struct queue_sysfs_entry queue_nonrot_entry = {
297 .attr = {.name = "rotational", .mode = S_IRUGO | S_IWUSR }, 317 .attr = {.name = "rotational", .mode = S_IRUGO | S_IWUSR },
298 .show = queue_nonrot_show, 318 .show = queue_nonrot_show,
@@ -328,6 +348,8 @@ static struct attribute *default_attrs[] = {
328 &queue_physical_block_size_entry.attr, 348 &queue_physical_block_size_entry.attr,
329 &queue_io_min_entry.attr, 349 &queue_io_min_entry.attr,
330 &queue_io_opt_entry.attr, 350 &queue_io_opt_entry.attr,
351 &queue_discard_granularity_entry.attr,
352 &queue_discard_max_entry.attr,
331 &queue_nonrot_entry.attr, 353 &queue_nonrot_entry.attr,
332 &queue_nomerges_entry.attr, 354 &queue_nomerges_entry.attr,
333 &queue_rq_affinity_entry.attr, 355 &queue_rq_affinity_entry.attr,
diff --git a/block/genhd.c b/block/genhd.c
index 517e4332cb37..b11a4ad7d571 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -861,12 +861,23 @@ static ssize_t disk_alignment_offset_show(struct device *dev,
861 return sprintf(buf, "%d\n", queue_alignment_offset(disk->queue)); 861 return sprintf(buf, "%d\n", queue_alignment_offset(disk->queue));
862} 862}
863 863
864static ssize_t disk_discard_alignment_show(struct device *dev,
865 struct device_attribute *attr,
866 char *buf)
867{
868 struct gendisk *disk = dev_to_disk(dev);
869
870 return sprintf(buf, "%u\n", queue_discard_alignment(disk->queue));
871}
872
864static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); 873static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
865static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); 874static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
866static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); 875static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
867static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); 876static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL);
868static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); 877static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
869static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL); 878static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL);
879static DEVICE_ATTR(discard_alignment, S_IRUGO, disk_discard_alignment_show,
880 NULL);
870static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); 881static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
871static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); 882static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
872static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); 883static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
@@ -887,6 +898,7 @@ static struct attribute *disk_attrs[] = {
887 &dev_attr_ro.attr, 898 &dev_attr_ro.attr,
888 &dev_attr_size.attr, 899 &dev_attr_size.attr,
889 &dev_attr_alignment_offset.attr, 900 &dev_attr_alignment_offset.attr,
901 &dev_attr_discard_alignment.attr,
890 &dev_attr_capability.attr, 902 &dev_attr_capability.attr,
891 &dev_attr_stat.attr, 903 &dev_attr_stat.attr,
892 &dev_attr_inflight.attr, 904 &dev_attr_inflight.attr,