aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--block/blk-settings.c46
-rw-r--r--block/blk-sysfs.c22
-rw-r--r--block/genhd.c12
-rw-r--r--fs/partitions/check.c12
-rw-r--r--include/linux/blkdev.h18
-rw-r--r--include/linux/genhd.h1
6 files changed, 101 insertions, 10 deletions
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 66d4aa8799b..7f986cafacd 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 8a6d81afb28..3147145edc1 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 517e4332cb3..b11a4ad7d57 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,
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 7b685e10cba..64bc8998ac9 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -226,6 +226,13 @@ ssize_t part_alignment_offset_show(struct device *dev,
226 return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset); 226 return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset);
227} 227}
228 228
229ssize_t part_discard_alignment_show(struct device *dev,
230 struct device_attribute *attr, char *buf)
231{
232 struct hd_struct *p = dev_to_part(dev);
233 return sprintf(buf, "%u\n", p->discard_alignment);
234}
235
229ssize_t part_stat_show(struct device *dev, 236ssize_t part_stat_show(struct device *dev,
230 struct device_attribute *attr, char *buf) 237 struct device_attribute *attr, char *buf)
231{ 238{
@@ -288,6 +295,8 @@ static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL);
288static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); 295static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
289static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); 296static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
290static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); 297static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
298static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show,
299 NULL);
291static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); 300static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
292static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); 301static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
293#ifdef CONFIG_FAIL_MAKE_REQUEST 302#ifdef CONFIG_FAIL_MAKE_REQUEST
@@ -300,6 +309,7 @@ static struct attribute *part_attrs[] = {
300 &dev_attr_start.attr, 309 &dev_attr_start.attr,
301 &dev_attr_size.attr, 310 &dev_attr_size.attr,
302 &dev_attr_alignment_offset.attr, 311 &dev_attr_alignment_offset.attr,
312 &dev_attr_discard_alignment.attr,
303 &dev_attr_stat.attr, 313 &dev_attr_stat.attr,
304 &dev_attr_inflight.attr, 314 &dev_attr_inflight.attr,
305#ifdef CONFIG_FAIL_MAKE_REQUEST 315#ifdef CONFIG_FAIL_MAKE_REQUEST
@@ -403,6 +413,8 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
403 413
404 p->start_sect = start; 414 p->start_sect = start;
405 p->alignment_offset = queue_sector_alignment_offset(disk->queue, start); 415 p->alignment_offset = queue_sector_alignment_offset(disk->queue, start);
416 p->discard_alignment = queue_sector_discard_alignment(disk->queue,
417 start);
406 p->nr_sects = len; 418 p->nr_sects = len;
407 p->partno = partno; 419 p->partno = partno;
408 p->policy = get_disk_ro(disk); 420 p->policy = get_disk_ro(disk);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 39c601f783a..1cc02972fbe 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -312,12 +312,15 @@ struct queue_limits {
312 unsigned int io_min; 312 unsigned int io_min;
313 unsigned int io_opt; 313 unsigned int io_opt;
314 unsigned int max_discard_sectors; 314 unsigned int max_discard_sectors;
315 unsigned int discard_granularity;
316 unsigned int discard_alignment;
315 317
316 unsigned short logical_block_size; 318 unsigned short logical_block_size;
317 unsigned short max_hw_segments; 319 unsigned short max_hw_segments;
318 unsigned short max_phys_segments; 320 unsigned short max_phys_segments;
319 321
320 unsigned char misaligned; 322 unsigned char misaligned;
323 unsigned char discard_misaligned;
321 unsigned char no_cluster; 324 unsigned char no_cluster;
322}; 325};
323 326
@@ -1121,6 +1124,21 @@ static inline int bdev_alignment_offset(struct block_device *bdev)
1121 return q->limits.alignment_offset; 1124 return q->limits.alignment_offset;
1122} 1125}
1123 1126
1127static inline int queue_discard_alignment(struct request_queue *q)
1128{
1129 if (q->limits.discard_misaligned)
1130 return -1;
1131
1132 return q->limits.discard_alignment;
1133}
1134
1135static inline int queue_sector_discard_alignment(struct request_queue *q,
1136 sector_t sector)
1137{
1138 return ((sector << 9) - q->limits.discard_alignment)
1139 & (q->limits.discard_granularity - 1);
1140}
1141
1124static inline int queue_dma_alignment(struct request_queue *q) 1142static inline int queue_dma_alignment(struct request_queue *q)
1125{ 1143{
1126 return q ? q->dma_alignment : 511; 1144 return q ? q->dma_alignment : 511;
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 297df45ffd0..c6c0c41af35 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -91,6 +91,7 @@ struct hd_struct {
91 sector_t start_sect; 91 sector_t start_sect;
92 sector_t nr_sects; 92 sector_t nr_sects;
93 sector_t alignment_offset; 93 sector_t alignment_offset;
94 unsigned int discard_alignment;
94 struct device __dev; 95 struct device __dev;
95 struct kobject *holder_dir; 96 struct kobject *holder_dir;
96 int policy, partno; 97 int policy, partno;