On Thu, Oct 5, 2017 at 6:54 PM, Vishal Verma <[email protected]> wrote:
> The kernel uses sysfs to notify userspace of the number of completed
> Address Range Scrubs, as well as any ongoing scrubs. Add libndctl
> helpers to get the scrub count, and to wait for an in-progress scrub to
> complete.
>
> Cc: Dan Williams <[email protected]>
> Signed-off-by: Vishal Verma <[email protected]>
> ---
> ndctl/lib/libndctl.c | 85
> ++++++++++++++++++++++++++++++++++++++++++++++++++
> ndctl/lib/libndctl.sym | 2 ++
> ndctl/lib/private.h | 1 +
> ndctl/libndctl.h.in | 2 ++
> 4 files changed, 90 insertions(+)
>
> diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
> index 60143d9..3943978 100644
> --- a/ndctl/lib/libndctl.c
> +++ b/ndctl/lib/libndctl.c
> @@ -555,6 +555,7 @@ static void free_bus(struct ndctl_bus *bus, struct
> list_head *head)
> free(bus->bus_path);
> free(bus->bus_buf);
> free(bus->wait_probe_path);
> + free(bus->scrub_path);
> free(bus);
> }
>
> @@ -785,6 +786,11 @@ static void *add_bus(void *parent, int id, const char
> *ctl_base)
> if (!bus->wait_probe_path)
> goto err_read;
>
> + sprintf(path, "%s/device/nfit/scrub", ctl_base);
> + bus->scrub_path = strdup(path);
> + if (!bus->scrub_path)
> + goto err_read;
> +
> bus->bus_path = parent_dev_path("char", bus->major, bus->minor);
> if (!bus->bus_path)
> goto err_dev_path;
> @@ -810,6 +816,7 @@ static void *add_bus(void *parent, int id, const char
> *ctl_base)
> err_dev_path:
> err_read:
> free(bus->wait_probe_path);
> + free(bus->scrub_path);
> free(bus->provider);
> free(bus->bus_buf);
> free(bus);
> @@ -1082,6 +1089,84 @@ NDCTL_EXPORT int ndctl_bus_wait_probe(struct ndctl_bus
> *bus)
> return rc < 0 ? -ENXIO : 0;
> }
>
> +NDCTL_EXPORT unsigned int ndctl_bus_get_scrub_count(struct ndctl_bus *bus)
> +{
> + struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
> + char buf[SYSFS_ATTR_SIZE];
> + unsigned int scrub_count;
> + char in_progress = '\0';
> + int rc;
> +
> + rc = sysfs_read_attr(ctx, bus->scrub_path, buf);
> + if (rc < 0)
> + return UINT_MAX;
> +
> + rc = sscanf(buf, "%u%c", &scrub_count, &in_progress);
> + if (rc < 0)
> + return UINT_MAX;
> + if (rc == 0) {
> + /* unable to read scrub count */
> + return UINT_MAX;
> + }
> + if (rc >= 1)
> + return scrub_count;
> +
> + return UINT_MAX;
> +}
> +
> +/**
> + * ndctl_bus_wait_for_scrub - wait for a scrub to complete
> + * @bus: bus for which to check whether a scrub is in progress
> + *
> + * Upon return this bus has completed any in-progress scrubs. This is
> + * different from ndctl_cmd_ars_in_progress in that the latter checks
> + * the output of an ars_status command to see if the in-progress flag
> + * is set, i.e. provides the firmware's view of whether a scrub is in
> + * progress. ndctl_bus_wait_for_scrub instead checks the kernel's view
> + * of whether a scrub is in progress by looking at the 'scrub' file in
> + * sysfs.
> + */
> +NDCTL_EXPORT int ndctl_bus_wait_for_scrub_completion(struct ndctl_bus *bus)
> +{
> + struct ndctl_ctx *ctx = ndctl_bus_get_ctx(bus);
> + unsigned int tmo = 120, scrub_count;
> + char buf[SYSFS_ATTR_SIZE];
> + char in_progress = '\0';
> + int rc, elapsed = 0;
> +
> + do {
> + rc = sysfs_read_attr(ctx, bus->scrub_path, buf);
> + if (rc < 0)
> + break;
> +
> + rc = sscanf(buf, "%u%c", &scrub_count, &in_progress);
> + if (rc < 0)
> + break;
> + else if (rc <= 1) {
> + /* scrub complete, break successfully */
> + rc = 0;
> + break;
> + } else if (rc == 2 && in_progress == '+') {
> + /* scrub in progress, continue to wait */
> + ;
> + } else {
> + /* unknown condition */
> + rc = -ENXIO;
> + break;
> + }
> +
> + elapsed++;
> + sleep(1);
> + } while (tmo-- != 0);
Hmm, we don't need to do a sleep loop here we can use select(2) or
poll(2) to wait until the scrub notifies completion.
Something like:
seq = read_count()
fd = ndctl_bus_get_scrub_eventfd()
while (in_progress(seq)) {
select(..., fd, timeout);
seq = read_count();
}
We already have the kernel doing sleep polling, no need to compound
wake up the problem in userspace.
_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm