From patchwork Mon Oct 30 17:43:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Verma, Vishal L" X-Patchwork-Id: 10032965 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3F64A60291 for ; Mon, 30 Oct 2017 17:45:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 30B4E288C3 for ; Mon, 30 Oct 2017 17:45:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2584228918; Mon, 30 Oct 2017 17:45:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from ml01.01.org (ml01.01.org [198.145.21.10]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id B2DB6288C3 for ; Mon, 30 Oct 2017 17:45:55 +0000 (UTC) Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id E680B21CEB136; Mon, 30 Oct 2017 10:42:03 -0700 (PDT) X-Original-To: linux-nvdimm@lists.01.org Delivered-To: linux-nvdimm@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.24; helo=mga09.intel.com; envelope-from=vishal.l.verma@intel.com; receiver=linux-nvdimm@lists.01.org Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 3A0172034A7C1 for ; Mon, 30 Oct 2017 10:42:02 -0700 (PDT) Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 30 Oct 2017 10:45:52 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos; i="5.44,320,1505804400"; d="scan'208"; a="1211996846" Received: from omniknight.lm.intel.com ([10.232.112.27]) by fmsmga001.fm.intel.com with ESMTP; 30 Oct 2017 10:45:52 -0700 From: Vishal Verma To: Subject: [ndctl PATCH v3 1/6] libndctl: add APIs to get scrub count and to wait for a scrub Date: Mon, 30 Oct 2017 11:43:30 -0600 Message-Id: <20171030174335.6806-2-vishal.l.verma@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20171030174335.6806-1-vishal.l.verma@intel.com> References: <20171030174335.6806-1-vishal.l.verma@intel.com> X-BeenThere: linux-nvdimm@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "Linux-nvdimm developer list." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" X-Virus-Scanned: ClamAV using ClamSMTP 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 Signed-off-by: Vishal Verma --- ndctl/lib/libndctl.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ ndctl/lib/libndctl.sym | 2 + ndctl/lib/private.h | 1 + ndctl/libndctl.h.in | 2 + 4 files changed, 105 insertions(+) diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c index 60143d9..c878383 100644 --- a/ndctl/lib/libndctl.c +++ b/ndctl/lib/libndctl.c @@ -10,7 +10,9 @@ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for * more details. */ +#include #include +#include #include #include #include @@ -555,6 +557,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 +788,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 +818,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 +1091,97 @@ 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'; + struct pollfd fds; + int fd = 0, rc; + + fd = open(bus->scrub_path, O_RDONLY|O_CLOEXEC); + fds.fd = fd; + fds.events = POLLPRI | POLLIN; + 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, wait */ + rc = poll(&fds, 1, tmo); + if (rc < 0) { + dbg(ctx, "poll error: %d\n", errno); + break; + } else if (rc == 0) { + dbg(ctx, "poll timeout after: %d seconds", tmo); + rc = -ENXIO; + break; + } + if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) { + dbg(ctx, "poll error, revents: %d\n", + fds.revents); + rc = -ENXIO; + break; + } + } else { + /* unknown condition */ + rc = -ENXIO; + break; + } + } while (in_progress); + + dbg(ctx, "bus%d: scrub complete\n", ndctl_bus_get_id(bus)); + if (fd) + close (fd); + return rc < 0 ? -ENXIO : 0; +} + static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module, const char *devname); static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath); diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index 58db669..4c22c0f 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -286,6 +286,8 @@ global: ndctl_bus_get_region_by_physical_address; ndctl_bus_get_dimm_by_physical_address; ndctl_bus_is_nfit_cmd_supported; + ndctl_bus_wait_for_scrub_completion; + ndctl_bus_get_scrub_count; ndctl_dimm_read_labels; ndctl_dimm_validate_labels; ndctl_dimm_init_labels; diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h index 2de314c..6b909aa 100644 --- a/ndctl/lib/private.h +++ b/ndctl/lib/private.h @@ -152,6 +152,7 @@ struct ndctl_bus { char *bus_buf; size_t buf_len; char *wait_probe_path; + char *scrub_path; unsigned long dsm_mask; unsigned long nfit_dsm_mask; }; diff --git a/ndctl/libndctl.h.in b/ndctl/libndctl.h.in index 42e53c6..a4fbe33 100644 --- a/ndctl/libndctl.h.in +++ b/ndctl/libndctl.h.in @@ -113,6 +113,8 @@ unsigned int ndctl_bus_get_revision(struct ndctl_bus *bus); unsigned int ndctl_bus_get_id(struct ndctl_bus *bus); const char *ndctl_bus_get_provider(struct ndctl_bus *bus); int ndctl_bus_wait_probe(struct ndctl_bus *bus); +int ndctl_bus_wait_for_scrub_completion(struct ndctl_bus *bus); +unsigned int ndctl_bus_get_scrub_count(struct ndctl_bus *bus); struct ndctl_dimm; struct ndctl_dimm *ndctl_dimm_get_first(struct ndctl_bus *bus);