[PATCH] libnvdimm, btt: convert some info messages to warn/err
by Vishal Verma
Some critical messages such as IO errors, metadata failures were printed
with dev_info. Make them louder by upgrading them to dev_warn or
dev_error.
Signed-off-by: Vishal Verma <vishal.l.verma(a)intel.com>
---
drivers/nvdimm/btt.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index 4e56e72..2af329d 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -323,7 +323,7 @@ static int btt_log_read(struct arena_info *arena, u32 lane,
old_ent = btt_log_get_old(log);
if (old_ent < 0 || old_ent > 1) {
- dev_info(to_dev(arena),
+ dev_err(to_dev(arena),
"log corruption (%d): lane %d seq [%d, %d]\n",
old_ent, lane, log[0].seq, log[1].seq);
/* TODO set error state? */
@@ -684,7 +684,7 @@ static int discover_arenas(struct btt *btt)
dev_info(to_dev(arena), "No existing arenas\n");
goto out;
} else {
- dev_info(to_dev(arena),
+ dev_err(to_dev(arena),
"Found corrupted metadata!\n");
ret = -ENODEV;
goto out;
@@ -1227,7 +1227,7 @@ static blk_qc_t btt_make_request(struct request_queue *q, struct bio *bio)
err = btt_do_bvec(btt, bip, bvec.bv_page, len, bvec.bv_offset,
op_is_write(bio_op(bio)), iter.bi_sector);
if (err) {
- dev_info(&btt->nd_btt->dev,
+ dev_err(&btt->nd_btt->dev,
"io error in %s sector %lld, len %d,\n",
(op_is_write(bio_op(bio))) ? "WRITE" :
"READ",
@@ -1373,7 +1373,7 @@ static struct btt *btt_init(struct nd_btt *nd_btt, unsigned long long rawsize,
}
if (btt->init_state != INIT_READY && nd_region->ro) {
- dev_info(dev, "%s is read-only, unable to init btt metadata\n",
+ dev_warn(dev, "%s is read-only, unable to init btt metadata\n",
dev_name(&nd_region->dev));
return NULL;
} else if (btt->init_state != INIT_READY) {
--
2.9.3
5 years, 1 month
[PATCH] check-namespace: Updates for UEFI 2.7 (BTT v2.0)
by Vishal Verma
Update the check-namespace command to check/detect both v1.1 and v2.0
BTTs. Also update the btt-check.sh test to work for both.
Signed-off-by: Vishal Verma <vishal.l.verma(a)intel.com>
---
ndctl/check.c | 94 +++++++++++++++++++++++++++++++++++++++++++++----------
ndctl/check.h | 5 ++-
test/btt-check.sh | 4 +--
3 files changed, 83 insertions(+), 20 deletions(-)
diff --git a/ndctl/check.c b/ndctl/check.c
index 3775c2e..0b564ed 100644
--- a/ndctl/check.c
+++ b/ndctl/check.c
@@ -766,14 +766,29 @@ static void btt_remove_mappings(struct btt_chk *bttc)
}
}
-static int btt_recover_first_sb(struct btt_chk *bttc)
+static int btt_sb_get_expected_offset(struct btt_sb *btt_sb)
+{
+ u16 version_major, version_minor;
+
+ version_major = le16_to_cpu(btt_sb->version_major);
+ version_minor = le16_to_cpu(btt_sb->version_minor);
+
+ if (version_major == 1 && version_minor == 1)
+ return BTT1_START_OFFSET;
+ else if (version_major == 2 && version_minor == 0)
+ return BTT2_START_OFFSET;
+ else
+ return -ENXIO;
+}
+
+static int __btt_recover_first_sb(struct btt_chk *bttc, int off)
{
int rc, est_arenas = 0;
u64 offset, remaining;
struct btt_sb *btt_sb;
/* Estimate the number of arenas */
- remaining = bttc->rawsize - bttc->start_off;
+ remaining = bttc->rawsize - off;
while (remaining) {
if (remaining < ARENA_MIN_SIZE && est_arenas == 0)
return -EINVAL;
@@ -800,7 +815,7 @@ static int btt_recover_first_sb(struct btt_chk *bttc)
if (btt_sb == NULL)
return -ENOMEM;
/* Read the original first info block into btt_sb[0] */
- rc = btt_read_info(bttc, &btt_sb[0], bttc->start_off);
+ rc = btt_read_info(bttc, &btt_sb[0], off);
if (rc)
goto out;
@@ -809,13 +824,26 @@ static int btt_recover_first_sb(struct btt_chk *bttc)
offset = rounddown(bttc->rawsize - remaining, SZ_4K) -
BTT_INFO_SIZE;
else
- offset = ARENA_MAX_SIZE - BTT_INFO_SIZE + bttc->start_off;
+ offset = ARENA_MAX_SIZE - BTT_INFO_SIZE + off;
info(bttc, "Attempting recover info-block from end-of-arena offset %#lx\n",
offset);
rc = btt_info_read_verify(bttc, &btt_sb[1], offset);
if (rc == 0) {
- rc = btt_write_info(bttc, &btt_sb[1], bttc->start_off);
+ int expected_offset = btt_sb_get_expected_offset(&btt_sb[1]);
+
+ /*
+ * The fact that the btt_sb is self-consistent doesn't tell us
+ * what BTT version it was, if restoring from the end of the
+ * arena. (i.e. a consistent sb may be found for any valid
+ * start offset). Use the version information in the sb to
+ * determine what the expected start offset is.
+ */
+ if ((expected_offset < 0) || (expected_offset != off)) {
+ rc = -ENXIO;
+ goto out;
+ }
+ rc = btt_write_info(bttc, &btt_sb[1], off);
goto out;
}
@@ -844,7 +872,7 @@ static int btt_recover_first_sb(struct btt_chk *bttc)
btt_sb[1].checksum = btt_sb[0].checksum;
rc = btt_info_verify(bttc, &btt_sb[1]);
if (rc == 0) {
- rc = btt_write_info(bttc, &btt_sb[1], bttc->start_off);
+ rc = btt_write_info(bttc, &btt_sb[1], off);
goto out;
}
}
@@ -855,7 +883,7 @@ static int btt_recover_first_sb(struct btt_chk *bttc)
*/
offset = le32_to_cpu(btt_sb[0].info2off);
if (offset > min(bttc->rawsize - BTT_INFO_SIZE,
- ARENA_MAX_SIZE - BTT_INFO_SIZE + bttc->start_off)) {
+ ARENA_MAX_SIZE - BTT_INFO_SIZE + off)) {
rc = -ENXIO;
goto out;
}
@@ -863,9 +891,9 @@ static int btt_recover_first_sb(struct btt_chk *bttc)
info(bttc, "Attempting to recover info-block from info2 offset %#lx\n",
offset);
rc = btt_info_read_verify(bttc, &btt_sb[1],
- offset + bttc->start_off);
+ offset + off);
if (rc == 0) {
- rc = btt_write_info(bttc, &btt_sb[1], bttc->start_off);
+ rc = btt_write_info(bttc, &btt_sb[1], off);
goto out;
}
} else
@@ -875,6 +903,25 @@ static int btt_recover_first_sb(struct btt_chk *bttc)
return rc;
}
+static int btt_recover_first_sb(struct btt_chk *bttc)
+{
+ int offsets[BTT_NUM_OFFSETS] = {
+ BTT1_START_OFFSET,
+ BTT2_START_OFFSET,
+ };
+ int i, rc;
+
+ for (i = 0; i < BTT_NUM_OFFSETS; i++) {
+ rc = __btt_recover_first_sb(bttc, offsets[i]);
+ if (rc == 0) {
+ bttc->start_off = offsets[i];
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
int namespace_check(struct ndctl_namespace *ndns, struct check_opts *opts)
{
const char *devname = ndctl_namespace_get_devname(ndns);
@@ -902,7 +949,6 @@ int namespace_check(struct ndctl_namespace *ndns, struct check_opts *opts)
}
bttc->opts = opts;
- bttc->start_off = BTT_START_OFFSET;
bttc->sys_page_size = sysconf(_SC_PAGESIZE);
bttc->rawsize = ndctl_namespace_get_size(ndns);
ndctl_namespace_get_uuid(ndns, bttc->parent_uuid);
@@ -980,17 +1026,31 @@ int namespace_check(struct ndctl_namespace *ndns, struct check_opts *opts)
goto out_close;
}
- rc = btt_info_read_verify(bttc, btt_sb, bttc->start_off);
+ /* Try reading a BTT1 info block first */
+ rc = btt_info_read_verify(bttc, btt_sb, BTT1_START_OFFSET);
+ if (rc == 0)
+ bttc->start_off = BTT1_START_OFFSET;
if (rc) {
- rc = btt_recover_first_sb(bttc);
+ /* Try reading a BTT2 info block */
+ rc = btt_info_read_verify(bttc, btt_sb, BTT2_START_OFFSET);
+ if (rc == 0)
+ bttc->start_off = BTT2_START_OFFSET;
if (rc) {
- err(bttc, "Unable to recover any BTT info blocks\n");
- goto out_close;
+ rc = btt_recover_first_sb(bttc);
+ if (rc) {
+ err(bttc, "Unable to recover any BTT info blocks\n");
+ goto out_close;
+ }
+ /*
+ * btt_recover_first_sb will have set bttc->start_off
+ * based on the version it found
+ */
+ rc = btt_info_read_verify(bttc, btt_sb, bttc->start_off);
+ if (rc)
+ goto out_close;
}
- rc = btt_info_read_verify(bttc, btt_sb, bttc->start_off);
- if (rc)
- goto out_close;
}
+
rc = btt_discover_arenas(bttc);
if (rc)
goto out_close;
diff --git a/ndctl/check.h b/ndctl/check.h
index f0200db..00b11b2 100644
--- a/ndctl/check.h
+++ b/ndctl/check.h
@@ -27,9 +27,12 @@
#define ARENA_MIN_SIZE (1UL << 24) /* 16 MB */
#define ARENA_MAX_SIZE (1ULL << 39) /* 512 GB */
#define BTT_INFO_SIZE 4096
-#define BTT_START_OFFSET 4096
#define IB_FLAG_ERROR_MASK 0x00000001
+#define BTT_NUM_OFFSETS 2
+#define BTT1_START_OFFSET 4096
+#define BTT2_START_OFFSET 0
+
struct log_entry {
le32 lba;
le32 old_map;
diff --git a/test/btt-check.sh b/test/btt-check.sh
index 5ec224b..d309448 100755
--- a/test/btt-check.sh
+++ b/test/btt-check.sh
@@ -146,10 +146,10 @@ test_bad_info()
echo "=== ${FUNCNAME[0]} ==="
set_raw
echo "wiping info block"
- dd if=/dev/zero of=/dev/$raw_bdev bs=$bs count=1 seek=1
+ dd if=/dev/zero of=/dev/$raw_bdev bs=$bs count=2 seek=0
unset_raw
$ndctl disable-namespace $dev
- $ndctl check-namespace $dev 2>&1 | grep "info block at offset 0x1000 needs to be restored"
+ $ndctl check-namespace $dev 2>&1 | grep -E "info block at offset .* needs to be restored"
$ndctl check-namespace --repair $dev
$ndctl enable-namespace $dev
post_repair_test
--
2.9.3
5 years, 1 month
ND_MIN_NAMESPACE_SIZE
by Soccer Liu
Hi all:
I noticed that ND_MIN_NAMESPACE_SIZE is defined as 4MB.
nvdimm_namespace_common_probe(..){..
if (size < ND_MIN_NAMESPACE_SIZE) {
dev_dbg(&ndns->dev, "%pa, too small must be at least %#x\n",
&size, ND_MIN_NAMESPACE_SIZE);
return ERR_PTR(-ENODEV);
}...}
In our configuration, we have a host based software enumerated PMEM device that could be much smaller than 4MB.Because of above failure, no PMEM device was exposed.
I changed ND_MIN_NAMESPACE_SIZE to smaller size (such as 256 KB) and a smaller size (<4MB) Persistent Memory starts working.Is there any reason that it cannot be smaller?
Thanks
Cheng-mean
5 years, 1 month
[ndctl PATCH v2] ndctl, test: unit test updates for the BTT 2.0 format
by Vishal Verma
With the BTT 2.0 update, a couple of minor updates to the unit tests are
needed:
test/libndctl: Update expected BTT sizes
test/libndctl: in btt_autodetect, when wiping an old BTT, wipe the first
two 4K pages instead of one.
Cc: Dan Williams <dan.j.williams(a)intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma(a)intel.com>
---
v2:
- Move the new BTT size check under a 4.13.0 attempt (Dan)
test/libndctl.c | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/test/libndctl.c b/test/libndctl.c
index 24aff36..0f67d54 100644
--- a/test/libndctl.c
+++ b/test/libndctl.c
@@ -994,16 +994,16 @@ static int check_btt_size(struct ndctl_btt *btt)
int size_select, sect_select;
unsigned long long expect_table[][2] = {
[0] = {
- [0] = 0x11b4400,
- [1] = 0x8da2000,
+ [0] = 0x11b5400,
+ [1] = 0x8daa000,
},
[1] = {
- [0] = 0x13b0400,
- [1] = 0x9d82000,
+ [0] = 0x13b1400,
+ [1] = 0x9d8a000,
},
[2] = {
- [0] = 0x1aa2600,
- [1] = 0xd513000,
+ [0] = 0x1aa3600,
+ [1] = 0xd51b000,
},
};
@@ -1107,9 +1107,12 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
devname, mode);
}
- rc = check_btt_size(btt);
- if (rc)
- goto err;
+ /* prior to v4.13 the expected sizes were different due to BTT1.1 */
+ if (ndctl_test_attempt(test, KERNEL_VERSION(4, 13, 0))) {
+ rc = check_btt_size(btt);
+ if (rc)
+ goto err;
+ }
if (btt_seed == ndctl_region_get_btt_seed(region)
&& btt == btt_seed) {
@@ -1517,12 +1520,19 @@ static int check_btt_autodetect(struct ndctl_bus *bus,
}
memset(buf, 0, 4096);
+ /* Delete both the first and second 4K pages */
rc = pwrite(fd, buf, 4096, 4096);
if (rc < 4096) {
rc = -ENXIO;
fprintf(stderr, "%s: failed to overwrite btt on %s\n",
devname, bdev);
}
+ rc = pwrite(fd, buf, 4096, 0);
+ if (rc < 4096) {
+ rc = -ENXIO;
+ fprintf(stderr, "%s: failed to overwrite btt on %s\n",
+ devname, bdev);
+ }
out:
ndctl_region_set_ro(region, namespace->ro);
ndctl_namespace_set_raw_mode(ndns, 0);
--
2.9.3
5 years, 1 month
[PATCH v2] libnvdimm, pmem: Add sysfs notifications to badblocks
by Toshi Kani
Sysfs "badblocks" information may be updated during run-time that:
- MCE, SCI, and sysfs "scrub" may add new bad blocks
- Writes and ioctl() may clear bad blocks
Add support to send sysfs notifications to sysfs "badblocks" file
under region and pmem directories when their badblocks information
is re-evaluated (but is not necessarily changed) during run-time.
Signed-off-by: Toshi Kani <toshi.kani(a)hpe.com>
Cc: Dan Williams <dan.j.williams(a)intel.com>
Cc: Vishal Verma <vishal.l.verma(a)intel.com>
Cc: Linda Knippers <linda.knippers(a)hpe.com>
---
v2: Send notifications for the clearing case
---
drivers/nvdimm/bus.c | 3 +++
drivers/nvdimm/nd.h | 1 +
drivers/nvdimm/pmem.c | 14 ++++++++++++++
drivers/nvdimm/pmem.h | 1 +
drivers/nvdimm/region.c | 12 ++++++++++--
5 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index e9361bf..63ce50d 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -198,6 +198,9 @@ static int nvdimm_clear_badblocks_region(struct device *dev, void *data)
sector = (ctx->phys - nd_region->ndr_start) / 512;
badblocks_clear(&nd_region->bb, sector, ctx->cleared / 512);
+ if (nd_region->bb_state)
+ sysfs_notify_dirent(nd_region->bb_state);
+
return 0;
}
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 03852d7..4bb57ff 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -155,6 +155,7 @@ struct nd_region {
u64 ndr_start;
int id, num_lanes, ro, numa_node;
void *provider_data;
+ struct kernfs_node *bb_state;
struct badblocks bb;
struct nd_interleave_set *nd_set;
struct nd_percpu_lane __percpu *lane;
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index c544d46..6c14c72 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -68,6 +68,8 @@ static int pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset,
(unsigned long long) sector, cleared,
cleared > 1 ? "s" : "");
badblocks_clear(&pmem->bb, sector, cleared);
+ if (pmem->bb_state)
+ sysfs_notify_dirent(pmem->bb_state);
}
invalidate_pmem(pmem->virt_addr + offset, len);
@@ -377,6 +379,13 @@ static int pmem_attach_disk(struct device *dev,
revalidate_disk(disk);
+ pmem->bb_state = sysfs_get_dirent(disk_to_dev(disk)->kobj.sd,
+ "badblocks");
+ if (pmem->bb_state)
+ sysfs_put(pmem->bb_state);
+ else
+ dev_warn(dev, "sysfs_get_dirent 'badblocks' failed\n");
+
return 0;
}
@@ -428,6 +437,7 @@ static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
struct nd_namespace_io *nsio;
struct resource res;
struct badblocks *bb;
+ struct kernfs_node *bb_state;
if (event != NVDIMM_REVALIDATE_POISON)
return;
@@ -439,11 +449,13 @@ static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
nd_region = to_nd_region(ndns->dev.parent);
nsio = to_nd_namespace_io(&ndns->dev);
bb = &nsio->bb;
+ bb_state = NULL;
} else {
struct pmem_device *pmem = dev_get_drvdata(dev);
nd_region = to_region(pmem);
bb = &pmem->bb;
+ bb_state = pmem->bb_state;
if (is_nd_pfn(dev)) {
struct nd_pfn *nd_pfn = to_nd_pfn(dev);
@@ -463,6 +475,8 @@ static void nd_pmem_notify(struct device *dev, enum nvdimm_event event)
res.start = nsio->res.start + offset;
res.end = nsio->res.end - end_trunc;
nvdimm_badblocks_populate(nd_region, bb, &res);
+ if (bb_state)
+ sysfs_notify_dirent(bb_state);
}
MODULE_ALIAS("pmem");
diff --git a/drivers/nvdimm/pmem.h b/drivers/nvdimm/pmem.h
index 7f4dbd7..c5917f0 100644
--- a/drivers/nvdimm/pmem.h
+++ b/drivers/nvdimm/pmem.h
@@ -17,6 +17,7 @@ struct pmem_device {
size_t size;
/* trim size when namespace capacity has been section aligned */
u32 pfn_pad;
+ struct kernfs_node *bb_state;
struct badblocks bb;
struct dax_device *dax_dev;
struct gendisk *disk;
diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c
index 869a886..ca94029 100644
--- a/drivers/nvdimm/region.c
+++ b/drivers/nvdimm/region.c
@@ -58,10 +58,16 @@ static int nd_region_probe(struct device *dev)
if (devm_init_badblocks(dev, &nd_region->bb))
return -ENODEV;
+ nd_region->bb_state = sysfs_get_dirent(nd_region->dev.kobj.sd,
+ "badblocks");
+ if (nd_region->bb_state)
+ sysfs_put(nd_region->bb_state);
+ else
+ dev_warn(&nd_region->dev,
+ "sysfs_get_dirent 'badblocks' failed\n");
ndr_res.start = nd_region->ndr_start;
ndr_res.end = nd_region->ndr_start + nd_region->ndr_size - 1;
- nvdimm_badblocks_populate(nd_region,
- &nd_region->bb, &ndr_res);
+ nvdimm_badblocks_populate(nd_region, &nd_region->bb, &ndr_res);
}
nd_region->btt_seed = nd_btt_create(nd_region);
@@ -126,6 +132,8 @@ static void nd_region_notify(struct device *dev, enum nvdimm_event event)
nd_region->ndr_size - 1;
nvdimm_badblocks_populate(nd_region,
&nd_region->bb, &res);
+ if (nd_region->bb_state)
+ sysfs_notify_dirent(nd_region->bb_state);
}
}
device_for_each_child(dev, &event, child_notify);
5 years, 1 month