diff options
author | Vishal Verma <vishal.l.verma@intel.com> | 2016-01-09 11:36:51 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2016-01-09 11:36:51 -0500 |
commit | 99e6608c9e7414ae4f2168df8bf8fae3eb49e41f (patch) | |
tree | 20ab40762557164e1358a960782410c33bd4f423 /block/genhd.c | |
parent | 9e0e252a048b0ba5066f0dc15c3b2468ffe5c422 (diff) |
block: Add badblock management for gendisks
NVDIMM devices, which can behave more like DRAM rather than block
devices, may develop bad cache lines, or 'poison'. A block device
exposed by the pmem driver can then consume poison via a read (or
write), and cause a machine check. On platforms without machine
check recovery features, this would mean a crash.
The block device maintaining a runtime list of all known sectors that
have poison can directly avoid this, and also provide a path forward
to enable proper handling/recovery for DAX faults on such a device.
Use the new badblock management interfaces to add a badblocks list to
gendisks.
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'block/genhd.c')
-rw-r--r-- | block/genhd.c | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/block/genhd.c b/block/genhd.c index 1a971bebbbfe..88579cf373b8 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/idr.h> | 20 | #include <linux/idr.h> |
21 | #include <linux/log2.h> | 21 | #include <linux/log2.h> |
22 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
23 | #include <linux/badblocks.h> | ||
23 | 24 | ||
24 | #include "blk.h" | 25 | #include "blk.h" |
25 | 26 | ||
@@ -505,6 +506,16 @@ static int exact_lock(dev_t devt, void *data) | |||
505 | return 0; | 506 | return 0; |
506 | } | 507 | } |
507 | 508 | ||
509 | int disk_alloc_badblocks(struct gendisk *disk) | ||
510 | { | ||
511 | disk->bb = kzalloc(sizeof(*(disk->bb)), GFP_KERNEL); | ||
512 | if (!disk->bb) | ||
513 | return -ENOMEM; | ||
514 | |||
515 | return badblocks_init(disk->bb, 1); | ||
516 | } | ||
517 | EXPORT_SYMBOL(disk_alloc_badblocks); | ||
518 | |||
508 | static void register_disk(struct gendisk *disk) | 519 | static void register_disk(struct gendisk *disk) |
509 | { | 520 | { |
510 | struct device *ddev = disk_to_dev(disk); | 521 | struct device *ddev = disk_to_dev(disk); |
@@ -659,6 +670,11 @@ void del_gendisk(struct gendisk *disk) | |||
659 | blk_unregister_queue(disk); | 670 | blk_unregister_queue(disk); |
660 | blk_unregister_region(disk_devt(disk), disk->minors); | 671 | blk_unregister_region(disk_devt(disk), disk->minors); |
661 | 672 | ||
673 | if (disk->bb) { | ||
674 | badblocks_free(disk->bb); | ||
675 | kfree(disk->bb); | ||
676 | } | ||
677 | |||
662 | part_stat_set_all(&disk->part0, 0); | 678 | part_stat_set_all(&disk->part0, 0); |
663 | disk->part0.stamp = 0; | 679 | disk->part0.stamp = 0; |
664 | 680 | ||
@@ -671,6 +687,63 @@ void del_gendisk(struct gendisk *disk) | |||
671 | } | 687 | } |
672 | EXPORT_SYMBOL(del_gendisk); | 688 | EXPORT_SYMBOL(del_gendisk); |
673 | 689 | ||
690 | /* | ||
691 | * The gendisk usage of badblocks does not track acknowledgements for | ||
692 | * badblocks. We always assume they are acknowledged. | ||
693 | */ | ||
694 | int disk_check_badblocks(struct gendisk *disk, sector_t s, int sectors, | ||
695 | sector_t *first_bad, int *bad_sectors) | ||
696 | { | ||
697 | if (!disk->bb) | ||
698 | return 0; | ||
699 | |||
700 | return badblocks_check(disk->bb, s, sectors, first_bad, bad_sectors); | ||
701 | } | ||
702 | EXPORT_SYMBOL(disk_check_badblocks); | ||
703 | |||
704 | int disk_set_badblocks(struct gendisk *disk, sector_t s, int sectors) | ||
705 | { | ||
706 | if (!disk->bb) | ||
707 | return 0; | ||
708 | |||
709 | return badblocks_set(disk->bb, s, sectors, 1); | ||
710 | } | ||
711 | EXPORT_SYMBOL(disk_set_badblocks); | ||
712 | |||
713 | int disk_clear_badblocks(struct gendisk *disk, sector_t s, int sectors) | ||
714 | { | ||
715 | if (!disk->bb) | ||
716 | return 0; | ||
717 | |||
718 | return badblocks_clear(disk->bb, s, sectors); | ||
719 | } | ||
720 | EXPORT_SYMBOL(disk_clear_badblocks); | ||
721 | |||
722 | /* sysfs access to bad-blocks list. */ | ||
723 | static ssize_t disk_badblocks_show(struct device *dev, | ||
724 | struct device_attribute *attr, | ||
725 | char *page) | ||
726 | { | ||
727 | struct gendisk *disk = dev_to_disk(dev); | ||
728 | |||
729 | if (!disk->bb) | ||
730 | return sprintf(page, "\n"); | ||
731 | |||
732 | return badblocks_show(disk->bb, page, 0); | ||
733 | } | ||
734 | |||
735 | static ssize_t disk_badblocks_store(struct device *dev, | ||
736 | struct device_attribute *attr, | ||
737 | const char *page, size_t len) | ||
738 | { | ||
739 | struct gendisk *disk = dev_to_disk(dev); | ||
740 | |||
741 | if (!disk->bb) | ||
742 | return -ENXIO; | ||
743 | |||
744 | return badblocks_store(disk->bb, page, len, 0); | ||
745 | } | ||
746 | |||
674 | /** | 747 | /** |
675 | * get_gendisk - get partitioning information for a given device | 748 | * get_gendisk - get partitioning information for a given device |
676 | * @devt: device to get partitioning information for | 749 | * @devt: device to get partitioning information for |
@@ -989,6 +1062,8 @@ static DEVICE_ATTR(discard_alignment, S_IRUGO, disk_discard_alignment_show, | |||
989 | static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); | 1062 | static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); |
990 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); | 1063 | static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); |
991 | static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); | 1064 | static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); |
1065 | static DEVICE_ATTR(badblocks, S_IRUGO | S_IWUSR, disk_badblocks_show, | ||
1066 | disk_badblocks_store); | ||
992 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 1067 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
993 | static struct device_attribute dev_attr_fail = | 1068 | static struct device_attribute dev_attr_fail = |
994 | __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); | 1069 | __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); |
@@ -1010,6 +1085,7 @@ static struct attribute *disk_attrs[] = { | |||
1010 | &dev_attr_capability.attr, | 1085 | &dev_attr_capability.attr, |
1011 | &dev_attr_stat.attr, | 1086 | &dev_attr_stat.attr, |
1012 | &dev_attr_inflight.attr, | 1087 | &dev_attr_inflight.attr, |
1088 | &dev_attr_badblocks.attr, | ||
1013 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 1089 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
1014 | &dev_attr_fail.attr, | 1090 | &dev_attr_fail.attr, |
1015 | #endif | 1091 | #endif |