Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/nvdimm/nvdimm.c
Show First 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static bool | static bool | ||||
label_index_is_valid(struct nvdimm_label_index *index, uint32_t max_labels, | label_index_is_valid(struct nvdimm_label_index *index, uint32_t max_labels, | ||||
size_t size, size_t offset) | size_t size, size_t offset) | ||||
{ | { | ||||
uint64_t checksum; | uint64_t checksum; | ||||
index = (struct nvdimm_label_index *)((uint8_t *)index + offset); | index = (struct nvdimm_label_index *)((uint8_t *)index + size * offset); | ||||
if (strcmp(index->signature, NVDIMM_INDEX_BLOCK_SIGNATURE) != 0) | if (strcmp(index->signature, NVDIMM_INDEX_BLOCK_SIGNATURE) != 0) | ||||
return false; | return false; | ||||
checksum = index->checksum; | checksum = index->checksum; | ||||
index->checksum = 0; | index->checksum = 0; | ||||
if (checksum != fletcher64(index, size) || | if (checksum != fletcher64(index, size) || | ||||
index->this_offset != size * offset || index->this_size != size || | index->this_offset != size * offset || index->this_size != size || | ||||
index->other_offset != size * (offset == 0 ? 1 : 0) || | index->other_offset != size * (offset == 0 ? 1 : 0) || | ||||
index->seq == 0 || index->seq > 3 || index->slot_cnt > max_labels || | index->seq == 0 || index->seq > 3 || index->slot_cnt > max_labels || | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | SLIST_FOREACH_SAFE(i, &nv->labels, link, next) { | ||||
} | } | ||||
} | } | ||||
__unreachable(); | __unreachable(); | ||||
} | } | ||||
static int | static int | ||||
read_labels(struct nvdimm_dev *nv) | read_labels(struct nvdimm_dev *nv) | ||||
{ | { | ||||
struct nvdimm_label_index *indices; | struct nvdimm_label_index *indices, *index1; | ||||
size_t bitfield_size, index_size, num_labels; | size_t bitfield_size, index_size, num_labels; | ||||
int error, n; | int error, n; | ||||
bool index_0_valid, index_1_valid; | bool index_0_valid, index_1_valid; | ||||
for (index_size = 256; ; index_size += 256) { | for (index_size = 256; ; index_size += 256) { | ||||
num_labels = 8 * (index_size - | num_labels = 8 * (index_size - | ||||
sizeof(struct nvdimm_label_index)); | sizeof(struct nvdimm_label_index)); | ||||
if (index_size + num_labels * sizeof(struct nvdimm_label) >= | if (index_size + num_labels * sizeof(struct nvdimm_label) >= | ||||
nv->label_area_size) | nv->label_area_size) | ||||
break; | break; | ||||
} | } | ||||
num_labels = (nv->label_area_size - index_size) / | num_labels = (nv->label_area_size - index_size) / | ||||
sizeof(struct nvdimm_label); | sizeof(struct nvdimm_label); | ||||
bitfield_size = roundup2(num_labels, 8) / 8; | bitfield_size = roundup2(num_labels, 8) / 8; | ||||
indices = malloc(2 * index_size, M_NVDIMM, M_WAITOK); | indices = malloc(2 * index_size, M_NVDIMM, M_WAITOK); | ||||
index1 = (void *)((uint8_t *)indices + index_size); | |||||
error = read_label_area(nv, (void *)indices, 0, 2 * index_size); | error = read_label_area(nv, (void *)indices, 0, 2 * index_size); | ||||
if (error != 0) { | if (error != 0) { | ||||
free(indices, M_NVDIMM); | free(indices, M_NVDIMM); | ||||
return (error); | return (error); | ||||
} | } | ||||
index_0_valid = label_index_is_valid(indices, num_labels, index_size, | index_0_valid = label_index_is_valid(indices, num_labels, index_size, | ||||
0); | 0); | ||||
index_1_valid = label_index_is_valid(indices, num_labels, index_size, | index_1_valid = label_index_is_valid(indices, num_labels, index_size, | ||||
1); | 1); | ||||
if (!index_0_valid && !index_1_valid) { | if (!index_0_valid && !index_1_valid) { | ||||
free(indices, M_NVDIMM); | free(indices, M_NVDIMM); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
if (index_0_valid && index_1_valid && | if (index_0_valid && index_1_valid) { | ||||
(indices[1].seq > indices[0].seq || | if (((int)indices->seq - (int)index1->seq + 3) % 3 == 1) { | ||||
(indices[1].seq == 1 && indices[0].seq == 3))) | /* index 0 was more recently updated */ | ||||
index_1_valid = false; | |||||
} else { | |||||
/* | |||||
* either index 1 was more recently updated, | |||||
* or the sequence numbers are equal, in which | |||||
* case the specification says the block with | |||||
* the higher offset is to be treated as valid | |||||
*/ | |||||
index_0_valid = false; | index_0_valid = false; | ||||
} | |||||
} | |||||
nv->label_index = malloc(index_size, M_NVDIMM, M_WAITOK); | nv->label_index = malloc(index_size, M_NVDIMM, M_WAITOK); | ||||
bcopy(indices + (index_0_valid ? 0 : 1), nv->label_index, index_size); | bcopy(index_0_valid ? indices : index1, nv->label_index, index_size); | ||||
free(indices, M_NVDIMM); | free(indices, M_NVDIMM); | ||||
for (bit_ffc_at((bitstr_t *)nv->label_index->free, 0, num_labels, &n); | bit_ffc_at((bitstr_t *)nv->label_index->free, 0, | ||||
n >= 0; | nv->label_index->slot_cnt, &n); | ||||
bit_ffc_at((bitstr_t *)nv->label_index->free, n + 1, num_labels, | while (n >= 0) { | ||||
&n)) { | |||||
read_label(nv, n); | read_label(nv, n); | ||||
bit_ffc_at((bitstr_t *)nv->label_index->free, n + 1, | |||||
nv->label_index->slot_cnt, &n); | |||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
struct nvdimm_dev * | struct nvdimm_dev * | ||||
nvdimm_find_by_handle(nfit_handle_t nv_handle) | nvdimm_find_by_handle(nfit_handle_t nv_handle) | ||||
{ | { | ||||
struct nvdimm_dev *res; | struct nvdimm_dev *res; | ||||
▲ Show 20 Lines • Show All 107 Lines • Show Last 20 Lines |