summaryrefslogtreecommitdiffstats
path: root/block/genhd.c
diff options
context:
space:
mode:
authorVishal Verma <vishal.l.verma@intel.com>2016-01-09 11:36:51 -0500
committerDan Williams <dan.j.williams@intel.com>2016-01-09 11:36:51 -0500
commit99e6608c9e7414ae4f2168df8bf8fae3eb49e41f (patch)
tree20ab40762557164e1358a960782410c33bd4f423 /block/genhd.c
parent9e0e252a048b0ba5066f0dc15c3b2468ffe5c422 (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.c76
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
509int 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}
517EXPORT_SYMBOL(disk_alloc_badblocks);
518
508static void register_disk(struct gendisk *disk) 519static 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}
672EXPORT_SYMBOL(del_gendisk); 688EXPORT_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 */
694int 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}
702EXPORT_SYMBOL(disk_check_badblocks);
703
704int 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}
711EXPORT_SYMBOL(disk_set_badblocks);
712
713int 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}
720EXPORT_SYMBOL(disk_clear_badblocks);
721
722/* sysfs access to bad-blocks list. */
723static 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
735static 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,
989static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); 1062static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
990static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); 1063static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
991static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); 1064static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
1065static 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
993static struct device_attribute dev_attr_fail = 1068static 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