Message ID | 20220222121519.1674117-1-vaibhav@linux.ibm.com (mailing list archive) |
---|---|
State | Accepted |
Commit | c5ccbf29c54b5a3d9cb1c138c06c8d5ac3ee80c2 |
Headers | show |
Series | [ndctl,v5] ndctl,libndctl: Update nvdimm flags after smart-inject | expand |
I have tested the patch, which is working on the system Kernel Version: 5.17.0 + patch (https://patchwork.ozlabs.org/project/linuxppc-dev/patch/20220124202204.1488346-1-vaibhav@linux.ibm.com/) System: Power-9, PPC64le, RHEL 8.1 Results: Without this patch, building ndctl on base commit: 6e85cac1958f920f231b94ff570ac0e434595b7d $ sudo ndctl inject-smart -fU nmem0 [ { "dev":"nmem0", "health":{ "health_state":"fatal", "shutdown_state":"dirty", "shutdown_count":0 } } ] With the patch applied, $ sudo ndctl inject-smart -fU nmem0 [ { "dev":"nmem0", "flag_failed_flush":true, "flag_smart_event":true, "health":{ "health_state":"fatal", "shutdown_state":"dirty", "shutdown_count":0 } } ] it update flags also when flags are unset (implies flags get removed from the output): $ ./builddir/ndctl/ndctl inject-smart -fU nmem0 [ { "dev":"nmem0", "flag_failed_flush":true, "flag_smart_event":true, "health":{ "health_state":"fatal", "shutdown_state":"dirty", "shutdown_count":0 } } ] $ ./ndctl inject-smart --fatal-uninject nmem0 [ { "dev":"nmem0", "flag_failed_flush":true, "health":{ "health_state":"ok", "shutdown_state":"dirty", "shutdown_count":0 } } ] Tested-by: Tarun Sahu <tsahu@linux.ibm.com> On Tue, Feb 22, 2022 at 05:45:19PM +0530, Vaibhav Jain wrote: > Presently after performing an inject-smart command the nvdimm flags reported are > out of date as shown below where no 'smart_notify' or 'flush_fail' flags were > reported even though they are set after injecting the smart error: > > $ sudo ndctl inject-smart -fU nmem0 > [ > { > "dev":"nmem0", > "health":{ > "health_state":"fatal", > "shutdown_state":"dirty", > "shutdown_count":0 > } > } > ] > $ sudo cat /sys/class/nd/ndctl0/device/nmem0/papr/flags > flush_fail smart_notify > > This happens because nvdimm flags are only parsed once during its probe > and not refreshed even after a inject-smart operation makes them out of > date. To fix this the patch forces an update of nvdimm flags via newly > introduced export from libndctl named ndctl_dimm_refresh_flags() thats called > from dimm_inject_smart() after inject-smart command is successfully > submitted. This ensures that correct nvdimm flags are displayed later in that > function. With this implemented correct nvdimm flags are reported after a > inject-smart operation: > > $ sudo ndctl inject-smart -fU nmem0 > [ > { > "dev":"nmem0", > "flag_failed_flush":true, > "flag_smart_event":true, > "health":{ > "health_state":"fatal", > "shutdown_state":"dirty", > "shutdown_count":0 > } > } > ] > > The patch refactors populate_dimm_attributes() to move the nvdimm flags > parsing code to the newly introduced ndctl_dimm_refresh_flags() > export. Since reading nvdimm flags requires constructing path using > 'bus_prefix' which is only available during add_dimm(), the patch > introduces a new member 'struct ndctl_dimm.bus_prefix' to cache its > value. During ndctl_dimm_refresh_flags() the cached bus_prefix is used to > read the contents of the nvdimm flag file and pass it on to the appropriate > flag parsing function. Finally dimm_inject_smart() is updated to issue call to > ndctl_dimm_refresh_flags() before generating json output of the nvdimm status > > Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com> > Signed-off-by: Shivaprasad G Bhat <sbhat@linux.ibm.com> > --- > Changelog: > > Since v4: > https://lore.kernel.org/nvdimm/20220124205822.1492702-1-vaibhav@linux.ibm.com > > * Instead of updating nvdimm flags in cmd_submit() only refresh when for > inject-smart command [ Vishal ] > * Added the export of ndctl_dimm_refresh_flags() to libndctl exports [ Vishal ] > * Updated changes to add_dimm() to make then more readable [ Vishal ] > * Updated patch description. > --- > ndctl/inject-smart.c | 4 +++ > ndctl/lib/libndctl.c | 55 +++++++++++++++++++++++++++++++----------- > ndctl/lib/libndctl.sym | 4 +++ > ndctl/lib/private.h | 1 + > ndctl/libndctl.h | 1 + > 5 files changed, 51 insertions(+), 14 deletions(-) > > diff --git a/ndctl/inject-smart.c b/ndctl/inject-smart.c > index bd8c01e000d4..d7da5ad8c425 100644 > --- a/ndctl/inject-smart.c > +++ b/ndctl/inject-smart.c > @@ -467,6 +467,10 @@ static int dimm_inject_smart(struct ndctl_dimm *dimm) > jdimms = json_object_new_array(); > if (!jdimms) > goto out; > + > + /* Ensure the dimm flags are upto date before reporting them */ > + ndctl_dimm_refresh_flags(dimm); > + > jdimm = util_dimm_to_json(dimm, sctx.flags); > if (!jdimm) > goto out; > diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c > index 5979a92c113c..8b92d0419871 100644 > --- a/ndctl/lib/libndctl.c > +++ b/ndctl/lib/libndctl.c > @@ -608,6 +608,7 @@ static void free_dimm(struct ndctl_dimm *dimm) > free(dimm->unique_id); > free(dimm->dimm_buf); > free(dimm->dimm_path); > + free(dimm->bus_prefix); > if (dimm->module) > kmod_module_unref(dimm->module); > if (dimm->health_eventfd > -1) > @@ -1670,14 +1671,34 @@ static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module, > static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath); > static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias); > > +NDCTL_EXPORT void ndctl_dimm_refresh_flags(struct ndctl_dimm *dimm) > +{ > + struct ndctl_ctx *ctx = dimm->bus->ctx; > + char *path = dimm->dimm_buf; > + char buf[SYSFS_ATTR_SIZE]; > + > + /* Construct path to dimm flags sysfs file */ > + sprintf(path, "%s/%s/flags", dimm->dimm_path, dimm->bus_prefix); > + > + if (sysfs_read_attr(ctx, path, buf) < 0) > + return; > + > + /* Reset the flags */ > + dimm->flags.flags = 0; > + if (ndctl_bus_has_nfit(dimm->bus)) > + parse_nfit_mem_flags(dimm, buf); > + else if (ndctl_bus_is_papr_scm(dimm->bus)) > + parse_papr_flags(dimm, buf); > +} > + > static int populate_dimm_attributes(struct ndctl_dimm *dimm, > - const char *dimm_base, > - const char *bus_prefix) > + const char *dimm_base) > { > int i, rc = -1; > char buf[SYSFS_ATTR_SIZE]; > struct ndctl_ctx *ctx = dimm->bus->ctx; > char *path = calloc(1, strlen(dimm_base) + 100); > + const char *bus_prefix = dimm->bus_prefix; > > if (!path) > return -ENOMEM; > @@ -1761,16 +1782,10 @@ static int populate_dimm_attributes(struct ndctl_dimm *dimm, > } > > sprintf(path, "%s/%s/flags", dimm_base, bus_prefix); > - if (sysfs_read_attr(ctx, path, buf) == 0) { > - if (ndctl_bus_has_nfit(dimm->bus)) > - parse_nfit_mem_flags(dimm, buf); > - else if (ndctl_bus_is_papr_scm(dimm->bus)) { > - dimm->cmd_family = NVDIMM_FAMILY_PAPR; > - parse_papr_flags(dimm, buf); > - } > - } > - > dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC); > + > + ndctl_dimm_refresh_flags(dimm); > + > rc = 0; > err_read: > > @@ -1826,8 +1841,9 @@ static int add_papr_dimm(struct ndctl_dimm *dimm, const char *dimm_base) > > rc = 0; > } else if (strcmp(buf, "nvdimm_test") == 0) { > + dimm->cmd_family = NVDIMM_FAMILY_PAPR; > /* probe via common populate_dimm_attributes() */ > - rc = populate_dimm_attributes(dimm, dimm_base, "papr"); > + rc = populate_dimm_attributes(dimm, dimm_base); > } > out: > free(path); > @@ -1924,9 +1940,20 @@ static void *add_dimm(void *parent, int id, const char *dimm_base) > dimm->formats = formats; > /* Check if the given dimm supports nfit */ > if (ndctl_bus_has_nfit(bus)) { > - rc = populate_dimm_attributes(dimm, dimm_base, "nfit"); > + dimm->bus_prefix = strdup("nfit"); > + if (!dimm->bus_prefix) { > + rc = -ENOMEM; > + goto out; > + } > + rc = populate_dimm_attributes(dimm, dimm_base); > + > } else if (ndctl_bus_has_of_node(bus)) { > - rc = add_papr_dimm(dimm, dimm_base); > + dimm->bus_prefix = strdup("papr"); > + if (!dimm->bus_prefix) { > + rc = -ENOMEM; > + goto out; > + } > + rc = add_papr_dimm(dimm, dimm_base); > } > > if (rc == -ENODEV) { > diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym > index 3557b32c50ea..f1f9edd4b6ff 100644 > --- a/ndctl/lib/libndctl.sym > +++ b/ndctl/lib/libndctl.sym > @@ -458,3 +458,7 @@ LIBNDCTL_26 { > ndctl_set_config_path; > ndctl_get_config_path; > } LIBNDCTL_25; > + > +LIBNDCTL_27 { > + ndctl_dimm_refresh_flags; > +} LIBNDCTL_26; > diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h > index 4d8622978790..e5c56295556d 100644 > --- a/ndctl/lib/private.h > +++ b/ndctl/lib/private.h > @@ -75,6 +75,7 @@ struct ndctl_dimm { > char *unique_id; > char *dimm_path; > char *dimm_buf; > + char *bus_prefix; > int health_eventfd; > int buf_len; > int id; > diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h > index 4d5cdbf6f619..57cf93d8d151 100644 > --- a/ndctl/libndctl.h > +++ b/ndctl/libndctl.h > @@ -223,6 +223,7 @@ int ndctl_dimm_is_active(struct ndctl_dimm *dimm); > int ndctl_dimm_is_enabled(struct ndctl_dimm *dimm); > int ndctl_dimm_disable(struct ndctl_dimm *dimm); > int ndctl_dimm_enable(struct ndctl_dimm *dimm); > +void ndctl_dimm_refresh_flags(struct ndctl_dimm *dimm); > > struct ndctl_cmd; > struct ndctl_cmd *ndctl_bus_cmd_new_ars_cap(struct ndctl_bus *bus, > > base-commit: 6e85cac1958f920f231b94ff570ac0e434595b7d > -- > 2.35.1 > >
diff --git a/ndctl/inject-smart.c b/ndctl/inject-smart.c index bd8c01e000d4..d7da5ad8c425 100644 --- a/ndctl/inject-smart.c +++ b/ndctl/inject-smart.c @@ -467,6 +467,10 @@ static int dimm_inject_smart(struct ndctl_dimm *dimm) jdimms = json_object_new_array(); if (!jdimms) goto out; + + /* Ensure the dimm flags are upto date before reporting them */ + ndctl_dimm_refresh_flags(dimm); + jdimm = util_dimm_to_json(dimm, sctx.flags); if (!jdimm) goto out; diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c index 5979a92c113c..8b92d0419871 100644 --- a/ndctl/lib/libndctl.c +++ b/ndctl/lib/libndctl.c @@ -608,6 +608,7 @@ static void free_dimm(struct ndctl_dimm *dimm) free(dimm->unique_id); free(dimm->dimm_buf); free(dimm->dimm_path); + free(dimm->bus_prefix); if (dimm->module) kmod_module_unref(dimm->module); if (dimm->health_eventfd > -1) @@ -1670,14 +1671,34 @@ static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module, static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath); static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias); +NDCTL_EXPORT void ndctl_dimm_refresh_flags(struct ndctl_dimm *dimm) +{ + struct ndctl_ctx *ctx = dimm->bus->ctx; + char *path = dimm->dimm_buf; + char buf[SYSFS_ATTR_SIZE]; + + /* Construct path to dimm flags sysfs file */ + sprintf(path, "%s/%s/flags", dimm->dimm_path, dimm->bus_prefix); + + if (sysfs_read_attr(ctx, path, buf) < 0) + return; + + /* Reset the flags */ + dimm->flags.flags = 0; + if (ndctl_bus_has_nfit(dimm->bus)) + parse_nfit_mem_flags(dimm, buf); + else if (ndctl_bus_is_papr_scm(dimm->bus)) + parse_papr_flags(dimm, buf); +} + static int populate_dimm_attributes(struct ndctl_dimm *dimm, - const char *dimm_base, - const char *bus_prefix) + const char *dimm_base) { int i, rc = -1; char buf[SYSFS_ATTR_SIZE]; struct ndctl_ctx *ctx = dimm->bus->ctx; char *path = calloc(1, strlen(dimm_base) + 100); + const char *bus_prefix = dimm->bus_prefix; if (!path) return -ENOMEM; @@ -1761,16 +1782,10 @@ static int populate_dimm_attributes(struct ndctl_dimm *dimm, } sprintf(path, "%s/%s/flags", dimm_base, bus_prefix); - if (sysfs_read_attr(ctx, path, buf) == 0) { - if (ndctl_bus_has_nfit(dimm->bus)) - parse_nfit_mem_flags(dimm, buf); - else if (ndctl_bus_is_papr_scm(dimm->bus)) { - dimm->cmd_family = NVDIMM_FAMILY_PAPR; - parse_papr_flags(dimm, buf); - } - } - dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC); + + ndctl_dimm_refresh_flags(dimm); + rc = 0; err_read: @@ -1826,8 +1841,9 @@ static int add_papr_dimm(struct ndctl_dimm *dimm, const char *dimm_base) rc = 0; } else if (strcmp(buf, "nvdimm_test") == 0) { + dimm->cmd_family = NVDIMM_FAMILY_PAPR; /* probe via common populate_dimm_attributes() */ - rc = populate_dimm_attributes(dimm, dimm_base, "papr"); + rc = populate_dimm_attributes(dimm, dimm_base); } out: free(path); @@ -1924,9 +1940,20 @@ static void *add_dimm(void *parent, int id, const char *dimm_base) dimm->formats = formats; /* Check if the given dimm supports nfit */ if (ndctl_bus_has_nfit(bus)) { - rc = populate_dimm_attributes(dimm, dimm_base, "nfit"); + dimm->bus_prefix = strdup("nfit"); + if (!dimm->bus_prefix) { + rc = -ENOMEM; + goto out; + } + rc = populate_dimm_attributes(dimm, dimm_base); + } else if (ndctl_bus_has_of_node(bus)) { - rc = add_papr_dimm(dimm, dimm_base); + dimm->bus_prefix = strdup("papr"); + if (!dimm->bus_prefix) { + rc = -ENOMEM; + goto out; + } + rc = add_papr_dimm(dimm, dimm_base); } if (rc == -ENODEV) { diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index 3557b32c50ea..f1f9edd4b6ff 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -458,3 +458,7 @@ LIBNDCTL_26 { ndctl_set_config_path; ndctl_get_config_path; } LIBNDCTL_25; + +LIBNDCTL_27 { + ndctl_dimm_refresh_flags; +} LIBNDCTL_26; diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h index 4d8622978790..e5c56295556d 100644 --- a/ndctl/lib/private.h +++ b/ndctl/lib/private.h @@ -75,6 +75,7 @@ struct ndctl_dimm { char *unique_id; char *dimm_path; char *dimm_buf; + char *bus_prefix; int health_eventfd; int buf_len; int id; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index 4d5cdbf6f619..57cf93d8d151 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -223,6 +223,7 @@ int ndctl_dimm_is_active(struct ndctl_dimm *dimm); int ndctl_dimm_is_enabled(struct ndctl_dimm *dimm); int ndctl_dimm_disable(struct ndctl_dimm *dimm); int ndctl_dimm_enable(struct ndctl_dimm *dimm); +void ndctl_dimm_refresh_flags(struct ndctl_dimm *dimm); struct ndctl_cmd; struct ndctl_cmd *ndctl_bus_cmd_new_ars_cap(struct ndctl_bus *bus,