2019-10-09 18:06:43 +02:00
|
|
|
#include <libcbd.h>
|
|
|
|
|
|
|
|
#include <cbdutil.h>
|
|
|
|
|
|
|
|
struct zone_metadata
|
|
|
|
{
|
|
|
|
u8* pblk_alloc;
|
|
|
|
u8* lblk_alloc;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2019-10-10 22:21:36 +02:00
|
|
|
pblk_read(int fd, u64 pblk, u32 count, u8* data)
|
2019-10-09 18:06:43 +02:00
|
|
|
{
|
2019-10-10 22:21:36 +02:00
|
|
|
off_t pos;
|
2019-10-09 18:06:43 +02:00
|
|
|
size_t remain;
|
|
|
|
ssize_t ret;
|
|
|
|
|
2019-10-10 22:21:36 +02:00
|
|
|
pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET);
|
|
|
|
if (pos == (off_t)-1) {
|
2019-10-09 18:06:43 +02:00
|
|
|
error("Failed to seek\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
remain = count * PBLK_SIZE;
|
|
|
|
while (remain) {
|
|
|
|
ret = read(fd, data, remain);
|
|
|
|
if (ret <= 0) {
|
|
|
|
error("Failed to read\n");
|
|
|
|
}
|
|
|
|
remain -= ret;
|
|
|
|
data += ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
check_header(const struct cbd_header* header)
|
|
|
|
{
|
|
|
|
if (memcmp(header->magic, CBD_MAGIC, sizeof(header->magic))) {
|
|
|
|
error("Bad magic\n");
|
|
|
|
}
|
|
|
|
if (header->version_major != CBD_VERSION_MAJOR) {
|
|
|
|
error("Bad major version\n");
|
|
|
|
}
|
|
|
|
if (header->version_minor != CBD_VERSION_MINOR) {
|
|
|
|
error("Bad major version\n");
|
|
|
|
}
|
|
|
|
if (header->params.algorithm == CBD_ALG_NONE ||
|
|
|
|
header->params.algorithm >= CBD_ALG_MAX) {
|
|
|
|
error("Bad algorithm\n");
|
|
|
|
}
|
|
|
|
if (header->params.compression > 9) {
|
|
|
|
error("Bad compression\n");
|
|
|
|
}
|
|
|
|
if (header->params.lblk_shift < LBLK_SHIFT_MIN ||
|
|
|
|
header->params.lblk_shift >= LBLK_SHIFT_MAX) {
|
|
|
|
error("Bad logical block shift\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
check_one_lblk(const struct cbd_params* params,
|
|
|
|
u32 zone,
|
|
|
|
u32 lblk,
|
|
|
|
const struct zone_metadata* zm,
|
|
|
|
u8** pblk_used)
|
|
|
|
{
|
2019-10-09 20:45:30 +02:00
|
|
|
struct lblk_alloc_elem* elem;
|
2019-10-09 20:57:57 +02:00
|
|
|
u8* elem_buf;
|
2019-10-09 18:06:43 +02:00
|
|
|
u32 n;
|
|
|
|
u64 pblk;
|
|
|
|
u32 rel_pblk;
|
|
|
|
|
2019-10-09 20:45:30 +02:00
|
|
|
elem = calloc(1, offsetof(struct lblk_alloc_elem, pblk[lblk_per_pblk(params)]));
|
2019-10-09 20:57:57 +02:00
|
|
|
elem_buf = zm->lblk_alloc + lblk * lblk_alloc_elem_len(params);
|
|
|
|
lblk_alloc_elem_get(params, elem_buf, elem);
|
2019-10-09 20:45:30 +02:00
|
|
|
printf(" lblk[%u]: len=%u\n", lblk, elem->len);
|
2019-10-09 18:06:43 +02:00
|
|
|
for (n = 0; n < lblk_per_pblk(params); ++n) {
|
2019-10-09 20:45:30 +02:00
|
|
|
pblk = elem->pblk[n];
|
|
|
|
if (elem->len > PBLK_SIZE * n) {
|
2019-10-09 18:06:43 +02:00
|
|
|
/* XXX: allow out-of-zone allocs for v1.1 */
|
|
|
|
if (pblk < zone_data_off(params, zone) || pblk >= zone_off(params, zone + 1)) {
|
|
|
|
printf("Alloc out of bounds for zone %u block %u index %u: %lu\n",
|
|
|
|
(unsigned int)zone, lblk, n,
|
|
|
|
(unsigned long)pblk);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
rel_pblk = pblk - zone_data_off(params, zone);
|
|
|
|
printf(" [%u] pblk=%lu rel_pblk=%u\n", n, (unsigned long)pblk, rel_pblk);
|
|
|
|
if (pblk_used[zone][rel_pblk/8] & (1 << (rel_pblk % 8))) {
|
|
|
|
printf("Duplicate allocation for zone %u block %u\n",
|
|
|
|
(unsigned int)zone, (unsigned int)rel_pblk);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
pblk_used[zone][rel_pblk/8] |= (1 << (rel_pblk % 8));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (pblk) {
|
|
|
|
printf("Unexpected pblk alloc for zone %u block %u index %u: %lu\n",
|
|
|
|
(unsigned int)zone, lblk, n,
|
|
|
|
(unsigned long)pblk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-09 20:45:30 +02:00
|
|
|
free(elem);
|
2019-10-09 18:06:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
check_one_zone(const struct cbd_params* params,
|
|
|
|
u32 zone,
|
|
|
|
const struct zone_metadata* zm,
|
|
|
|
u8** pblk_used)
|
|
|
|
{
|
|
|
|
u32 lblk;
|
|
|
|
|
|
|
|
printf("Zone %u: alloc [%lu .. %lu]\n",
|
|
|
|
(unsigned int)zone,
|
|
|
|
(unsigned long)zone_data_off(params, zone),
|
|
|
|
(unsigned long)zone_off(params, zone + 1));
|
|
|
|
for (lblk = 0; lblk < params->lblk_per_zone; ++lblk) {
|
|
|
|
check_one_lblk(params, zone, lblk, zm, pblk_used);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
check_zone_metadata(const struct cbd_params* params,
|
|
|
|
const struct zone_metadata* zmvec)
|
|
|
|
{
|
|
|
|
u8** pblk_used;
|
|
|
|
u32 zone;
|
|
|
|
|
|
|
|
pblk_used = calloc(params->nr_zones, sizeof(void*));
|
|
|
|
for (zone = 0; zone < params->nr_zones; ++zone) {
|
2019-10-09 20:32:36 +02:00
|
|
|
pblk_used[zone] = calloc(1, pblk_alloc_len(params));
|
2019-10-09 18:06:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (zone = 0; zone < params->nr_zones; ++zone) {
|
|
|
|
check_one_zone(params, zone, &zmvec[zone], pblk_used);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (zone = 0; zone < params->nr_zones; ++zone) {
|
|
|
|
free(pblk_used[zone]);
|
|
|
|
}
|
|
|
|
free(pblk_used);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
cbd_check(const char* dev,
|
|
|
|
tristate_t auto_response)
|
|
|
|
{
|
|
|
|
int devfd;
|
|
|
|
struct cbd_header header;
|
|
|
|
uint8_t pblkbuf[PBLK_SIZE];
|
|
|
|
struct zone_metadata* zmvec;
|
|
|
|
u32 zone;
|
|
|
|
|
|
|
|
devfd = open(dev, O_RDONLY);
|
|
|
|
if (devfd < 0) {
|
|
|
|
error("Cannot open device\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
pblk_read(devfd, 0, 1, pblkbuf);
|
|
|
|
cbd_header_get(pblkbuf, &header);
|
|
|
|
check_header(&header);
|
|
|
|
|
|
|
|
zmvec = calloc(header.params.nr_zones, sizeof(struct zone_metadata));
|
|
|
|
for (zone = 0; zone < header.params.nr_zones; ++zone) {
|
|
|
|
zmvec[zone].pblk_alloc = calloc(1, PBLK_SIZE);
|
|
|
|
pblk_read(devfd,
|
2019-10-09 20:32:36 +02:00
|
|
|
pblk_alloc_off(&header.params, zone),
|
|
|
|
pblk_alloc_len(&header.params),
|
2019-10-09 18:06:43 +02:00
|
|
|
zmvec[zone].pblk_alloc);
|
2019-10-09 20:32:36 +02:00
|
|
|
zmvec[zone].lblk_alloc = calloc(lblk_alloc_len(&header.params), PBLK_SIZE);
|
2019-10-09 18:06:43 +02:00
|
|
|
pblk_read(devfd,
|
2019-10-09 20:32:36 +02:00
|
|
|
lblk_alloc_off(&header.params, zone),
|
|
|
|
lblk_alloc_len(&header.params),
|
2019-10-09 18:06:43 +02:00
|
|
|
zmvec[zone].lblk_alloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
check_zone_metadata(&header.params, zmvec);
|
|
|
|
|
|
|
|
for (zone = 0; zone < header.params.nr_zones; ++zone) {
|
|
|
|
free(zmvec[zone].lblk_alloc);
|
|
|
|
free(zmvec[zone].pblk_alloc);
|
|
|
|
}
|
|
|
|
free(zmvec);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|