summaryrefslogtreecommitdiffstats
path: root/src/pmdk/src/common/pool_hdr.c
blob: dc6985f099380ec92c88eaa890f4a8ad8ce84419 (plain)
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
// SPDX-License-Identifier: BSD-3-Clause
/* Copyright 2014-2019, Intel Corporation */

/*
 * pool_hdr.c -- pool header utilities
 */

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <endian.h>

#include "out.h"
#include "pool_hdr.h"

/* Determine ISA for which PMDK is currently compiled */
#if defined(__x86_64) || defined(_M_X64)
/* x86 -- 64 bit */
#define PMDK_MACHINE PMDK_MACHINE_X86_64
#define PMDK_MACHINE_CLASS PMDK_MACHINE_CLASS_64

#elif defined(__aarch64__)
/* 64 bit ARM not supported yet */
#define PMDK_MACHINE PMDK_MACHINE_AARCH64
#define PMDK_MACHINE_CLASS PMDK_MACHINE_CLASS_64

#elif defined(__PPC64__)
#define PMDK_MACHINE PMDK_MACHINE_PPC64
#define PMDK_MACHINE_CLASS PMDK_MACHINE_CLASS_64

#else
/* add appropriate definitions here when porting PMDK to another ISA */
#error unable to recognize ISA at compile time

#endif

/*
 * arch_machine -- (internal) determine endianness
 */
static uint8_t
arch_data(void)
{
	uint16_t word = (PMDK_DATA_BE << 8) + PMDK_DATA_LE;
	return ((uint8_t *)&word)[0];
}

/*
 * util_get_arch_flags -- get architecture identification flags
 */
void
util_get_arch_flags(struct arch_flags *arch_flags)
{
	memset(arch_flags, 0, sizeof(*arch_flags));
	arch_flags->machine = PMDK_MACHINE;
	arch_flags->machine_class = PMDK_MACHINE_CLASS;
	arch_flags->data = arch_data();
	arch_flags->alignment_desc = alignment_desc();
}

/*
 * util_convert2le_hdr -- convert pool_hdr into little-endian byte order
 */
void
util_convert2le_hdr(struct pool_hdr *hdrp)
{
	hdrp->major = htole32(hdrp->major);
	hdrp->features.compat = htole32(hdrp->features.compat);
	hdrp->features.incompat = htole32(hdrp->features.incompat);
	hdrp->features.ro_compat = htole32(hdrp->features.ro_compat);
	hdrp->arch_flags.alignment_desc =
		htole64(hdrp->arch_flags.alignment_desc);
	hdrp->arch_flags.machine = htole16(hdrp->arch_flags.machine);
	hdrp->crtime = htole64(hdrp->crtime);
	hdrp->checksum = htole64(hdrp->checksum);
}

/*
 * util_convert2h_hdr_nocheck -- convert pool_hdr into host byte order
 */
void
util_convert2h_hdr_nocheck(struct pool_hdr *hdrp)
{
	hdrp->major = le32toh(hdrp->major);
	hdrp->features.compat = le32toh(hdrp->features.compat);
	hdrp->features.incompat = le32toh(hdrp->features.incompat);
	hdrp->features.ro_compat = le32toh(hdrp->features.ro_compat);
	hdrp->crtime = le64toh(hdrp->crtime);
	hdrp->arch_flags.machine = le16toh(hdrp->arch_flags.machine);
	hdrp->arch_flags.alignment_desc =
		le64toh(hdrp->arch_flags.alignment_desc);
	hdrp->checksum = le64toh(hdrp->checksum);
}

/*
 * util_arch_flags_check -- validates arch_flags
 */
int
util_check_arch_flags(const struct arch_flags *arch_flags)
{
	struct arch_flags cur_af;
	int ret = 0;

	util_get_arch_flags(&cur_af);

	if (!util_is_zeroed(&arch_flags->reserved,
				sizeof(arch_flags->reserved))) {
		ERR("invalid reserved values");
		ret = -1;
	}

	if (arch_flags->machine != cur_af.machine) {
		ERR("invalid machine value");
		ret = -1;
	}

	if (arch_flags->data != cur_af.data) {
		ERR("invalid data value");
		ret = -1;
	}

	if (arch_flags->machine_class != cur_af.machine_class) {
		ERR("invalid machine_class value");
		ret = -1;
	}

	if (arch_flags->alignment_desc != cur_af.alignment_desc) {
		ERR("invalid alignment_desc value");
		ret = -1;
	}

	return ret;
}

/*
 * util_get_unknown_features -- filter out unknown features flags
 */
features_t
util_get_unknown_features(features_t features, features_t known)
{
	features_t unknown;
	unknown.compat = util_get_not_masked_bits(
			features.compat, known.compat);
	unknown.incompat = util_get_not_masked_bits(
			features.incompat, known.incompat);
	unknown.ro_compat = util_get_not_masked_bits(
			features.ro_compat, known.ro_compat);
	return unknown;
}

/*
 * util_feature_check -- check features masks
 */
int
util_feature_check(struct pool_hdr *hdrp, features_t known)
{
	LOG(3, "hdrp %p features {incompat %#x ro_compat %#x compat %#x}",
			hdrp,
			known.incompat, known.ro_compat, known.compat);

	features_t unknown = util_get_unknown_features(hdrp->features, known);

	/* check incompatible ("must support") features */
	if (unknown.incompat) {
		ERR("unsafe to continue due to unknown incompat "\
				"features: %#x", unknown.incompat);
		errno = EINVAL;
		return -1;
	}

	/* check RO-compatible features (force RO if unsupported) */
	if (unknown.ro_compat) {
		ERR("switching to read-only mode due to unknown ro_compat "\
				"features: %#x", unknown.ro_compat);
		return 0;
	}

	/* check compatible ("may") features */
	if (unknown.compat) {
		LOG(3, "ignoring unknown compat features: %#x", unknown.compat);
	}

	return 1;
}

/*
 * util_feature_cmp -- compares features with reference
 *
 * returns 1 if features and reference match and 0 otherwise
 */
int
util_feature_cmp(features_t features, features_t ref)
{
	LOG(3, "features {incompat %#x ro_compat %#x compat %#x} "
			"ref {incompat %#x ro_compat %#x compat %#x}",
			features.incompat, features.ro_compat, features.compat,
			ref.incompat, ref.ro_compat, ref.compat);

	return features.compat == ref.compat &&
			features.incompat == ref.incompat &&
			features.ro_compat == ref.ro_compat;
}

/*
 * util_feature_is_zero -- check if features flags are zeroed
 *
 * returns 1 if features is zeroed and 0 otherwise
 */
int
util_feature_is_zero(features_t features)
{
	const uint32_t bits =
			features.compat | features.incompat |
			features.ro_compat;
	return bits ? 0 : 1;
}

/*
 * util_feature_is_set -- check if feature flag is set in features
 *
 * returns 1 if feature flag is set and 0 otherwise
 */
int
util_feature_is_set(features_t features, features_t flag)
{
	uint32_t bits = 0;
	bits |= features.compat & flag.compat;
	bits |= features.incompat & flag.incompat;
	bits |= features.ro_compat & flag.ro_compat;
	return bits ? 1 : 0;
}

/*
 * util_feature_enable -- enable feature
 */
void
util_feature_enable(features_t *features, features_t new_feature)
{
#define FEATURE_ENABLE(flags, X) \
	(flags) |= (X)

	FEATURE_ENABLE(features->compat, new_feature.compat);
	FEATURE_ENABLE(features->incompat, new_feature.incompat);
	FEATURE_ENABLE(features->ro_compat, new_feature.ro_compat);

#undef FEATURE_ENABLE
}

/*
 * util_feature_disable -- (internal) disable feature
 */
void
util_feature_disable(features_t *features, features_t old_feature)
{
#define FEATURE_DISABLE(flags, X) \
	(flags) &= ~(X)

	FEATURE_DISABLE(features->compat, old_feature.compat);
	FEATURE_DISABLE(features->incompat, old_feature.incompat);
	FEATURE_DISABLE(features->ro_compat, old_feature.ro_compat);

#undef FEATURE_DISABLE
}

static const features_t feature_2_pmempool_feature_map[] = {
	FEAT_INCOMPAT(SINGLEHDR),	/* PMEMPOOL_FEAT_SINGLEHDR */
	FEAT_INCOMPAT(CKSUM_2K),	/* PMEMPOOL_FEAT_CKSUM_2K */
	FEAT_INCOMPAT(SDS),		/* PMEMPOOL_FEAT_SHUTDOWN_STATE */
	FEAT_COMPAT(CHECK_BAD_BLOCKS),	/* PMEMPOOL_FEAT_CHECK_BAD_BLOCKS */
};

#define FEAT_2_PMEMPOOL_FEATURE_MAP_SIZE \
	ARRAY_SIZE(feature_2_pmempool_feature_map)

static const char *str_2_pmempool_feature_map[] = {
	"SINGLEHDR",
	"CKSUM_2K",
	"SHUTDOWN_STATE",
	"CHECK_BAD_BLOCKS",
};

#define PMEMPOOL_FEATURE_2_STR_MAP_SIZE ARRAY_SIZE(str_2_pmempool_feature_map)

/*
 * util_str2feature -- convert string to feat_flags value
 */
features_t
util_str2feature(const char *str)
{
	/* all features have to be named in incompat_features_str array */
	COMPILE_ERROR_ON(FEAT_2_PMEMPOOL_FEATURE_MAP_SIZE !=
			PMEMPOOL_FEATURE_2_STR_MAP_SIZE);

	for (uint32_t f = 0; f < PMEMPOOL_FEATURE_2_STR_MAP_SIZE; ++f) {
		if (strcmp(str, str_2_pmempool_feature_map[f]) == 0) {
			return feature_2_pmempool_feature_map[f];
		}
	}
	return features_zero;
}

/*
 * util_feature2pmempool_feature -- convert feature to pmempool_feature
 */
uint32_t
util_feature2pmempool_feature(features_t feat)
{
	for (uint32_t pf = 0; pf < FEAT_2_PMEMPOOL_FEATURE_MAP_SIZE; ++pf) {
		const features_t *record =
				&feature_2_pmempool_feature_map[pf];
		if (util_feature_cmp(feat, *record)) {
			return pf;
		}
	}
	return UINT32_MAX;
}

/*
 * util_str2pmempool_feature -- convert string to uint32_t enum pmempool_feature
 * equivalent
 */
uint32_t
util_str2pmempool_feature(const char *str)
{
	features_t fval = util_str2feature(str);
	if (util_feature_is_zero(fval))
		return UINT32_MAX;
	return util_feature2pmempool_feature(fval);
}

/*
 * util_feature2str -- convert uint32_t feature to string
 */
const char *
util_feature2str(features_t features, features_t *found)
{
	for (uint32_t i = 0; i < FEAT_2_PMEMPOOL_FEATURE_MAP_SIZE; ++i) {
		const features_t *record = &feature_2_pmempool_feature_map[i];
		if (util_feature_is_set(features, *record)) {
			if (found)
				memcpy(found, record, sizeof(features_t));
			return str_2_pmempool_feature_map[i];
		}
	}
	return NULL;
}