2019-10-09 18:06:43 +02:00
|
|
|
#include <libcbd.h>
|
|
|
|
|
|
|
|
#include <cbdutil.h>
|
|
|
|
|
|
|
|
static void
|
2019-11-12 22:25:46 +01:00
|
|
|
pblk_write(int fd, u32 pblk_size, u64 pblk, u32 count, const 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-11-12 22:25:46 +01:00
|
|
|
pos = lseek(fd, pblk * pblk_size, SEEK_SET);
|
2019-10-10 22:21:36 +02:00
|
|
|
if (pos == (off_t)-1) {
|
2019-10-09 18:06:43 +02:00
|
|
|
error("Failed to seek\n");
|
|
|
|
}
|
|
|
|
|
2019-11-12 22:25:46 +01:00
|
|
|
remain = count * pblk_size;
|
2019-10-09 18:06:43 +02:00
|
|
|
while (remain) {
|
2019-11-12 22:25:46 +01:00
|
|
|
ret = write(fd, data, remain);
|
2019-10-09 18:06:43 +02:00
|
|
|
if (ret <= 0) {
|
|
|
|
error("Failed to write\n");
|
|
|
|
}
|
|
|
|
remain -= ret;
|
|
|
|
data += ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
cbd_format(const char* dev,
|
2019-11-12 22:25:46 +01:00
|
|
|
enum cbd_alg alg, uint level,
|
2019-11-14 00:13:12 +01:00
|
|
|
uint8_t pshift, uint8_t lshift,
|
|
|
|
uint8_t pbatshift,
|
2019-11-15 19:30:47 +01:00
|
|
|
uint64_t psize, uint64_t lsize,
|
|
|
|
bool full_init)
|
2019-10-09 18:06:43 +02:00
|
|
|
{
|
|
|
|
int devfd;
|
2019-11-12 22:25:46 +01:00
|
|
|
uint pblk_size;
|
|
|
|
uint lblk_size;
|
2019-11-15 19:30:47 +01:00
|
|
|
uint32_t est_zone_len;
|
2019-10-09 18:06:43 +02:00
|
|
|
struct cbd_header header;
|
2019-11-14 13:58:30 +01:00
|
|
|
uint8_t header_buf[PAGE_SIZE];
|
2019-10-09 18:06:43 +02:00
|
|
|
|
|
|
|
devfd = open(dev, O_RDWR);
|
|
|
|
if (devfd < 0) {
|
|
|
|
error("Cannot open device\n");
|
|
|
|
}
|
|
|
|
|
2019-11-14 00:13:12 +01:00
|
|
|
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);
|
|
|
|
}
|
2019-11-12 22:25:46 +01:00
|
|
|
if (!pshift) {
|
|
|
|
pshift = CBD_DEFAULT_PHYSICAL_BLOCK_SHIFT;
|
2019-10-09 18:06:43 +02:00
|
|
|
}
|
2019-11-12 22:25:46 +01:00
|
|
|
if (pshift < PBLK_SHIFT_MIN || pshift > PBLK_SHIFT_MAX) {
|
|
|
|
error("Physical block shift %u is not in [%u,%u]\n",
|
|
|
|
(uint)pshift, (uint)PBLK_SHIFT_MIN, (uint)PBLK_SHIFT_MAX);
|
2019-11-03 23:55:06 +01:00
|
|
|
}
|
2019-11-12 22:25:46 +01:00
|
|
|
pblk_size = SECTOR_SIZE * (1 << pshift);
|
2019-10-09 18:06:43 +02:00
|
|
|
if (!lshift) {
|
|
|
|
lshift = CBD_DEFAULT_LOGICAL_BLOCK_SHIFT;
|
|
|
|
}
|
2019-10-10 22:21:36 +02:00
|
|
|
if (lshift < LBLK_SHIFT_MIN || lshift > LBLK_SHIFT_MAX) {
|
2019-11-12 22:25:46 +01:00
|
|
|
error("Logical block shift %u is not in [%u,%u]\n",
|
|
|
|
(uint)lshift, (uint)LBLK_SHIFT_MIN, (uint)LBLK_SHIFT_MAX);
|
2019-10-10 22:21:36 +02:00
|
|
|
}
|
2019-11-12 22:25:46 +01:00
|
|
|
lblk_size = pblk_size * (1 << lshift);
|
2019-11-14 00:13:12 +01:00
|
|
|
if (pbatshift < PBAT_SHIFT_MIN || pbatshift > PBAT_SHIFT_MAX) {
|
|
|
|
error("Physical block allocation table shift %u is not in [%u,%u]\n",
|
|
|
|
(uint)pbatshift, (uint)PBAT_SHIFT_MIN, (uint)PBAT_SHIFT_MAX);
|
2019-10-31 18:24:20 +01:00
|
|
|
}
|
2019-11-12 22:25:46 +01:00
|
|
|
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 (psize % pblk_size) {
|
|
|
|
error("Physical size %lu is not a multiple of %u bytes\n", (ulong)psize, pblk_size);
|
|
|
|
}
|
|
|
|
if (!lsize) {
|
|
|
|
/* XXX: Why is the cast needed here? */
|
|
|
|
lsize = (uint64_t)(psize * CBD_DEFAULT_COMPRESSION_FACTOR) / lblk_size * lblk_size;
|
|
|
|
}
|
|
|
|
if (lsize % lblk_size) {
|
|
|
|
error("Logical size %lu is not a multiple of %u bytes\n", (ulong)lsize, lblk_size);
|
|
|
|
}
|
2019-10-09 18:06:43 +02:00
|
|
|
|
2019-11-12 22:25:46 +01:00
|
|
|
printf("%s: parameters...\n", __func__);
|
|
|
|
printf(" pshift=%u\n", (unsigned int)pshift);
|
|
|
|
printf(" lshift=%u\n", (unsigned int)lshift);
|
2019-11-14 00:13:12 +01:00
|
|
|
printf(" pbatshift=%u\n", (unsigned int)pbatshift);
|
2019-11-12 22:25:46 +01:00
|
|
|
printf(" alg=%d\n", (int)alg);
|
|
|
|
printf(" level=%u\n", level);
|
|
|
|
printf(" psize=%lu\n", (unsigned long)psize);
|
2019-10-10 22:21:36 +02:00
|
|
|
printf(" lsize=%lu\n", (unsigned long)lsize);
|
2019-10-09 18:06:43 +02:00
|
|
|
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;
|
2019-11-04 15:14:37 +01:00
|
|
|
header.params.flags = 0;
|
2019-11-12 22:25:46 +01:00
|
|
|
header.params.compression = 0;
|
|
|
|
cbd_compression_alg_put(&header.params, alg);
|
|
|
|
cbd_compression_level_put(&header.params, level);
|
|
|
|
header.params.pblk_shift = pshift;
|
2019-10-09 18:06:43 +02:00
|
|
|
header.params.lblk_shift = lshift;
|
2019-11-12 22:25:46 +01:00
|
|
|
header.params.lba_elem_pblk_bytes =
|
|
|
|
((psize / pblk_size) <= 0xffff ? 2 :
|
|
|
|
((psize / pblk_size) <= 0xffffffff ? 4 : 6));
|
2019-11-14 00:13:12 +01:00
|
|
|
header.params.pbat_shift = pbatshift;
|
|
|
|
if (pbat_len(&header.params) * pblk_size > PAGE_SIZE) {
|
|
|
|
error("Physical block allocation table too large\n");
|
|
|
|
}
|
|
|
|
if (lba_len(&header.params) > pblk_size) {
|
|
|
|
error("lba element size too large\n");
|
|
|
|
}
|
2019-10-09 18:06:43 +02:00
|
|
|
/* XXX: Initial estimate */
|
2019-11-12 22:25:46 +01:00
|
|
|
header.params.lblk_per_zone = zone_data_len(&header.params) * (lsize / lblk_size) / (psize / pblk_size);
|
2019-11-15 19:30:47 +01:00
|
|
|
printf(" initial estimate for lblk_per_zone: %u\n", (unsigned int)header.params.lblk_per_zone);
|
2019-11-12 22:25:46 +01:00
|
|
|
header.params.nr_zones = ((psize / pblk_size) - CBD_HEADER_BLOCKS) / zone_len(&header.params);
|
2019-11-15 19:30:47 +01:00
|
|
|
est_zone_len = zone_len(&header.params);
|
2019-10-10 22:21:36 +02:00
|
|
|
header.params.lblk_per_zone = DIV_ROUND_UP(lsize / lblk_size, header.params.nr_zones);
|
2019-11-15 19:30:47 +01:00
|
|
|
while (zone_len(&header.params) > est_zone_len) {
|
|
|
|
--header.params.lblk_per_zone;
|
|
|
|
}
|
|
|
|
header.params.init_zones = 0;
|
2019-11-12 22:25:46 +01:00
|
|
|
printf("%s: header...\n", __func__);
|
|
|
|
printf(" compression=0x%02x\n", (unsigned int)header.params.compression);
|
|
|
|
printf(" pblk_shift=%hu\n", (unsigned short)header.params.pblk_shift);
|
2019-10-09 18:06:43 +02:00
|
|
|
printf(" lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift);
|
2019-11-12 22:25:46 +01:00
|
|
|
printf(" lba_elem_pblk_bytes=%hu\n", (unsigned short)header.params.lba_elem_pblk_bytes);
|
2019-11-14 00:13:12 +01:00
|
|
|
printf(" pbat_shift=%hu\n", (unsigned short)header.params.pbat_shift);
|
2019-11-15 19:30:47 +01:00
|
|
|
printf(" nr_zones=%u\n", (unsigned int)header.params.nr_zones);
|
|
|
|
printf(" lblk_per_zone=%u\n", (unsigned int)header.params.lblk_per_zone);
|
2019-10-09 18:06:43 +02:00
|
|
|
|
2019-11-14 13:58:30 +01:00
|
|
|
memset(header_buf, 0, sizeof(header_buf));
|
|
|
|
cbd_header_put(header_buf, &header);
|
2019-11-15 19:30:47 +01:00
|
|
|
pblk_write(devfd, pblk_size, 0, 1, header_buf);
|
2019-10-09 18:06:43 +02:00
|
|
|
|
2019-11-15 19:30:47 +01:00
|
|
|
if (full_init) {
|
|
|
|
uint32_t nr_pblk = zone_metadata_len(&header.params);
|
|
|
|
uint8_t* data_buf;
|
|
|
|
uint64_t pblk;
|
|
|
|
time_t now;
|
|
|
|
time_t next_write;
|
|
|
|
printf("Writing %lu zones ...\n",
|
|
|
|
(unsigned long)header.params.nr_zones);
|
2019-10-09 18:06:43 +02:00
|
|
|
|
2019-11-15 19:30:47 +01:00
|
|
|
data_buf = calloc(nr_pblk, pblk_size);
|
|
|
|
next_write = time(NULL) + 5;
|
|
|
|
while (header.params.init_zones < header.params.nr_zones) {
|
|
|
|
pblk = zone_off(&header.params, header.params.init_zones);
|
|
|
|
pblk_write(devfd, pblk_size, pblk, nr_pblk, data_buf);
|
|
|
|
++header.params.init_zones;
|
|
|
|
now = time(NULL);
|
|
|
|
if (now >= next_write) {
|
|
|
|
printf("Initialized %u/%u zones\n",
|
|
|
|
header.params.init_zones, header.params.nr_zones);
|
|
|
|
cbd_header_put(header_buf, &header);
|
|
|
|
pblk_write(devfd, pblk_size, 0, 1, header_buf);
|
|
|
|
next_write = now + 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(data_buf);
|
|
|
|
cbd_header_put(header_buf, &header);
|
|
|
|
pblk_write(devfd, pblk_size, 0, 1, header_buf);
|
2019-10-09 18:06:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|