File: dax-dev.c

package info (click to toggle)
ndctl 82-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,460 kB
  • sloc: ansic: 42,027; sh: 3,974; makefile: 28
file content (131 lines) | stat: -rw-r--r-- 2,823 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// SPDX-License-Identifier: LGPL-2.1
// Copyright (C) 2014-2020, Intel Corporation. All rights reserved.
#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_namespace *ndns;
	enum ndctl_namespace_mode mode;
	struct ndctl_region *region, *min = NULL;

	bus = ndctl_bus_get_by_provider(ctx, "e820");
	if (!bus)
		goto out;

	ndctl_region_foreach(bus, region) {
		if (!min) {
			min = region;
			continue;
		}
		if (ndctl_region_get_id(region) < ndctl_region_get_id(min))
			min = region;
	}
	if (!min)
		goto out;
	region = min;

	/* attempt to re-enable the region if a previous test disabled it */
	ndctl_region_enable(region);

	ndns = ndctl_namespace_get_first(region);
	if (!ndns)
		goto out;

	rc = ndctl_namespace_enable(ndns);
	if (rc)
		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);
}