diff options
-rw-r--r-- | block/blk-settings.c | 46 | ||||
-rw-r--r-- | block/blk-sysfs.c | 22 | ||||
-rw-r--r-- | block/genhd.c | 12 | ||||
-rw-r--r-- | fs/partitions/check.c | 12 | ||||
-rw-r--r-- | include/linux/blkdev.h | 18 | ||||
-rw-r--r-- | include/linux/genhd.h | 1 |
6 files changed, 101 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 | } |
489 | EXPORT_SYMBOL(blk_queue_stack_limits); | 492 | EXPORT_SYMBOL(blk_queue_stack_limits); |
490 | 493 | ||
494 | static 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); | |||
502 | int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, | 515 | int 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 | } |
560 | EXPORT_SYMBOL(blk_stack_limits); | 586 | EXPORT_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 | ||
129 | static 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 | |||
134 | static 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 | |||
129 | static ssize_t | 139 | static ssize_t |
130 | queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) | 140 | queue_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 | ||
306 | static struct queue_sysfs_entry queue_discard_granularity_entry = { | ||
307 | .attr = {.name = "discard_granularity", .mode = S_IRUGO }, | ||
308 | .show = queue_discard_granularity_show, | ||
309 | }; | ||
310 | |||
311 | static 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 | |||
296 | static struct queue_sysfs_entry queue_nonrot_entry = { | 316 | static 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 | ||
864 | static 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 | |||
864 | static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); | 873 | static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); |
865 | static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); | 874 | static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); |
866 | static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); | 875 | static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); |
867 | static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); | 876 | static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); |
868 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); | 877 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); |
869 | static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL); | 878 | static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL); |
879 | static DEVICE_ATTR(discard_alignment, S_IRUGO, disk_discard_alignment_show, | ||
880 | NULL); | ||
870 | static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); | 881 | static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); |
871 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); | 882 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); |
872 | static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); | 883 | static 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 7b685e10cbad..64bc8998ac9a 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 | ||
229 | ssize_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 | |||
229 | ssize_t part_stat_show(struct device *dev, | 236 | ssize_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); | |||
288 | static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); | 295 | static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); |
289 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); | 296 | static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); |
290 | static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); | 297 | static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); |
298 | static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show, | ||
299 | NULL); | ||
291 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); | 300 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); |
292 | static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); | 301 | static 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 39c601f783a0..1cc02972fbe2 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 | ||
1127 | static 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 | |||
1135 | static 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 | |||
1124 | static inline int queue_dma_alignment(struct request_queue *q) | 1142 | static 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 297df45ffd0a..c6c0c41af35f 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; |