@@ -2868,6 +2868,32 @@ NDCTL_EXPORT const char *ndctl_namespace_get_block_device(struct ndctl_namespace
return ndns->bdev ? ndns->bdev : "";
}
+NDCTL_EXPORT enum ndctl_namespace_mode ndctl_namespace_get_mode(
+ struct ndctl_namespace *ndns)
+{
+ struct ndctl_ctx *ctx = ndctl_namespace_get_ctx(ndns);
+ char *path = ndns->ndns_buf;
+ int len = ndns->buf_len;
+ char buf[SYSFS_ATTR_SIZE];
+
+ if (snprintf(path, len, "%s/mode", ndns->ndns_path) >= len) {
+ err(ctx, "%s: buffer too small!\n",
+ ndctl_namespace_get_devname(ndns));
+ return -ENOMEM;
+ }
+
+ if (sysfs_read_attr(ctx, path, buf) < 0)
+ return -ENXIO;
+
+ if (strcmp("memory", buf) == 0)
+ return NDCTL_NS_MODE_MEMORY;
+ if (strcmp("raw", buf) == 0)
+ return NDCTL_NS_MODE_RAW;
+ if (strcmp("safe", buf) == 0)
+ return NDCTL_NS_MODE_SAFE;
+ return -ENXIO;
+}
+
NDCTL_EXPORT int ndctl_namespace_is_valid(struct ndctl_namespace *ndns)
{
struct ndctl_region *region = ndctl_namespace_get_region(ndns);
@@ -132,6 +132,7 @@ global:
ndctl_namespace_get_id;
ndctl_namespace_get_devname;
ndctl_namespace_get_block_device;
+ ndctl_namespace_get_mode;
ndctl_region_get_nstype;
ndctl_namespace_get_type;
ndctl_namespace_get_type_name;
@@ -34,6 +34,7 @@ static int emit_e820_device(int loglevel, struct ndctl_test *test)
struct ndctl_bus *bus;
struct ndctl_region *region;
struct ndctl_namespace *ndns;
+ struct ndctl_namespace_mode mode;
if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 3, 0)))
return 77;
@@ -56,6 +57,10 @@ static int emit_e820_device(int loglevel, struct ndctl_test *test)
if (!ndns)
goto out;
+ mode = ndctl_namespace_get_mode(ndns);
+ if (mode >= 0 && mode != NDCTL_NS_MODE_MEMORY)
+ goto out;
+
bdev = ndctl_namespace_get_block_device(ndns);
if (!bdev)
goto out;
@@ -575,6 +575,7 @@ static int __check_pfn_create(struct ndctl_region *region,
uuid_t uuid)
{
struct ndctl_pfn *pfn_seed = ndctl_region_get_pfn_seed(region);
+ enum ndctl_namespace_mode mode;
struct ndctl_pfn *pfn;
const char *devname;
int fd, retry = 10;
@@ -600,6 +601,12 @@ static int __check_pfn_create(struct ndctl_region *region,
ndctl_pfn_delete(pfn);
return 0;
}
+
+ mode = ndctl_namespace_get_mode(ndns);
+ if (mode >= 0 && mode != NDCTL_NS_MODE_MEMORY)
+ fprintf(stderr, "%s: expected memory mode got: %d\n",
+ devname, mode);
+
if (namespace->ro == (rc == 0)) {
fprintf(stderr, "%s: expected pfn enable %s, %s read-%s\n",
devname,
@@ -718,6 +725,7 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
for (i = 0; i < btt_s->num_sector_sizes; i++) {
struct ndctl_namespace *ns_seed = ndctl_region_get_namespace_seed(region);
struct ndctl_btt *btt_seed = ndctl_region_get_btt_seed(region);
+ enum ndctl_namespace_mode mode;
btt = get_idle_btt(region);
if (!btt)
@@ -737,6 +745,11 @@ static int check_btt_create(struct ndctl_region *region, struct ndctl_namespace
goto err;
}
+ mode = ndctl_namespace_get_mode(ndns);
+ if (mode >= 0 && mode != NDCTL_NS_MODE_SAFE)
+ fprintf(stderr, "%s: expected safe mode got: %d\n",
+ devname, mode);
+
if (btt_seed == ndctl_region_get_btt_seed(region)
&& btt == btt_seed) {
fprintf(stderr, "%s: failed to advance btt seed\n",
The three modes for a namespace are: 1/ 'memory': the kernel has the infrastructure to support the usage of DAX mappings of this namespace in any context. In contrast to a 'raw' pmem namespace that, for example, does not support direct I/O in current kernels. 2/ 'safe': the namespace is being fronted by a btt to provide atomic sector udpates. 3/ 'raw': Neither of the above two modes, this namespace may tear sectors on interrupted writes or fail direct I/O requests. Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- lib/libndctl.c | 26 ++++++++++++++++++++++++++ lib/libndctl.sym | 1 + lib/test-dax-dev.c | 5 +++++ lib/test-libndctl.c | 13 +++++++++++++ 4 files changed, 45 insertions(+)