cbd/libcbd/check.c

187 lines
5.2 KiB
C

#include <libcbd.h>
#include <cbdutil.h>
struct zone_metadata
{
u8* pblk_alloc;
u8* lblk_alloc;
};
static void
pblk_read(int fd, size_t pblk, size_t count, u8* data)
{
off_t off;
size_t remain;
ssize_t ret;
off = lseek(fd, pblk * PBLK_SIZE, SEEK_SET);
if (off == (off_t)-1) {
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)
{
struct lblk_alloc_elem* alloc;
u32 n;
u64 pblk;
u32 rel_pblk;
alloc = calloc(1, offsetof(struct lblk_alloc_elem, pblk[lblk_per_pblk(params)]));
lblk_alloc_elem_get(params, zm->lblk_alloc, lblk, alloc);
printf(" lblk[%u]: len=%u\n", lblk, alloc->len);
for (n = 0; n < lblk_per_pblk(params); ++n) {
pblk = alloc->pblk[n];
if (alloc->len > PBLK_SIZE * n) {
/* 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);
}
}
}
free(alloc);
}
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) {
pblk_used[zone] = calloc(1, pblk_alloc_len(params));
}
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,
pblk_alloc_off(&header.params, zone),
pblk_alloc_len(&header.params),
zmvec[zone].pblk_alloc);
zmvec[zone].lblk_alloc = calloc(lblk_alloc_len(&header.params), PBLK_SIZE);
pblk_read(devfd,
lblk_alloc_off(&header.params, zone),
lblk_alloc_len(&header.params),
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;
}