The helper function allow iteration through the badblocks file that's part
of the region sysfs attributes. This will support the region list badblocks
code that's coming.

Signed-off-by: Dave Jiang <dave.ji...@intel.com>
---

v2: added cleanup of opened badblocks file from Dan's comments.
v3: fixed inconsistent return code from Andy Rudoff's comments.

 ndctl/lib/libndctl.c   |   74 ++++++++++++++++++++++++++++++++++++++++++++++++
 ndctl/lib/libndctl.sym |    2 +
 ndctl/libndctl.h.in    |   10 ++++++
 3 files changed, 86 insertions(+)

diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index ac1fc63..d85f9ee 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -229,6 +229,8 @@ struct ndctl_region {
                int state;
                unsigned long long cookie;
        } iset;
+       FILE *badblocks;
+       struct badblock bb;
 };
 
 /**
@@ -594,6 +596,8 @@ static void free_region(struct ndctl_region *region)
        kmod_module_unref(region->module);
        free(region->region_buf);
        free(region->region_path);
+       if (region->badblocks)
+               fclose(region->badblocks);
        free(region);
 }
 
@@ -1867,6 +1871,76 @@ NDCTL_EXPORT struct ndctl_dimm 
*ndctl_region_get_next_dimm(struct ndctl_region *
        return NULL;
 }
 
+static int regions_badblocks_init(struct ndctl_region *region)
+{
+       struct ndctl_ctx *ctx = ndctl_region_get_ctx(region);
+       char *bb_path;
+       int rc = 0;
+
+       /* if the file is already open */
+       if (region->badblocks) {
+               fclose(region->badblocks);
+               region->badblocks = NULL;
+       }
+
+       if (asprintf(&bb_path, "%s/badblocks",
+                               region->region_path) < 0) {
+               rc = -errno;
+               err(ctx, "region badblocks path allocation failure\n");
+               return rc;
+       }
+
+       region->badblocks = fopen(bb_path, "re");
+       if (!region->badblocks) {
+               rc = -errno;
+               free(bb_path);
+               return rc;
+       }
+
+       free(bb_path);
+       return rc;
+}
+
+NDCTL_EXPORT struct badblock *ndctl_region_get_next_badblock(struct 
ndctl_region *region)
+{
+       int rc;
+       char *buf = NULL;
+       size_t rlen = 0;
+
+       if (!region->badblocks)
+               return NULL;
+
+       rc = getline(&buf, &rlen, region->badblocks);
+       if (rc == -1) {
+               free(buf);
+               return NULL;
+       }
+
+       rc = sscanf(buf, "%llu %u", &region->bb.offset, &region->bb.len);
+       free(buf);
+       if (rc != 2) {
+               /* end of the road, clean up */
+               fclose(region->badblocks);
+               region->badblocks = NULL;
+               region->bb.offset = 0;
+               region->bb.len = 0;
+               return NULL;
+       }
+
+       return &region->bb;
+}
+
+NDCTL_EXPORT struct badblock *ndctl_region_get_first_badblock(struct 
ndctl_region *region)
+{
+       int rc;
+
+       rc = regions_badblocks_init(region);
+       if (rc < 0)
+               return NULL;
+
+       return ndctl_region_get_next_badblock(region);
+}
+
 static struct nd_cmd_vendor_tail *to_vendor_tail(struct ndctl_cmd *cmd)
 {
        struct nd_cmd_vendor_tail *tail = (struct nd_cmd_vendor_tail *)
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index b5a085c..9bc36a3 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -140,6 +140,8 @@ global:
        ndctl_region_get_ro;
        ndctl_region_set_ro;
        ndctl_region_get_resource;
+       ndctl_region_get_first_badblock;
+       ndctl_region_get_next_badblock;
        ndctl_interleave_set_get_first;
        ndctl_interleave_set_get_next;
        ndctl_interleave_set_is_active;
diff --git a/ndctl/libndctl.h.in b/ndctl/libndctl.h.in
index 6ee8a35..2c45d2d 100644
--- a/ndctl/libndctl.h.in
+++ b/ndctl/libndctl.h.in
@@ -372,6 +372,10 @@ int ndctl_cmd_get_status(struct ndctl_cmd *cmd);
 unsigned int ndctl_cmd_get_firmware_status(struct ndctl_cmd *cmd);
 int ndctl_cmd_submit(struct ndctl_cmd *cmd);
 
+struct badblock {
+       unsigned long long offset;
+       unsigned int len;
+};
 struct ndctl_region;
 struct ndctl_region *ndctl_region_get_first(struct ndctl_bus *bus);
 struct ndctl_region *ndctl_region_get_next(struct ndctl_region *region);
@@ -379,6 +383,12 @@ struct ndctl_region *ndctl_region_get_next(struct 
ndctl_region *region);
         for (region = ndctl_region_get_first(bus); \
              region != NULL; \
              region = ndctl_region_get_next(region))
+struct badblock *ndctl_region_get_first_badblock(struct ndctl_region *region);
+struct badblock *ndctl_region_get_next_badblock(struct ndctl_region *region);
+#define ndctl_region_badblock_foreach(region, badblock) \
+        for (badblock = ndctl_region_get_first_badblock(region); \
+             badblock != NULL; \
+             badblock = ndctl_region_get_next_badblock(region))
 unsigned int ndctl_region_get_id(struct ndctl_region *region);
 const char *ndctl_region_get_devname(struct ndctl_region *region);
 unsigned int ndctl_region_get_interleave_ways(struct ndctl_region *region);

_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to