Skip to content

Commit 2361db8

Browse files
committed
libnvdimm: Notify disk drivers to revalidate region read-only
Previous kernels allowed the BLKROSET to override the disk's read-only status. With that situation fixed the pmem driver needs to rely on notification events to reevaluate the disk read-only status after the host region has been marked read-write. Recall that when libnvdimm determines that the persistent memory has lost persistence (for example lack of energy to flush from DRAM to FLASH on an NVDIMM-N device) it marks the region read-only, but that state can be overridden by the user via: echo 0 > /sys/bus/nd/devices/regionX/read_only ...to date there is no notification that the region has restored persistence, so the user override is the only recovery. Fixes: 52f019d ("block: add a hard-readonly flag to struct gendisk") Reported-by: kernel test robot <lkp@intel.com> Reported-by: Vishal Verma <vishal.l.verma@intel.com> Tested-by: Vishal Verma <vishal.l.verma@intel.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Cc: Christoph Hellwig <hch@lst.de> Cc: Ming Lei <ming.lei@redhat.com> Cc: Martin K. Petersen <martin.petersen@oracle.com> Cc: Hannes Reinecke <hare@suse.de> Cc: Jens Axboe <axboe@kernel.dk> Link: https://lore.kernel.org/r/161534060720.528671.2341213328968989192.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent e49d033 commit 2361db8

File tree

4 files changed

+47
-12
lines changed

4 files changed

+47
-12
lines changed

drivers/nvdimm/bus.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -631,16 +631,14 @@ void nvdimm_check_and_set_ro(struct gendisk *disk)
631631
struct nd_region *nd_region = to_nd_region(dev->parent);
632632
int disk_ro = get_disk_ro(disk);
633633

634-
/*
635-
* Upgrade to read-only if the region is read-only preserve as
636-
* read-only if the disk is already read-only.
637-
*/
638-
if (disk_ro || nd_region->ro == disk_ro)
634+
/* catch the disk up with the region ro state */
635+
if (disk_ro == nd_region->ro)
639636
return;
640637

641-
dev_info(dev, "%s read-only, marking %s read-only\n",
642-
dev_name(&nd_region->dev), disk->disk_name);
643-
set_disk_ro(disk, 1);
638+
dev_info(dev, "%s read-%s, marking %s read-%s\n",
639+
dev_name(&nd_region->dev), nd_region->ro ? "only" : "write",
640+
disk->disk_name, nd_region->ro ? "only" : "write");
641+
set_disk_ro(disk, nd_region->ro);
644642
}
645643
EXPORT_SYMBOL(nvdimm_check_and_set_ro);
646644

drivers/nvdimm/pmem.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/mm.h>
2727
#include <asm/cacheflush.h>
2828
#include "pmem.h"
29+
#include "btt.h"
2930
#include "pfn.h"
3031
#include "nd.h"
3132

@@ -585,7 +586,7 @@ static void nd_pmem_shutdown(struct device *dev)
585586
nvdimm_flush(to_nd_region(dev->parent), NULL);
586587
}
587588

588-
static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
589+
static void pmem_revalidate_poison(struct device *dev)
589590
{
590591
struct nd_region *nd_region;
591592
resource_size_t offset = 0, end_trunc = 0;
@@ -595,9 +596,6 @@ static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
595596
struct range range;
596597
struct kernfs_node *bb_state;
597598

598-
if (event != NVDIMM_REVALIDATE_POISON)
599-
return;
600-
601599
if (is_nd_btt(dev)) {
602600
struct nd_btt *nd_btt = to_nd_btt(dev);
603601

@@ -635,6 +633,37 @@ static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
635633
sysfs_notify_dirent(bb_state);
636634
}
637635

636+
static void pmem_revalidate_region(struct device *dev)
637+
{
638+
struct pmem_device *pmem;
639+
640+
if (is_nd_btt(dev)) {
641+
struct nd_btt *nd_btt = to_nd_btt(dev);
642+
struct btt *btt = nd_btt->btt;
643+
644+
nvdimm_check_and_set_ro(btt->btt_disk);
645+
return;
646+
}
647+
648+
pmem = dev_get_drvdata(dev);
649+
nvdimm_check_and_set_ro(pmem->disk);
650+
}
651+
652+
static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
653+
{
654+
switch (event) {
655+
case NVDIMM_REVALIDATE_POISON:
656+
pmem_revalidate_poison(dev);
657+
break;
658+
case NVDIMM_REVALIDATE_REGION:
659+
pmem_revalidate_region(dev);
660+
break;
661+
default:
662+
dev_WARN_ONCE(dev, 1, "notify: unknown event: %d\n", event);
663+
break;
664+
}
665+
}
666+
638667
MODULE_ALIAS("pmem");
639668
MODULE_ALIAS_ND_DEVICE(ND_DEVICE_NAMESPACE_IO);
640669
MODULE_ALIAS_ND_DEVICE(ND_DEVICE_NAMESPACE_PMEM);

drivers/nvdimm/region_devs.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,12 @@ static ssize_t read_only_show(struct device *dev,
518518
return sprintf(buf, "%d\n", nd_region->ro);
519519
}
520520

521+
static int revalidate_read_only(struct device *dev, void *data)
522+
{
523+
nd_device_notify(dev, NVDIMM_REVALIDATE_REGION);
524+
return 0;
525+
}
526+
521527
static ssize_t read_only_store(struct device *dev,
522528
struct device_attribute *attr, const char *buf, size_t len)
523529
{
@@ -529,6 +535,7 @@ static ssize_t read_only_store(struct device *dev,
529535
return rc;
530536

531537
nd_region->ro = ro;
538+
device_for_each_child(dev, NULL, revalidate_read_only);
532539
return len;
533540
}
534541
static DEVICE_ATTR_RW(read_only);

include/linux/nd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
enum nvdimm_event {
1313
NVDIMM_REVALIDATE_POISON,
14+
NVDIMM_REVALIDATE_REGION,
1415
};
1516

1617
enum nvdimm_claim_class {

0 commit comments

Comments
 (0)