blob: 0183b7af2052218916cbfe34d8e895b361a1099f [file] [log] [blame]
/*
* Copyright (c) 2014-2016, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*/
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <syslog.h>
#include <test.h>
#include <linux/version.h>
#include <ndctl/libndctl.h>
struct ndctl_namespace *ndctl_get_test_dev(struct ndctl_ctx *ctx)
{
char path[256];
const char *bdev;
int fd, rc = -ENXIO;
struct ndctl_bus *bus;
struct ndctl_dax *dax;
struct ndctl_pfn *pfn;
struct ndctl_region *region;
struct ndctl_namespace *ndns;
enum ndctl_namespace_mode mode;
bus = ndctl_bus_get_by_provider(ctx, "e820");
if (!bus)
goto out;
region = ndctl_region_get_first(bus);
if (!region)
goto out;
ndns = ndctl_namespace_get_first(region);
if (!ndns)
goto out;
mode = ndctl_namespace_get_mode(ndns);
if (mode >= 0 && mode != NDCTL_NS_MODE_MEMORY)
goto out;
/* if device-dax mode already established it might contain user data */
pfn = ndctl_namespace_get_pfn(ndns);
dax = ndctl_namespace_get_dax(ndns);
if (dax || pfn)
goto out;
/* device is unconfigured, assume that was on purpose */
bdev = ndctl_namespace_get_block_device(ndns);
if (!bdev)
goto out;
if (snprintf(path, sizeof(path), "/dev/%s", bdev) >= (int) sizeof(path))
goto out;
/*
* Note, if the bdev goes active after this check we'll still
* clobber it in the following tests, see test/dax.sh and
* test/device-dax.sh.
*/
fd = open(path, O_RDWR | O_EXCL);
if (fd < 0)
goto out;
close(fd);
rc = 0;
out:
return rc ? NULL : ndns;
}
static int emit_e820_device(int loglevel, struct ndctl_test *test)
{
int err;
struct ndctl_ctx *ctx;
struct ndctl_namespace *ndns;
if (!ndctl_test_attempt(test, KERNEL_VERSION(4, 3, 0)))
return 77;
err = ndctl_new(&ctx);
if (err < 0)
return err;
ndctl_set_log_priority(ctx, loglevel);
ndns = ndctl_get_test_dev(ctx);
if (!ndns) {
fprintf(stderr, "%s: failed to find usable victim device\n",
__func__);
ndctl_test_skip(test);
err = 77;
} else {
fprintf(stdout, "%s\n", ndctl_namespace_get_devname(ndns));
err = 0;
}
ndctl_unref(ctx);
return err;
}
int __attribute__((weak)) main(int argc, char *argv[])
{
struct ndctl_test *test = ndctl_test_new(0);
int rc;
if (!test) {
fprintf(stderr, "failed to initialize test\n");
return EXIT_FAILURE;
}
rc = emit_e820_device(LOG_DEBUG, test);
return ndctl_test_result(test, rc);
}