diff mbox

[1/2] ndctl: add foreach helper for region badblocks in libndctl

Message ID 149428467512.44955.4085670669863366983.stgit@djiang5-desk3.ch.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dave Jiang May 8, 2017, 11:04 p.m. UTC
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.jiang@intel.com>
---
 ndctl/lib/libndctl.c   |   72 ++++++++++++++++++++++++++++++++++++++++++++++++
 ndctl/lib/libndctl.sym |    2 +
 ndctl/libndctl.h.in    |   10 +++++++
 3 files changed, 84 insertions(+)

Comments

Dan Williams May 8, 2017, 11:28 p.m. UTC | #1
On Mon, May 8, 2017 at 4:04 PM, Dave Jiang <dave.jiang@intel.com> wrote:
> 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.jiang@intel.com>
> ---
>  ndctl/lib/libndctl.c   |   72 ++++++++++++++++++++++++++++++++++++++++++++++++
>  ndctl/lib/libndctl.sym |    2 +
>  ndctl/libndctl.h.in    |   10 +++++++
>  3 files changed, 84 insertions(+)
>
> diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
> index ac1fc63..40d9463 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;
>  };
>
>  /**
> @@ -1867,6 +1869,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, "r");

Can you change this to fopen(bb_path, "re") so that we get O_CLOEXEC behavior?

> +       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 */

What if they only consume the first entry and never get here? I think
we need to clean up any leftovers and free_region() time as well.
diff mbox

Patch

diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index ac1fc63..40d9463 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;
 };
 
 /**
@@ -1867,6 +1869,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, "r");
+	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);