#include #include static void pblk_write(int fd, u64 pblk, u32 count, const u8* data) { off_t pos; size_t remain; ssize_t ret; pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET); if (pos == (off_t)-1) { error("Failed to seek\n"); } remain = count * PBLK_SIZE; while (remain) { ret = write(fd, data, count * PBLK_SIZE); if (ret <= 0) { error("Failed to write\n"); } remain -= ret; data += ret; } } int cbd_format(const char* dev, uint64_t psize, uint16_t lshift, uint64_t lsize, enum cbd_alg alg, uint level) { int devfd; uint32_t lblk_size; struct cbd_header header; uint8_t pblkbuf[PBLK_SIZE]; uint64_t pblk; uint64_t zone_idx; devfd = open(dev, O_RDWR); if (devfd < 0) { error("Cannot open device\n"); } if (!psize) { off_t pos; pos = lseek(devfd, 0, SEEK_END); if (pos == (off_t)-1) { error("Cannot seek device\n"); } psize = pos / PBLK_SIZE * PBLK_SIZE; } if (!lshift) { lshift = CBD_DEFAULT_LOGICAL_BLOCK_SHIFT; } lblk_size = 1 << (lshift + PBLK_SHIFT); if (!lsize) { /* XXX: Why is the cast needed here? */ lsize = (uint64_t)(psize * CBD_DEFAULT_COMPRESSION_FACTOR) / lblk_size * lblk_size; } if (psize % PBLK_SIZE) { error("Physical size %lu is not a multiple of %u bytes\n", (ulong)psize, (uint)PBLK_SIZE); } if (lshift < LBLK_SHIFT_MIN || lshift > LBLK_SHIFT_MAX) { error("Logical shift %hu is not in [%u,%u]\n", (ushort)lshift, (uint)LBLK_SHIFT_MIN, (uint)LBLK_SHIFT_MAX); } if (lsize % (1 << (lshift + PBLK_SHIFT))) { error("Logical size %lu is not a multiple of %u bytes\n", (ulong)psize, (uint)lblk_size); } if (alg <= CBD_ALG_NONE || alg >= CBD_ALG_MAX) { error("Compression algorithm %d unknown\n", (int)alg); } if (level < 1 || level > 9) { error("Compression level %u out of bounds\n", level); } printf("%s: paramaters...\n", __func__); printf(" psize=%lu\n", (unsigned long)psize); printf(" lshift=%hu\n", (unsigned short)lshift); printf(" lsize=%lu\n", (unsigned long)lsize); memset(&header, 0, sizeof(header)); memcpy(header.magic, CBD_MAGIC, sizeof(header.magic)); header.version_major = CBD_VERSION_MAJOR; header.version_minor = CBD_VERSION_MINOR; header.params.algorithm = alg; header.params.compression = level; header.params.lblk_shift = lshift; header.params.nr_pblk = psize / PBLK_SIZE; /* XXX: Initial estimate */ header.params.lblk_per_zone = zone_data_len(&header.params) * (lsize / lblk_size) / (psize / PBLK_SIZE); printf(" initial estimate for lblk_per_zone: %lu\n", (unsigned long)header.params.lblk_per_zone); header.params.nr_zones = ((psize >> PBLK_SHIFT) - CBD_HEADER_BLOCKS) / zone_len(&header.params); header.params.lblk_per_zone = DIV_ROUND_UP(lsize / lblk_size, header.params.nr_zones); printf("%s: parameters...\n", __func__); printf(" algorithm=%d\n", (int)header.params.algorithm); printf(" compression=%u\n", (unsigned int)header.params.compression); printf(" lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift); printf(" nr_pblk=%lu\n", (unsigned long)header.params.nr_pblk); printf(" nr_zones=%lu\n", (unsigned long)header.params.nr_zones); printf(" lblk_per_zone=%lu\n", (unsigned long)header.params.lblk_per_zone); memset(pblkbuf, 0, sizeof(pblkbuf)); cbd_header_put(pblkbuf, &header); pblk = 0; pblk_write(devfd, pblk, 1, pblkbuf); pblk += CBD_HEADER_BLOCKS; printf("Writing %lu zones starting at %lu\n", (unsigned long)header.params.nr_zones, (unsigned long)pblk); memset(pblkbuf, 0, sizeof(pblkbuf)); for (zone_idx = 0; zone_idx < header.params.nr_zones; ++zone_idx) { uint32_t count; uint32_t n; pblk = zone_off(&header.params, zone_idx); count = zone_metadata_len(&header.params); printf(" Zone %lu pblk=%lu count=%u\n", (unsigned long)zone_idx, (unsigned long)pblk, (unsigned int)count); for (n = 0; n < count; ++n) { pblk_write(devfd, pblk + n, 1, pblkbuf); } } return 0; }