Make pblk len variable, add format profiles, and cleanup

This commit is contained in:
Tom Marshall 2019-11-12 22:25:46 +01:00
parent efc83e0dc2
commit 8229ef90bd
13 changed files with 442 additions and 281 deletions

40
README
View File

@ -2,29 +2,37 @@ This is a device mapper block compression driver.
Note: Note:
- Sectors are always 512 bytes (kernel constant). - Sectors are always 512 bytes (kernel constant).
- Physical blocks are always 4kb (internal constant). - Physical blocks are variable 512b .. 4kb.
- Logical blocks are variable 4kb .. 1gb. - Logical blocks are variable 4kb .. 4mb.
- All integers are little endian. - All integers are little endian.
Block device layout: Block device layout:
- byte[4096] header - pblk[0] header (512 bytes)
/* Offset 0 */ /* Offset 0: magic and version */
- byte[4] magic - byte[4] magic
- u16 version_major - u16 version_major
- u16 version_minor - u16 version_minor
/* Offset 8: parameters */
- u16 flags - u16 flags
- u8 algorithm (1=lz4, 2=zlib, ...) [1] - u8 algorithm (1=lz4, 2=zlib, ...) [1]
- u8 compression (1..9) [1] - u8 compression (1..9) [1]
- u8 pblk_shift (0..3) [3 = 4kb]
- u8 lblk_shift (1..10) [4 = 64kb (*)]
- u16 pbat_len [1] - u16 pbat_len [1]
- u16 lblk_shift (1..18) [4 = 64kb]
- u64 nr_pblk
- u32 nr_zones - u32 nr_zones
- u32 lblk_per_zone - u32 lblk_per_zone
- byte[32] reserved - byte[40] reserved
/* Offset 64 */ /* Offset 64: stats */
- u64 pblk_alloc - u64 pblk_used
- byte[] reserved - u64 lblk_used
- byte[] zone ... vector of zone - byte[48] reserved
/* Offset 128: reserved */
- byte[384] reserved
- pblk[] zone ... vector of zone
(*) The maximum lblk_shift may be (and usually is) less than 10 because
lblk_alloc size must be <= pblk size. When pblk_shift=1 (1024) and
lblk_alloc_16_32, the maximum lblk_shift is 8 (256kb).
Device size limits: Device size limits:
- Min: header plus one zone (header, pbat, lbat, data) - Min: header plus one zone (header, pbat, lbat, data)
@ -43,8 +51,8 @@ There are six different lblk_alloc sizes:
Zone layout: Zone layout:
- byte[4k*pbat_len] Physical block allocation table (pbat) - byte[pblk_size*pbat_len] Physical block allocation table (pbat)
- lblk_alloc_x_y[] Logical block allocation table (lbat) - lblk_alloc_x_y[] Logical block allocation table (lbat)
Note: padded to pblk size Note: padded to pblk size
- data[4k*pbat_len*4k*8] Data - data[] Data
One pblk per bit in pbat One pblk per bit in pbat

146
cbd/cbd.c
View File

@ -70,6 +70,54 @@ parse_numeric_arg(const char* arg, uint64_t* val)
return true; return true;
} }
struct profile {
const char* name;
uint pblksize;
uint lblksize;
enum cbd_alg alg;
uint level;
};
static struct profile profiles[] = {
{ "performance", 1*1024, 4*1024, CBD_ALG_LZ4, 1 },
{ "mixed", 4*1024, 64*1024, CBD_ALG_LZ4, 3 },
{ "read-mostly", 4*1024, 64*1024, CBD_ALG_ZLIB, 6 },
{ "archive", 4*1024, 256*1024, CBD_ALG_ZLIB, 9 },
};
static bool
parse_profile(const char* name,
uint* pblksize, uint* lblksize,
enum cbd_alg* alg, uint* level)
{
uint n;
for (n = 0; n < ARRAY_SIZE(profiles); ++n) {
struct profile* profile = &profiles[n];
if (!strcmp(profile->name, name)) {
*pblksize = profile->pblksize;
*lblksize = profile->lblksize;
*alg = profile->alg;
*level = profile->level;
return true;
}
}
return false;
}
static uint
get_shift(uint val, uint base)
{
uint shift = 0;
while (val > base) {
++shift;
base *= 2;
}
return shift;
}
static const char* progname; static const char* progname;
static void __attribute__((noreturn)) static void __attribute__((noreturn))
@ -83,19 +131,23 @@ usage(void)
"\n"); "\n");
fprintf(stderr, "Commands:\n" fprintf(stderr, "Commands:\n"
" format [opts] <device> Create (format) a compressed device\n" " format [opts] <device> Create (format) a compressed device\n"
" -S --pysical-size Physical size [device size]\n"
" -L --logical-blksize Logical block size\n"
" -P --pbat-len Physical block allocation table length [1]\n" " -P --pbat-len Physical block allocation table length [1]\n"
" -S --pysical-size Physical size [device size]\n"
" -c --compress-factor Compression factor [2.0]\n" " -c --compress-factor Compression factor [2.0]\n"
" -l --logical-shift Logical block shift [4]\n" " -l --logical-blksize Logical block size\n"
" -p --physical-blksize Physical block size\n"
" -s --size Logical size\n" " -s --size Logical size\n"
" -z --compress-alg Compression algorithm [lz4]\n" " -z --compress-alg Compression algorithm [lz4]\n"
" -Z --compress-level Compression level [?]\n" " -Z --compress-level Compression level [1]\n"
" --profile Set -p -l -z -Z automatically\n"
" Note:\n" " Note:\n"
" -c and -s are different ways of specifying the compressed device size.\n" " -c and -s are different ways of specifying the compressed device size.\n"
" Only one may be used, not both.\n" " Only one may be used, not both.\n"
" -l and -L are different ways of specifying the logical block size.\n" " Profiles:\n"
" Only one may be used, not both.\n" " performance: 1k pblk, 4k lblk, lz4 level 1\n"
" mixed: 4k pblk, 64k lblk, lz4 level 3\n"
" read-mostly: 4k pblk, 64k lblk, zlib level 6\n"
" archive: 4k pblk, 256k lblk, zlib level 9\n"
"\n" "\n"
" open [opts] <device> <name> Open an existing compressed device\n" " open [opts] <device> <name> Open an existing compressed device\n"
" create [opts] <device> <name> Alias for open\n" " create [opts] <device> <name> Alias for open\n"
@ -115,52 +167,51 @@ usage(void)
static int static int
do_format(int argc, char** argv) do_format(int argc, char** argv)
{ {
static const char short_opts[] = "S:L:P:c:l:s:z:Z:"; static const char short_opts[] = "P:S:c:l:p:s:z:Z:";
static const struct option long_opts[] = { static const struct option long_opts[] = {
{ "physical-size", required_argument, NULL, 'S' }, { "pbat-len", required_argument, NULL, 'P' },
{ "logical-blksize", required_argument, NULL, 'L' }, { "physical-size", required_argument, NULL, 'S' },
{ "pbat-len", required_argument, NULL, 'P' }, { "compress-factor", required_argument, NULL, 'c' },
{ "compress-factor", required_argument, NULL, 'c' }, { "logical-blksize", required_argument, NULL, 'l' },
{ "logical-shift", required_argument, NULL, 'l' }, { "physical-blksize", required_argument, NULL, 'p' },
{ "size", required_argument, NULL, 's' }, { "size", required_argument, NULL, 's' },
{ "compress-alg", required_argument, NULL, 'z' }, { "compress-alg", required_argument, NULL, 'z' },
{ "compress-level", required_argument, NULL, 'Z' }, { "compress-level", required_argument, NULL, 'Z' },
{ NULL, no_argument, NULL, 0 } { "profile", required_argument, NULL, 0x1 },
{ NULL, no_argument, NULL, 0 }
}; };
char opt; char opt;
uint64_t optval; uint64_t optval;
uint64_t psize = 0; uint64_t psize = 0;
uint16_t pbatlen = 1;
uint16_t lshift = 0;
uint64_t lsize = 0; uint64_t lsize = 0;
uint pblksize = PAGE_SIZE;
uint lblksize = 16 * PAGE_SIZE;
uint16_t pbatlen = 1;
enum cbd_alg alg = CBD_ALG_LZ4; enum cbd_alg alg = CBD_ALG_LZ4;
uint level = 1; uint level = 1;
uint8_t pshift;
uint8_t lshift;
const char* dev; const char* dev;
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
switch (opt) { switch (opt) {
case 'P':
if (!parse_numeric_arg(optarg, &optval)) {
error("Failed to parse \"%s\"\n", optarg);
}
if (optval < 1) {
error("Size \"%s\" is not a valid pbat len\n", optarg);
}
pbatlen = optval;
break;
case 'S': case 'S':
if (!parse_numeric_arg(optarg, &optval)) { if (!parse_numeric_arg(optarg, &optval)) {
error("Failed to parse \"%s\"\n", optarg); error("Failed to parse \"%s\"\n", optarg);
} }
psize = optval; psize = optval;
break; break;
case 'L':
if (!parse_numeric_arg(optarg, &optval)) {
error("Failed to parse \"%s\"\n", optarg);
}
if ((optval & (optval-1)) || optval < PBLK_SIZE) {
error("Size \"%s\" is not a valid logical block size\n", optarg);
}
lshift = (optval >> PBLK_SHIFT);
break;
case 'P':
if (!parse_numeric_arg(optarg, &optval)) {
error("Failed to parse \"%s\"\n", optarg);
}
pbatlen = optval;
break;
case 'c': case 'c':
error("Implement me!\n"); error("Implement me!\n");
break; break;
@ -168,7 +219,19 @@ do_format(int argc, char** argv)
if (!parse_numeric_arg(optarg, &optval)) { if (!parse_numeric_arg(optarg, &optval)) {
error("Failed to parse \"%s\"\n", optarg); error("Failed to parse \"%s\"\n", optarg);
} }
lshift = optval; if (optval & (optval - 1)) {
error("Size \"%s\" is not a valid block size\n", optarg);
}
lblksize = optval;
break;
case 'p':
if (!parse_numeric_arg(optarg, &optval)) {
error("Failed to parse \"%s\"\n", optarg);
}
if (optval & (optval - 1)) {
error("Size \"%s\" is not a valid block size\n", optarg);
}
pblksize = optval;
break; break;
case 's': case 's':
if (!parse_numeric_arg(optarg, &optval)) { if (!parse_numeric_arg(optarg, &optval)) {
@ -197,16 +260,29 @@ do_format(int argc, char** argv)
} }
level = optval; level = optval;
break; break;
case 0x1:
if (!parse_profile(optarg, &pblksize, &lblksize, &alg, &level)) {
error("Invalid profile \"%s\"\n", optarg);
}
break;
default: default:
usage(); usage();
} }
} }
pshift = get_shift(pblksize, SECTOR_SIZE);
if (pshift < PBLK_SHIFT_MIN || pshift > PBLK_SHIFT_MAX) {
error("Invalid physical block size %u\n", pblksize);
}
lshift = get_shift(lblksize, pblksize);
if (lshift < LBLK_SHIFT_MIN || lshift > LBLK_SHIFT_MAX) {
error("Invalid logical block size %u\n", lblksize);
}
if (argc - optind != 1) { if (argc - optind != 1) {
usage(); usage();
} }
dev = argv[optind++]; dev = argv[optind++];
cbd_format(dev, psize, pbatlen, lshift, lsize, alg, level); cbd_format(dev, pshift, lshift, pbatlen, alg, level, psize, lsize);
return 0; return 0;
} }

View File

@ -65,15 +65,9 @@ struct compress
static struct kobject* compress_kobj; static struct kobject* compress_kobj;
static inline u64 static inline u64
blkdev_pblk_size(struct block_device *bdev) dm_target_pblk_size(struct dm_target* ti, struct cbd_params* params)
{ {
return i_size_read(bdev->bd_inode) >> PBLK_SHIFT; return ti->len * (pblk_size(params) >> SECTOR_SHIFT);
}
static inline u64
dm_target_pblk_size(struct dm_target* ti)
{
return ti->len >> (PBLK_SHIFT - SECTOR_SHIFT);
} }
/************************************** /**************************************
@ -119,44 +113,58 @@ compress_read_header(struct compress* c)
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (header.params.algorithm == CBD_ALG_NONE || if (cbd_compression_alg_get(&header.params) == CBD_ALG_NONE ||
header.params.algorithm >= CBD_ALG_MAX) { cbd_compression_alg_get(&header.params) >= CBD_ALG_MAX) {
printk(KERN_ERR "%s: bad algorithm\n", __func__); printk(KERN_ERR "%s: bad algorithm\n", __func__);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
#ifndef COMPRESS_HAVE_LZ4 #ifndef COMPRESS_HAVE_LZ4
if (header.params.algorithm == CBD_ALG_LZ4) { if (cbd_compression_alg_get(&header.params) == CBD_ALG_LZ4) {
printk(KERN_ERR "%s: algorithm lz4 is not built into kernel\n", __func__); printk(KERN_ERR "%s: algorithm lz4 is not built into kernel\n", __func__);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
#endif #endif
#ifndef COMPRESS_HAVE_ZLIB #ifndef COMPRESS_HAVE_ZLIB
if (header.params.algorithm == CBD_ALG_ZLIB) { if (cbd_compression_alg_get(&header.params) == CBD_ALG_ZLIB) {
printk(KERN_ERR "%s: algorithm zlib is not built into kernel\n", __func__); printk(KERN_ERR "%s: algorithm zlib is not built into kernel\n", __func__);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
#endif #endif
if (header.params.compression < 1 || header.params.compression > 9) { if (cbd_compression_level_get(&header.params) < 1 ||
cbd_compression_level_get(&header.params) > 9) {
printk(KERN_ERR "%s: bad compression\n", __func__); printk(KERN_ERR "%s: bad compression\n", __func__);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (header.params.pblk_shift < PBLK_SHIFT_MIN ||
header.params.pblk_shift > PBLK_SHIFT_MAX) {
printk(KERN_ERR "%s: bad pblk_shift\n", __func__);
ret = -EINVAL;
goto out;
}
if (header.params.lblk_shift < LBLK_SHIFT_MIN || if (header.params.lblk_shift < LBLK_SHIFT_MIN ||
header.params.lblk_shift > LBLK_SHIFT_MAX) { header.params.lblk_shift > LBLK_SHIFT_MAX) {
printk(KERN_ERR "%s: bad lblk_shift\n", __func__); printk(KERN_ERR "%s: bad lblk_shift\n", __func__);
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
if (header.params.lba_elem_pblk_bytes != 2 &&
header.params.lba_elem_pblk_bytes != 4 &&
header.params.lba_elem_pblk_bytes != 6) {
printk(KERN_ERR "%s: bad lba_elem_pblk_bytes\n", __func__);
ret = -EINVAL;
goto out;
}
printk(KERN_INFO "%s: parameters...\n", __func__); printk(KERN_INFO "%s: parameters...\n", __func__);
printk(KERN_INFO " algorithm=%hu\n", (unsigned short)header.params.algorithm); printk(KERN_INFO " compression=0x%02x\n", (unsigned int)header.params.compression);
printk(KERN_INFO " compression=%hu\n", (unsigned short)header.params.compression); printk(KERN_INFO " pblk_shift=%hu\n", (unsigned short)header.params.pblk_shift);
printk(KERN_INFO " pbat_len=%hu\n", (unsigned short)header.params.pbat_len);
printk(KERN_INFO " lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift); printk(KERN_INFO " lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift);
printk(KERN_INFO " nr_pblk=%lu\n", (unsigned long)header.params.nr_pblk); printk(KERN_INFO " lba_elem_pblk_bytes=%hu\n", (unsigned short)header.params.lba_elem_pblk_bytes);
printk(KERN_INFO " pbat_len=%hu\n", (unsigned short)header.params.pbat_len);
printk(KERN_INFO " nr_zones=%u\n", (unsigned int)header.params.nr_zones); printk(KERN_INFO " nr_zones=%u\n", (unsigned int)header.params.nr_zones);
printk(KERN_INFO " lblk_per_zone=%u\n", (unsigned int)header.params.lblk_per_zone); printk(KERN_INFO " lblk_per_zone=%u\n", (unsigned int)header.params.lblk_per_zone);
printk(KERN_INFO "%s: stats...\n", __func__); printk(KERN_INFO "%s: stats...\n", __func__);
@ -208,7 +216,7 @@ compress_read(struct compress *c, struct bio *bio)
struct lbd* lbd = NULL; struct lbd* lbd = NULL;
struct bio_vec bv; struct bio_vec bv;
struct bvec_iter iter; struct bvec_iter iter;
u32 lblk_per_sector = lblk_per_pblk(&c->kparams.params) * PBLK_PER_SECTOR; u32 lblk_per_sector = lblk_size(&c->kparams.params) >> SECTOR_SHIFT;
bio_for_each_segment(bv, bio, iter) { bio_for_each_segment(bv, bio, iter) {
u64 lblk = iter.bi_sector / lblk_per_sector; u64 lblk = iter.bi_sector / lblk_per_sector;
@ -235,7 +243,7 @@ compress_write(struct compress *c, struct bio *bio)
struct lbd* lbd = NULL; struct lbd* lbd = NULL;
struct bio_vec bv; struct bio_vec bv;
struct bvec_iter iter; struct bvec_iter iter;
u32 lblk_per_sector = lblk_per_pblk(&c->kparams.params) * PBLK_PER_SECTOR; u32 lblk_per_sector = lblk_size(&c->kparams.params) >> SECTOR_SHIFT;
bio_for_each_segment(bv, bio, iter) { bio_for_each_segment(bv, bio, iter) {
u64 lblk = iter.bi_sector / lblk_per_sector; u64 lblk = iter.bi_sector / lblk_per_sector;
@ -324,13 +332,14 @@ compress_attr_show(struct kobject* kobj, struct attribute* attr,
mutex_lock(&c->kstats.lock); mutex_lock(&c->kstats.lock);
switch (a->attr_id) { switch (a->attr_id) {
case attr_lblk_size: case attr_lblk_size:
val = PBLK_SIZE * lblk_per_pblk(&c->kparams.params); val = lblk_size(&c->kparams.params);
break; break;
case attr_pblk_used: case attr_pblk_used:
val = c->kstats.stats.pblk_used; val = c->kstats.stats.pblk_used;
break; break;
case attr_pblk_total: case attr_pblk_total:
val = pbat_len(&c->kparams.params) * PBLK_SIZE_BITS * val = pbat_len(&c->kparams.params) *
pblk_size_bits(&c->kparams.params) *
c->kparams.params.nr_zones; c->kparams.params.nr_zones;
break; break;
case attr_lblk_used: case attr_lblk_used:
@ -463,7 +472,7 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
unsigned int argn; unsigned int argn;
u32 cache_pages = 0; u32 cache_pages = 0;
struct compress *c = NULL; struct compress *c = NULL;
u64 backing_nr_pblks; u64 target_nr_pblks;
printk(KERN_INFO "%s: enter: argc=%u\n", __func__, argc); printk(KERN_INFO "%s: enter: argc=%u\n", __func__, argc);
for (argn = 0; argn < argc; ++argn) { for (argn = 0; argn < argc; ++argn) {
@ -509,13 +518,7 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
} }
ti->private = c; ti->private = c;
ti->per_io_data_size = ALIGN(sizeof(struct compress_io), ARCH_KMALLOC_MINALIGN);
backing_nr_pblks = blkdev_pblk_size(c->dev->bdev);
if ((backing_nr_pblks >> 48) != 0) {
ti->error = "Device too large";
ret = -EINVAL;
goto err;
}
ret = compress_register_sysfs(c); ret = compress_register_sysfs(c);
if (ret) { if (ret) {
@ -525,23 +528,27 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
c->kparams.dev = c->dev->bdev; c->kparams.dev = c->dev->bdev;
mutex_init(&c->kstats.lock); mutex_init(&c->kstats.lock);
ret = compress_read_header(c);
if (ret) {
goto err;
}
target_nr_pblks = dm_target_pblk_size(ti, &c->kparams.params);
if ((target_nr_pblks >> 48) != 0) {
ti->error = "Device too large";
ret = -EINVAL;
goto err;
}
if (!cache_pages) { if (!cache_pages) {
/* Minimum of 1/1k RAM and 1/64k device size */ /* Minimum of 1/1k RAM and 1/64k device size */
cache_pages = min((unsigned int)(totalram_pages >> 10), cache_pages = min((unsigned int)(totalram_pages >> 10),
(unsigned int)(backing_nr_pblks >> 16)); (unsigned int)(target_nr_pblks >> 16));
if (cache_pages < 32 * 2 * num_online_cpus()) { if (cache_pages < 32 * 2 * num_online_cpus()) {
cache_pages = 32 * 2 * num_online_cpus(); cache_pages = 32 * 2 * num_online_cpus();
} }
} }
printk(KERN_INFO "%s: pages=%lu pblks=%lu cache_pages=%u\n", printk(KERN_INFO "%s: pages=%lu pblks=%lu cache_pages=%u\n",
__func__, totalram_pages, (unsigned long)backing_nr_pblks, cache_pages); __func__, totalram_pages, (unsigned long)target_nr_pblks, cache_pages);
ti->per_io_data_size = ALIGN(sizeof(struct compress_io), ARCH_KMALLOC_MINALIGN);
ret = compress_read_header(c);
if (ret) {
goto err;
}
if (c->kparams.params.flags & CBD_FLAG_DIRTY) { if (c->kparams.params.flags & CBD_FLAG_DIRTY) {
printk(KERN_INFO "Warning: device was not properly closed\n"); printk(KERN_INFO "Warning: device was not properly closed\n");
} }
@ -555,15 +562,8 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
} }
} }
/* XXX: validate minumum pblk using zone_off(max_zone+1) */ if (target_nr_pblks < zone_off(&c->kparams.params, c->kparams.params.nr_zones)) {
if (c->kparams.params.nr_pblk > backing_nr_pblks) { printk(KERN_ERR "%s: Device too small\n", __func__);
printk(KERN_ERR "%s: bad nr_pblk\n", __func__);
ret = -EINVAL;
goto err;
}
if (c->kparams.params.nr_zones > zone_for_pblk(&c->kparams.params, backing_nr_pblks)) {
printk(KERN_ERR "%s: bad nr_zones\n", __func__);
ret = -EINVAL; ret = -EINVAL;
goto err; goto err;
} }

View File

@ -238,7 +238,6 @@ lbatview_free_pblk(struct lbatview* lv, u64 pblk)
ret = pbat_free(pbat, pblk); ret = pbat_free(pbat, pblk);
BUG_ON(ret != 0); BUG_ON(ret != 0);
if (lv->pbat && pbat_zone(lv->pbat) != zone && pblk_zone == zone) { if (lv->pbat && pbat_zone(lv->pbat) != zone && pblk_zone == zone) {
printk(KERN_INFO "%s: freed block %lu in zone %u switching back\n", __func__, (unsigned long)pblk, zone);
ret = pbatcache_put(lv->pc, lv->pbat); ret = pbatcache_put(lv->pc, lv->pbat);
if (ret) { if (ret) {
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__); printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
@ -264,7 +263,8 @@ lbatview_elem_off(struct lbatview* lv, u64 lblk)
/* The offset of the element in the (full) lbat. */ /* The offset of the element in the (full) lbat. */
u32 lbat_elem_off = zone_rel_lblk * lba_len(&lv->kparams->params); u32 lbat_elem_off = zone_rel_lblk * lba_len(&lv->kparams->params);
/* The offset of the first view pblk. */ /* The offset of the first view pblk. */
u32 lbatview_off = PBLK_SIZE * (lv->pblk - lbat_off(&lv->kparams->params, lv_zone)); u32 lbatview_off = pblk_size(&lv->kparams->params) *
(lv->pblk - lbat_off(&lv->kparams->params, lv_zone));
return lbat_elem_off - lbatview_off; return lbat_elem_off - lbatview_off;
} }
@ -340,13 +340,13 @@ lbatview_elem_realloc(struct lbatview* lv, u64 lblk, u32 len)
elem_off = lbatview_elem_off(lv, lblk); elem_off = lbatview_elem_off(lv, lblk);
req_nalloc = (len == CBD_UNCOMPRESSED) ? req_nalloc = (len == CBD_UNCOMPRESSED) ?
lblk_per_pblk(&lv->kparams->params) : lblk_per_pblk(&lv->kparams->params) :
DIV_ROUND_UP(len, PBLK_SIZE); DIV_ROUND_UP(len, pblk_size(&lv->kparams->params));
elem_lelen = 0; elem_lelen = 0;
lbatview_rmem(lv, elem_off, lba_elem_len_bytes(&lv->kparams->params), &elem_lelen); lbatview_rmem(lv, elem_off, lba_elem_len_bytes(&lv->kparams->params), &elem_lelen);
elem_len = __le32_to_cpu(elem_lelen); elem_len = __le32_to_cpu(elem_lelen);
cur_nalloc = (elem_len == CBD_UNCOMPRESSED) ? cur_nalloc = (elem_len == CBD_UNCOMPRESSED) ?
lblk_per_pblk(&lv->kparams->params) : lblk_per_pblk(&lv->kparams->params) :
DIV_ROUND_UP(elem_len, PBLK_SIZE); DIV_ROUND_UP(elem_len, pblk_size(&lv->kparams->params));
old_nalloc = cur_nalloc; old_nalloc = cur_nalloc;
while (cur_nalloc < req_nalloc) { while (cur_nalloc < req_nalloc) {
@ -558,7 +558,7 @@ lbatviewcache_get(struct lbatviewcache* lvc, u64 lblk)
zone_lbat_pblk = lbat_off(lvc->params, zone); zone_lbat_pblk = lbat_off(lvc->params, zone);
rel_lblk = lblk - lvc->params->lblk_per_zone * zone; rel_lblk = lblk - lvc->params->lblk_per_zone * zone;
lbat_offset = rel_lblk * lba_len(lvc->params); lbat_offset = rel_lblk * lba_len(lvc->params);
rel_pblk = lbat_offset / PBLK_SIZE; rel_pblk = lbat_offset / pblk_size(lvc->params);
pblk = zone_lbat_pblk + rel_pblk; pblk = zone_lbat_pblk + rel_pblk;
count = (rel_pblk == lbat_len(lvc->params) - 1) ? 1 : 2; count = (rel_pblk == lbat_len(lvc->params) - 1) ? 1 : 2;

View File

@ -100,9 +100,11 @@ lblk_compress_lz4(struct lbd* lbd)
state = lblk_get_compress_state(lbd->percpu, cpu); state = lblk_get_compress_state(lbd->percpu, cpu);
BUG_ON(state == NULL); BUG_ON(state == NULL);
clen = LZ4_compress_fast(lbd->buf, state->buf, clen = LZ4_compress_fast(lbd->buf, state->buf,
PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params), lblk_size(&lbd->kparams->params),
PBLK_SIZE * (lblk_per_pblk(&lbd->kparams->params) - 1), lblk_size(&lbd->kparams->params) -
lbd->kparams->params.compression, state->lz4_workmem); pblk_size(&lbd->kparams->params),
cbd_compression_level_get(&lbd->kparams->params),
state->lz4_workmem);
if (clen <= 0) { if (clen <= 0) {
put_cpu(); put_cpu();
return 0; return 0;
@ -119,7 +121,7 @@ lblk_decompress_lz4(struct lbd* lbd)
int ret; int ret;
int cpu; int cpu;
struct lblk_compress_state* state; struct lblk_compress_state* state;
u32 dlen = PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params); u32 dlen = lblk_size(&lbd->kparams->params);
cpu = get_cpu(); cpu = get_cpu();
state = lblk_get_compress_state(lbd->percpu, cpu); state = lblk_get_compress_state(lbd->percpu, cpu);
@ -156,9 +158,10 @@ lblk_compress_zlib(struct lbd* lbd)
ret = zlib_deflateReset(stream); ret = zlib_deflateReset(stream);
BUG_ON(ret != Z_OK); BUG_ON(ret != Z_OK);
stream->next_in = lbd->buf; stream->next_in = lbd->buf;
stream->avail_in = PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params); stream->avail_in = lblk_size(&lbd->kparams->params);
stream->next_out = state->buf; stream->next_out = state->buf;
stream->avail_out = PBLK_SIZE * (lblk_per_pblk(&lbd->kparams->params) - 1); stream->avail_out = lblk_size(&lbd->kparams->params) -
pblk_size(&lbd->kparams->params);
ret = zlib_deflate(stream, Z_FINISH); ret = zlib_deflate(stream, Z_FINISH);
if (ret != Z_STREAM_END) { if (ret != Z_STREAM_END) {
put_cpu(); put_cpu();
@ -178,7 +181,7 @@ lblk_decompress_zlib(struct lbd* lbd)
int cpu; int cpu;
struct lblk_compress_state* state; struct lblk_compress_state* state;
z_stream* stream; z_stream* stream;
u32 dlen = PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params); u32 dlen = lblk_size(&lbd->kparams->params);
cpu = get_cpu(); cpu = get_cpu();
state = lblk_get_compress_state(lbd->percpu, cpu); state = lblk_get_compress_state(lbd->percpu, cpu);
@ -218,12 +221,12 @@ static size_t
lblk_compress(struct lbd* lbd) lblk_compress(struct lbd* lbd)
{ {
#ifdef COMPRESS_HAVE_LZ4 #ifdef COMPRESS_HAVE_LZ4
if (lbd->kparams->params.algorithm == CBD_ALG_LZ4) { if (cbd_compression_alg_get(&lbd->kparams->params) == CBD_ALG_LZ4) {
return lblk_compress_lz4(lbd); return lblk_compress_lz4(lbd);
} }
#endif #endif
#ifdef COMPRESS_HAVE_ZLIB #ifdef COMPRESS_HAVE_ZLIB
if (lbd->kparams->params.algorithm == CBD_ALG_ZLIB) { if (cbd_compression_alg_get(&lbd->kparams->params) == CBD_ALG_ZLIB) {
return lblk_compress_zlib(lbd); return lblk_compress_zlib(lbd);
} }
#endif #endif
@ -237,12 +240,12 @@ static bool
lblk_decompress(struct lbd* lbd) lblk_decompress(struct lbd* lbd)
{ {
#ifdef COMPRESS_HAVE_LZ4 #ifdef COMPRESS_HAVE_LZ4
if (lbd->kparams->params.algorithm == CBD_ALG_LZ4) { if (cbd_compression_alg_get(&lbd->kparams->params) == CBD_ALG_LZ4) {
return lblk_decompress_lz4(lbd); return lblk_decompress_lz4(lbd);
} }
#endif #endif
#ifdef COMPRESS_HAVE_ZLIB #ifdef COMPRESS_HAVE_ZLIB
if (lbd->kparams->params.algorithm == CBD_ALG_ZLIB) { if (cbd_compression_alg_get(&lbd->kparams->params) == CBD_ALG_ZLIB) {
return lblk_decompress_zlib(lbd); return lblk_decompress_zlib(lbd);
} }
#endif #endif
@ -339,11 +342,11 @@ lbd_flush(struct lbd* lbd)
} }
lbd->c_len = lblk_compress(lbd); lbd->c_len = lblk_compress(lbd);
if (lbd->c_len > 0) { if (lbd->c_len > 0) {
u32 c_blkrem = lbd->c_len % PBLK_SIZE; u32 c_blkrem = lbd->c_len % pblk_size(&lbd->kparams->params);
if (c_blkrem) { if (c_blkrem) {
memset(lbd->buf + lbd->c_len, 0, c_blkrem); memset(lbd->buf + lbd->c_len, 0, c_blkrem);
} }
count = DIV_ROUND_UP(lbd->c_len, PBLK_SIZE); count = DIV_ROUND_UP(lbd->c_len, pblk_size(&lbd->kparams->params));
} }
else { else {
lbd->c_len = CBD_UNCOMPRESSED; lbd->c_len = CBD_UNCOMPRESSED;
@ -400,12 +403,12 @@ lbd_read(struct lbd* lbd)
} }
lbd->c_len = lbatview_elem_len(lbd->lv, lbd->lblk); lbd->c_len = lbatview_elem_len(lbd->lv, lbd->lblk);
if (lbd->c_len == 0) { if (lbd->c_len == 0) {
memset(lbd->buf, 0, PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params)); memset(lbd->buf, 0, lblk_size(&lbd->kparams->params));
} }
else { else {
count = (lbd->c_len == CBD_UNCOMPRESSED) ? count = (lbd->c_len == CBD_UNCOMPRESSED) ?
lblk_per_pblk(&lbd->kparams->params) : lblk_per_pblk(&lbd->kparams->params) :
DIV_ROUND_UP(lbd->c_len, PBLK_SIZE); DIV_ROUND_UP(lbd->c_len, pblk_size(&lbd->kparams->params));
for (n = 0; n < count; ++n) { for (n = 0; n < count; ++n) {
pblk = lbatview_elem_pblk(lbd->lv, lbd->lblk, n); pblk = lbatview_elem_pblk(lbd->lv, lbd->lblk, n);
if (pblk == PBLK_NONE) { if (pblk == PBLK_NONE) {
@ -494,7 +497,7 @@ void
lbd_data_read(struct lbd* lbd, u32 off, u32 len, u8* buf) lbd_data_read(struct lbd* lbd, u32 off, u32 len, u8* buf)
{ {
/* XXX: convert to BUG_ON */ /* XXX: convert to BUG_ON */
if (off + len > PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params)) { if (off + len > lblk_size(&lbd->kparams->params)) {
printk(KERN_ERR "%s: out of bounds\n", __func__); printk(KERN_ERR "%s: out of bounds\n", __func__);
return; return;
} }
@ -507,7 +510,7 @@ void
lbd_data_write(struct lbd* lbd, u32 off, u32 len, const u8* buf) lbd_data_write(struct lbd* lbd, u32 off, u32 len, const u8* buf)
{ {
/* XXX: convert to BUG_ON */ /* XXX: convert to BUG_ON */
if (off + len > PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params)) { if (off + len > lblk_size(&lbd->kparams->params)) {
printk(KERN_ERR "%s: out of bounds\n", __func__); printk(KERN_ERR "%s: out of bounds\n", __func__);
return; return;
} }
@ -556,12 +559,12 @@ lbdcache_alloc_compress_state(void* percpu, const struct cbd_params* params, int
} }
statep = per_cpu_ptr(percpu, cpu); statep = per_cpu_ptr(percpu, cpu);
*statep = state; *statep = state;
state->buf = vmalloc(PBLK_SIZE * lblk_per_pblk(params)); state->buf = vmalloc(lblk_size(params));
if (!state->buf) { if (!state->buf) {
return false; return false;
} }
#ifdef COMPRESS_HAVE_LZ4 #ifdef COMPRESS_HAVE_LZ4
workmem_len = LZ4_compressBound(PBLK_SIZE * lblk_per_pblk(params)); workmem_len = LZ4_compressBound(lblk_size(params));
state->lz4_workmem = vzalloc(workmem_len); state->lz4_workmem = vzalloc(workmem_len);
if (!state->lz4_workmem) { if (!state->lz4_workmem) {
return false; return false;
@ -573,7 +576,8 @@ lbdcache_alloc_compress_state(void* percpu, const struct cbd_params* params, int
if (!state->zlib_cstream.workspace) { if (!state->zlib_cstream.workspace) {
return false; return false;
} }
ret = zlib_deflateInit2(&state->zlib_cstream, params->compression, ret = zlib_deflateInit2(&state->zlib_cstream,
cbd_compression_level_get(params),
Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
Z_DEFAULT_STRATEGY); Z_DEFAULT_STRATEGY);
BUG_ON(ret != Z_OK); BUG_ON(ret != Z_OK);

View File

@ -195,7 +195,8 @@ pbat_zone(struct pbat* pbat)
u64 u64
pbat_alloc(struct pbat* pbat) pbat_alloc(struct pbat* pbat)
{ {
u32 pblk_count = pbat_len(&pbat->kparams->params) * PBLK_SIZE_BITS; u32 bitsize = pblk_size_bits(&pbat->kparams->params) *
pbat_len(&pbat->kparams->params);
u32 idx; u32 idx;
u64 pblk; u64 pblk;
@ -204,8 +205,8 @@ pbat_alloc(struct pbat* pbat)
pblk = PBLK_NONE; pblk = PBLK_NONE;
goto out; goto out;
} }
idx = cbd_bitmap_alloc(pbat->buf, pblk_count, pbat->last_alloc); idx = cbd_bitmap_alloc(pbat->buf, bitsize, pbat->last_alloc);
if (idx == pblk_count) { if (idx == bitsize) {
pbat->full = true; pbat->full = true;
pblk = PBLK_NONE; pblk = PBLK_NONE;
goto out; goto out;
@ -222,7 +223,8 @@ out:
int int
pbat_free(struct pbat* pbat, u64 pblk) pbat_free(struct pbat* pbat, u64 pblk)
{ {
u32 pblk_count = pbat_len(&pbat->kparams->params) * PBLK_SIZE_BITS; u32 bitsize = pblk_size_bits(&pbat->kparams->params) *
pbat_len(&pbat->kparams->params);
u32 zone; u32 zone;
u32 idx; u32 idx;
@ -233,7 +235,7 @@ pbat_free(struct pbat* pbat, u64 pblk)
return -EINVAL; return -EINVAL;
} }
idx = pblk - zone_data_off(&pbat->kparams->params, zone); idx = pblk - zone_data_off(&pbat->kparams->params, zone);
BUG_ON(idx >= pblk_count); BUG_ON(idx >= bitsize);
mutex_lock(&pbat->lock); mutex_lock(&pbat->lock);
cbd_bitmap_free(pbat->buf, idx); cbd_bitmap_free(pbat->buf, idx);
pbat->full = false; pbat->full = false;

View File

@ -99,7 +99,7 @@ cbd_free_pagev(struct page** pagev, size_t len)
static struct bio* static struct bio*
pblk_io_prepare(struct block_device* bdev, unsigned int op, pblk_io_prepare(struct block_device* bdev, unsigned int op,
u64 pblk, u32 count, struct page** pagev) u32 pblk_size, u64 pblk, u32 count, struct page** pagev)
{ {
struct bio* bio; struct bio* bio;
u32 n; u32 n;
@ -112,9 +112,9 @@ pblk_io_prepare(struct block_device* bdev, unsigned int op,
bio_set_dev(bio, bdev); bio_set_dev(bio, bdev);
bio->bi_opf = op; bio->bi_opf = op;
bio->bi_iter.bi_sector = (pblk << (PBLK_SHIFT - SECTOR_SHIFT)); bio->bi_iter.bi_sector = pblk * (pblk_size / SECTOR_SIZE);
for (n = 0; n < count; ++n) { for (n = 0; n < count; ++n) {
if (bio_add_page(bio, pagev[n], PAGE_SIZE, 0) != PAGE_SIZE) { if (bio_add_page(bio, pagev[n], pblk_size, 0) != pblk_size) {
BUG(); BUG();
} }
} }
@ -129,7 +129,8 @@ pblk_read_wait(struct compress_params* kparams,
int ret; int ret;
struct bio* bio; struct bio* bio;
bio = pblk_io_prepare(kparams->dev, REQ_OP_READ, pblk, count, pagev); bio = pblk_io_prepare(kparams->dev, REQ_OP_READ,
pblk_size(&kparams->params), pblk, count, pagev);
if (!bio) { if (!bio) {
printk(KERN_ERR "%s: out of memory\n", __func__); printk(KERN_ERR "%s: out of memory\n", __func__);
return -ENOMEM; return -ENOMEM;
@ -150,7 +151,8 @@ pblk_write_wait(struct compress_params* kparams,
int ret; int ret;
struct bio* bio; struct bio* bio;
bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE, pblk, count, pagev); bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE,
pblk_size(&kparams->params), pblk, count, pagev);
if (!bio) { if (!bio) {
printk(KERN_ERR "%s: out of memory\n", __func__); printk(KERN_ERR "%s: out of memory\n", __func__);
return -ENOMEM; return -ENOMEM;
@ -195,7 +197,8 @@ pblk_write(struct compress_params* kparams,
struct bio* bio; struct bio* bio;
u32 n; u32 n;
bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE, pblk, count, pagev); bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE,
pblk_size(&kparams->params), pblk, count, pagev);
if (!bio) { if (!bio) {
printk(KERN_ERR "%s: out of memory\n", __func__); printk(KERN_ERR "%s: out of memory\n", __func__);
kparams->params.flags |= CBD_FLAG_ERROR; kparams->params.flags |= CBD_FLAG_ERROR;

View File

@ -11,6 +11,20 @@
#define BITS_PER_BYTE 8 #define BITS_PER_BYTE 8
#endif #endif
#ifndef SECTOR_SHIFT
#define SECTOR_SHIFT 9
#endif
#ifndef SECTOR_SIZE
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
#endif
#ifndef PAGE_SHIFT
#define PAGE_SHIFT 12
#endif
#ifndef PAGE_SIZE
#define PAGE_SIZE (1 << PAGE_SHIFT)
#endif
#ifndef min #ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b))
#endif #endif
@ -41,6 +55,7 @@ typedef uint64_t u64;
#include <stdlib.h> #include <stdlib.h>
#define CBD_DEFAULT_COMPRESSION_FACTOR 2.0 #define CBD_DEFAULT_COMPRESSION_FACTOR 2.0
#define CBD_DEFAULT_PHYSICAL_BLOCK_SHIFT 3
#define CBD_DEFAULT_LOGICAL_BLOCK_SHIFT 4 #define CBD_DEFAULT_LOGICAL_BLOCK_SHIFT 4
/* XXX: move to types.h */ /* XXX: move to types.h */
@ -51,9 +66,10 @@ typedef enum {
} tristate_t; } tristate_t;
int cbd_format(const char* dev, int cbd_format(const char* dev,
uint64_t psize, uint16_t pbatlen, uint8_t pshift, uint8_t lshift,
uint16_t lshift, uint64_t lsize, uint16_t pbatlen,
enum cbd_alg alg, uint level); enum cbd_alg alg, uint level,
uint64_t psize, uint64_t lsize);
int cbd_open(const char* dev, int cbd_open(const char* dev,
const char* name); const char* name);
int cbd_close(const char* name); int cbd_close(const char* name);

View File

@ -1,20 +1,10 @@
#ifndef _LINUX_DM_COMPRESS_H #ifndef _LINUX_DM_COMPRESS_H
#define _LINUX_DM_COMPRESS_H #define _LINUX_DM_COMPRESS_H
#ifndef SECTOR_SHIFT #define PBLK_SHIFT_MIN 0
#define SECTOR_SHIFT 9 #define PBLK_SHIFT_MAX 3
#endif #define LBLK_SHIFT_MIN 1
#ifndef SECTOR_SIZE #define LBLK_SHIFT_MAX 10
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
#endif
#define PBLK_SHIFT 12
#define PBLK_SIZE (1 << PBLK_SHIFT)
#define PBLK_SIZE_BITS (PBLK_SIZE * BITS_PER_BYTE)
#define PBLK_PER_SECTOR (1 << (PBLK_SHIFT - SECTOR_SHIFT))
#define LBLK_SHIFT_MIN 1
#define LBLK_SHIFT_MAX (20 - PBLK_SHIFT)
#define ZONE_NONE (u32)(~0) #define ZONE_NONE (u32)(~0)
#define PBLK_NONE (u64)(~0) #define PBLK_NONE (u64)(~0)
@ -41,11 +31,11 @@ enum cbd_alg {
struct cbd_params { struct cbd_params {
u16 flags; u16 flags;
u8 algorithm; /* enum cbd_alg */ u8 compression; /* alg and level */
u8 compression; /* 0..9 */ u8 pblk_shift;
u8 lblk_shift;
u8 lba_elem_pblk_bytes;
u16 pbat_len; u16 pbat_len;
u16 lblk_shift;
u64 nr_pblk;
u32 nr_zones; u32 nr_zones;
u32 lblk_per_zone; u32 lblk_per_zone;
}; };
@ -236,12 +226,30 @@ cbd_bitmap_isset(u8* buf, u32 idx)
static inline u32
pblk_size(const struct cbd_params* params)
{
return (1 << params->pblk_shift) * SECTOR_SIZE;
}
static inline u32
pblk_size_bits(const struct cbd_params* params)
{
return pblk_size(params) * BITS_PER_BYTE;
}
static inline u32 static inline u32
lblk_per_pblk(const struct cbd_params* params) lblk_per_pblk(const struct cbd_params* params)
{ {
return (1 << params->lblk_shift); return (1 << params->lblk_shift);
} }
static inline u32
lblk_size(const struct cbd_params* params)
{
return pblk_size(params) * lblk_per_pblk(params);
}
static inline u32 static inline u32
pbat_len(const struct cbd_params* params) pbat_len(const struct cbd_params* params)
{ {
@ -251,14 +259,13 @@ pbat_len(const struct cbd_params* params)
static inline u32 static inline u32
lba_elem_len_bytes(const struct cbd_params* params) lba_elem_len_bytes(const struct cbd_params* params)
{ {
return (params->lblk_shift + PBLK_SHIFT > 16) ? 4 : 2; return (lblk_size(params) > 0xffff) ? 4 : 2;
} }
static inline u32 static inline u32
lba_elem_pblk_bytes(const struct cbd_params* params) lba_elem_pblk_bytes(const struct cbd_params* params)
{ {
return (params->nr_pblk <= 0xffff ? 2 : return params->lba_elem_pblk_bytes;
(params->nr_pblk <= 0xffffffff ? 4 : 6));
} }
static inline u32 static inline u32
@ -271,7 +278,7 @@ lba_len(const struct cbd_params* params)
static inline u32 static inline u32
lbat_len(const struct cbd_params* params) lbat_len(const struct cbd_params* params)
{ {
return DIV_ROUND_UP(params->lblk_per_zone * lba_len(params), PBLK_SIZE); return DIV_ROUND_UP(params->lblk_per_zone * lba_len(params), pblk_size(params));
} }
static inline u32 static inline u32
@ -284,7 +291,7 @@ zone_metadata_len(const struct cbd_params* params)
static inline u32 static inline u32
zone_data_len(const struct cbd_params* params) zone_data_len(const struct cbd_params* params)
{ {
return pbat_len(params) * PBLK_SIZE * BITS_PER_BYTE; return pbat_len(params) * pblk_size(params) * BITS_PER_BYTE;
} }
static inline u32 static inline u32
@ -339,39 +346,67 @@ zone_for_lblk(const struct cbd_params* params, u64 lblk)
static inline void static inline void
cbd_header_get(const u8* buf, struct cbd_header* header) cbd_header_get(const u8* buf, struct cbd_header* header)
{ {
get_mem(&buf, header->magic, sizeof(header->magic)); const u8* p;
header->version_major = get16_le(&buf); p = buf + 0;
header->version_minor = get16_le(&buf); get_mem(&p, header->magic, sizeof(header->magic));
header->params.flags = get16_le(&buf); header->version_major = get16_le(&p);
header->params.algorithm = get_byte(&buf); header->version_minor = get16_le(&p);
header->params.compression = get_byte(&buf); header->params.flags = get16_le(&p);
header->params.pbat_len = get16_le(&buf); header->params.compression = get_byte(&p);
header->params.lblk_shift = get16_le(&buf); header->params.pblk_shift = get_byte(&p);
header->params.nr_pblk = get64_le(&buf); header->params.lblk_shift = get_byte(&p);
header->params.nr_zones = get32_le(&buf); header->params.lba_elem_pblk_bytes = get_byte(&p);
header->params.lblk_per_zone = get32_le(&buf); header->params.pbat_len = get16_le(&p);
buf += 32; /* Reserved */ header->params.nr_zones = get32_le(&p);
header->stats.pblk_used = get64_le(&buf); header->params.lblk_per_zone = get32_le(&p);
header->stats.lblk_used = get64_le(&buf); p = buf + 64;
header->stats.pblk_used = get64_le(&p);
header->stats.lblk_used = get64_le(&p);
} }
static inline void static inline void
cbd_header_put(u8* buf, const struct cbd_header* header) cbd_header_put(u8* buf, const struct cbd_header* header)
{ {
put_mem(&buf, header->magic, sizeof(header->magic)); u8* p;
put16_le(&buf, header->version_major); p = buf + 0;
put16_le(&buf, header->version_minor); put_mem(&p, header->magic, sizeof(header->magic));
put16_le(&buf, header->params.flags); put16_le(&p, header->version_major);
put_byte(&buf, header->params.algorithm); put16_le(&p, header->version_minor);
put_byte(&buf, header->params.compression); put16_le(&p, header->params.flags);
put16_le(&buf, header->params.pbat_len); put_byte(&p, header->params.compression);
put16_le(&buf, header->params.lblk_shift); put_byte(&p, header->params.pblk_shift);
put64_le(&buf, header->params.nr_pblk); put_byte(&p, header->params.lblk_shift);
put32_le(&buf, header->params.nr_zones); put_byte(&p, header->params.lba_elem_pblk_bytes);
put32_le(&buf, header->params.lblk_per_zone); put16_le(&p, header->params.pbat_len);
buf += 32; /* Reserved */ put32_le(&p, header->params.nr_zones);
put64_le(&buf, header->stats.pblk_used); put32_le(&p, header->params.lblk_per_zone);
put64_le(&buf, header->stats.lblk_used); p = buf + 64;
put64_le(&p, header->stats.pblk_used);
put64_le(&p, header->stats.lblk_used);
}
static inline enum cbd_alg
cbd_compression_alg_get(const struct cbd_params* params)
{
return (enum cbd_alg)(params->compression >> 4);
}
static inline void
cbd_compression_alg_put(struct cbd_params* params, enum cbd_alg alg)
{
params->compression = (alg << 4) | (params->compression & 0x0f);
}
static inline u8
cbd_compression_level_get(const struct cbd_params* params)
{
return (params->compression & 0x0f);
}
static inline void
cbd_compression_level_put(struct cbd_params* params, u8 level)
{
params->compression = (params->compression & 0xf0) | level;
} }
static inline u32 static inline u32

View File

@ -22,18 +22,18 @@ struct check_state
}; };
static void static void
pblk_read(int fd, u64 pblk, u32 count, u8* data) pblk_read(int fd, u32 pblk_size, u64 pblk, u32 count, u8* data)
{ {
off_t pos; off_t pos;
size_t remain; size_t remain;
ssize_t ret; ssize_t ret;
pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET); pos = lseek(fd, pblk * pblk_size, SEEK_SET);
if (pos == (off_t)-1) { if (pos == (off_t)-1) {
error("Failed to seek\n"); error("Failed to seek\n");
} }
remain = count * PBLK_SIZE; remain = count * pblk_size;
while (remain) { while (remain) {
ret = read(fd, data, remain); ret = read(fd, data, remain);
if (ret <= 0) { if (ret <= 0) {
@ -45,18 +45,18 @@ pblk_read(int fd, u64 pblk, u32 count, u8* data)
} }
static void static void
pblk_write(int fd, u64 pblk, u32 count, const u8* data) pblk_write(int fd, u32 pblk_size, u64 pblk, u32 count, const u8* data)
{ {
off_t pos; off_t pos;
size_t remain; size_t remain;
ssize_t ret; ssize_t ret;
pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET); pos = lseek(fd, pblk * pblk_size, SEEK_SET);
if (pos == (off_t)-1) { if (pos == (off_t)-1) {
error("Failed to seek\n"); error("Failed to seek\n");
} }
remain = count * PBLK_SIZE; remain = count * pblk_size;
while (remain) { while (remain) {
ret = write(fd, data, remain); ret = write(fd, data, remain);
if (ret <= 0) { if (ret <= 0) {
@ -70,30 +70,33 @@ pblk_write(int fd, u64 pblk, u32 count, const u8* data)
static void static void
pbat_read(int fd, const struct cbd_params* params, u32 zone, u8* data) pbat_read(int fd, const struct cbd_params* params, u32 zone, u8* data)
{ {
pblk_read(fd, pbat_off(params, zone), pbat_len(params), data); pblk_read(fd, pblk_size(params), pbat_off(params, zone), pbat_len(params), data);
} }
static void static void
pbat_write(int fd, const struct cbd_params* params, u32 zone, const u8* data) pbat_write(int fd, const struct cbd_params* params, u32 zone, const u8* data)
{ {
pblk_write(fd, pbat_off(params, zone), pbat_len(params), data); pblk_write(fd, pblk_size(params), pbat_off(params, zone), pbat_len(params), data);
} }
static void static void
lbat_read(int fd, const struct cbd_params* params, u32 zone, u8* data) lbat_read(int fd, const struct cbd_params* params, u32 zone, u8* data)
{ {
pblk_read(fd, lbat_off(params, zone), lbat_len(params), data); pblk_read(fd, pblk_size(params), lbat_off(params, zone), lbat_len(params), data);
} }
static void static void
lbat_write(int fd, const struct cbd_params* params, u32 zone, const u8* data) lbat_write(int fd, const struct cbd_params* params, u32 zone, const u8* data)
{ {
pblk_write(fd, lbat_off(params, zone), lbat_len(params), data); pblk_write(fd, pblk_size(params), lbat_off(params, zone), lbat_len(params), data);
} }
static void static void
check_header(const struct cbd_header* header) check_header(const struct cbd_header* header)
{ {
enum cbd_alg alg = cbd_compression_alg_get(&header->params);
u8 level = cbd_compression_level_get(&header->params);
if (memcmp(header->magic, CBD_MAGIC, sizeof(header->magic))) { if (memcmp(header->magic, CBD_MAGIC, sizeof(header->magic))) {
error("Bad magic\n"); error("Bad magic\n");
} }
@ -103,11 +106,10 @@ check_header(const struct cbd_header* header)
if (header->version_minor != CBD_VERSION_MINOR) { if (header->version_minor != CBD_VERSION_MINOR) {
error("Bad major version\n"); error("Bad major version\n");
} }
if (header->params.algorithm == CBD_ALG_NONE || if (alg == CBD_ALG_NONE || alg >= CBD_ALG_MAX) {
header->params.algorithm >= CBD_ALG_MAX) {
error("Bad algorithm\n"); error("Bad algorithm\n");
} }
if (header->params.compression > 9) { if (level < 1 || level > 9) {
error("Bad compression\n"); error("Bad compression\n");
} }
if (header->params.lblk_shift < LBLK_SHIFT_MIN || if (header->params.lblk_shift < LBLK_SHIFT_MIN ||
@ -120,7 +122,7 @@ static bool
check_decompress_lz4(struct check_state* state, const struct cbd_params* params, u8* buf, u32 clen) check_decompress_lz4(struct check_state* state, const struct cbd_params* params, u8* buf, u32 clen)
{ {
int ret; int ret;
u32 dlen = PBLK_SIZE * lblk_per_pblk(params); u32 dlen = lblk_size(params);
ret = LZ4_decompress_safe((const char*)buf, (char*)state->compress_buf, clen, dlen); ret = LZ4_decompress_safe((const char*)buf, (char*)state->compress_buf, clen, dlen);
if (ret != dlen) { if (ret != dlen) {
@ -135,7 +137,7 @@ check_decompress_zlib(struct check_state* state, const struct cbd_params* params
{ {
int ret; int ret;
z_stream* stream; z_stream* stream;
u32 dlen = PBLK_SIZE * lblk_per_pblk(params); u32 dlen = lblk_size(params);
stream = &state->zlib_dstream; stream = &state->zlib_dstream;
ret = inflateReset(stream); ret = inflateReset(stream);
@ -163,7 +165,7 @@ check_decompress(struct check_state* state, const struct cbd_params* params, u8*
{ {
bool ret = false; bool ret = false;
switch (params->algorithm) { switch (cbd_compression_alg_get(params)) {
case CBD_ALG_LZ4: case CBD_ALG_LZ4:
ret = check_decompress_lz4(state, params, buf, clen); ret = check_decompress_lz4(state, params, buf, clen);
break; break;
@ -190,16 +192,16 @@ check_lblk_data(struct check_state* state,
u32 n; u32 n;
u64 pblk; u64 pblk;
data = calloc(PBLK_SIZE, lblk_per_pblk(params)); data = calloc(pblk_size(params), lblk_per_pblk(params));
buf = lba; buf = lba;
len = lba_len_get(params, buf); len = lba_len_get(params, buf);
if (len == 0 || len == CBD_UNCOMPRESSED) { if (len == 0 || len == CBD_UNCOMPRESSED) {
return true; return true;
} }
n_alloc = DIV_ROUND_UP(len, PBLK_SIZE); n_alloc = DIV_ROUND_UP(len, pblk_size(params));
for (n = 0; n < n_alloc; ++n) { for (n = 0; n < n_alloc; ++n) {
pblk = lba_pblk_get(params, buf, n); pblk = lba_pblk_get(params, buf, n);
pblk_read(state->fd, pblk, 1, data + n * PBLK_SIZE); pblk_read(state->fd, pblk_size(params), pblk, 1, data + n * pblk_size(params));
} }
ret = check_decompress(state, params, data, len); ret = check_decompress(state, params, data, len);
free(data); free(data);
@ -238,7 +240,7 @@ check_lblk_alloc(struct check_state* state,
else { else {
verbose(2, " lblk[%u]: len=%u\n", lblk, len); verbose(2, " lblk[%u]: len=%u\n", lblk, len);
} }
if (len > PBLK_SIZE * lblk_per_pblk(params)) { if (len > lblk_size(params)) {
if (ask_user_bool("lblk %u: length %u out of bounds. Clear?", lblk, len)) { if (ask_user_bool("lblk %u: length %u out of bounds. Clear?", lblk, len)) {
memset(lba, 0, lba_len(params)); memset(lba, 0, lba_len(params));
return true; return true;
@ -248,7 +250,7 @@ check_lblk_alloc(struct check_state* state,
} }
n_alloc = (len == CBD_UNCOMPRESSED) ? n_alloc = (len == CBD_UNCOMPRESSED) ?
lblk_per_pblk(params) : lblk_per_pblk(params) :
DIV_ROUND_UP(len, PBLK_SIZE); DIV_ROUND_UP(len, pblk_size(params));
for (n = 0; n < n_alloc; ++n) { for (n = 0; n < n_alloc; ++n) {
pblk = lba_pblk_get(params, buf, n); pblk = lba_pblk_get(params, buf, n);
if (pblk < CBD_HEADER_BLOCKS) { if (pblk < CBD_HEADER_BLOCKS) {
@ -302,7 +304,7 @@ check_lbat(struct check_state* state, const struct cbd_params* params)
u32 zone; u32 zone;
for (zone = 0; zone < params->nr_zones; ++zone) { for (zone = 0; zone < params->nr_zones; ++zone) {
u8* lbat = calloc(PBLK_SIZE, lbat_len(params)); u8* lbat = calloc(pblk_size(params), lbat_len(params));
bool zone_empty = true; bool zone_empty = true;
bool changed = false; bool changed = false;
u32 n; u32 n;
@ -341,7 +343,7 @@ check_lbat(struct check_state* state, const struct cbd_params* params)
len = lba_len_get(params, buf); len = lba_len_get(params, buf);
if (len != 0) { if (len != 0) {
++state->lblk_used; ++state->lblk_used;
state->pblk_used += DIV_ROUND_UP(len, PBLK_SIZE); state->pblk_used += DIV_ROUND_UP(len, pblk_size(params));
} }
} }
if (changed) { if (changed) {
@ -357,13 +359,13 @@ check_pbat(struct check_state* state, const struct cbd_params* params)
u32 zone; u32 zone;
u8* pbat; u8* pbat;
pbat = malloc(PBLK_SIZE * pbat_len(params)); pbat = malloc(pblk_size(params) * pbat_len(params));
for (zone = 0; zone < params->nr_zones; ++zone) { for (zone = 0; zone < params->nr_zones; ++zone) {
bool changed = false; bool changed = false;
pbat_read(state->fd, params, zone, pbat); pbat_read(state->fd, params, zone, pbat);
if (memcmp(pbat, state->pbatv[zone], PBLK_SIZE * pbat_len(params)) != 0) { if (memcmp(pbat, state->pbatv[zone], pblk_size(params) * pbat_len(params)) != 0) {
if (ask_user_bool("zone %u has incorrect pbat. Fix?", zone)) { if (ask_user_bool("zone %u has incorrect pbat. Fix?", zone)) {
memcpy(pbat, state->pbatv[zone], PBLK_SIZE * pbat_len(params)); memcpy(pbat, state->pbatv[zone], pblk_size(params) * pbat_len(params));
changed = true; changed = true;
} }
else { else {
@ -385,7 +387,7 @@ cbd_check(const char* dev,
{ {
struct check_state state; struct check_state state;
struct cbd_header header; struct cbd_header header;
uint8_t pblkbuf[PBLK_SIZE]; uint8_t buf[SECTOR_SIZE];
u32 n; u32 n;
memset(&state, 0, sizeof(state)); memset(&state, 0, sizeof(state));
@ -397,8 +399,8 @@ cbd_check(const char* dev,
state.clean = true; state.clean = true;
verbose(1, "Reading header\n"); verbose(1, "Reading header\n");
pblk_read(state.fd, 0, 1, pblkbuf); pblk_read(state.fd, SECTOR_SIZE, 0, 1, buf);
cbd_header_get(pblkbuf, &header); cbd_header_get(buf, &header);
verbose(1, "Checking header\n"); verbose(1, "Checking header\n");
check_header(&header); check_header(&header);
if (!force && !(header.params.flags & CBD_FLAG_DIRTY)) { if (!force && !(header.params.flags & CBD_FLAG_DIRTY)) {
@ -409,7 +411,7 @@ cbd_check(const char* dev,
state.pbatv = calloc(header.params.nr_zones, sizeof(u8*)); state.pbatv = calloc(header.params.nr_zones, sizeof(u8*));
for (n = 0; n < header.params.nr_zones; ++n) { for (n = 0; n < header.params.nr_zones; ++n) {
state.pbatv[n] = calloc(PBLK_SIZE, pbat_len(&header.params)); state.pbatv[n] = calloc(pblk_size(&header.params), pbat_len(&header.params));
} }
verbose(1, "Checking lbat\n"); verbose(1, "Checking lbat\n");
@ -436,8 +438,8 @@ cbd_check(const char* dev,
header.stats.lblk_used = state.lblk_used; header.stats.lblk_used = state.lblk_used;
} }
header.params.flags &= ~(CBD_FLAG_ERROR | CBD_FLAG_DIRTY); header.params.flags &= ~(CBD_FLAG_ERROR | CBD_FLAG_DIRTY);
cbd_header_put(pblkbuf, &header); cbd_header_put(buf, &header);
pblk_write(state.fd, 0, 1, pblkbuf); pblk_write(state.fd, SECTOR_SIZE, 0, 1, buf);
} }
close(state.fd); close(state.fd);

View File

@ -3,20 +3,20 @@
#include <cbdutil.h> #include <cbdutil.h>
static void static void
pblk_write(int fd, u64 pblk, u32 count, const u8* data) pblk_write(int fd, u32 pblk_size, u64 pblk, u32 count, const u8* data)
{ {
off_t pos; off_t pos;
size_t remain; size_t remain;
ssize_t ret; ssize_t ret;
pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET); pos = lseek(fd, pblk * pblk_size, SEEK_SET);
if (pos == (off_t)-1) { if (pos == (off_t)-1) {
error("Failed to seek\n"); error("Failed to seek\n");
} }
remain = count * PBLK_SIZE; remain = count * pblk_size;
while (remain) { while (remain) {
ret = write(fd, data, count * PBLK_SIZE); ret = write(fd, data, remain);
if (ret <= 0) { if (ret <= 0) {
error("Failed to write\n"); error("Failed to write\n");
} }
@ -27,14 +27,16 @@ pblk_write(int fd, u64 pblk, u32 count, const u8* data)
int int
cbd_format(const char* dev, cbd_format(const char* dev,
uint64_t psize, uint16_t pbatlen, uint8_t pshift, uint8_t lshift,
uint16_t lshift, uint64_t lsize, uint16_t pbatlen,
enum cbd_alg alg, uint level) enum cbd_alg alg, uint level,
uint64_t psize, uint64_t lsize)
{ {
int devfd; int devfd;
uint32_t lblk_size; uint pblk_size;
uint lblk_size;
struct cbd_header header; struct cbd_header header;
uint8_t pblkbuf[PBLK_SIZE]; uint8_t buf[PAGE_SIZE];
uint64_t pblk; uint64_t pblk;
uint64_t zone_idx; uint64_t zone_idx;
@ -43,34 +45,24 @@ cbd_format(const char* dev,
error("Cannot open device\n"); error("Cannot open device\n");
} }
if (!psize) { if (!pshift) {
off_t pos; pshift = CBD_DEFAULT_PHYSICAL_BLOCK_SHIFT;
pos = lseek(devfd, 0, SEEK_END);
if (pos == (off_t)-1) {
error("Cannot seek device\n");
}
psize = pos / PBLK_SIZE * PBLK_SIZE;
} }
if (!pbatlen) { if (pshift < PBLK_SHIFT_MIN || pshift > PBLK_SHIFT_MAX) {
pbatlen = 1; error("Physical block shift %u is not in [%u,%u]\n",
(uint)pshift, (uint)PBLK_SHIFT_MIN, (uint)PBLK_SHIFT_MAX);
} }
pblk_size = SECTOR_SIZE * (1 << pshift);
if (!lshift) { if (!lshift) {
lshift = CBD_DEFAULT_LOGICAL_BLOCK_SHIFT; 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) { 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); error("Logical block shift %u is not in [%u,%u]\n",
(uint)lshift, (uint)LBLK_SHIFT_MIN, (uint)LBLK_SHIFT_MAX);
} }
if (lsize % (1 << (lshift + PBLK_SHIFT))) { lblk_size = pblk_size * (1 << lshift);
error("Logical size %lu is not a multiple of %u bytes\n", (ulong)psize, (uint)lblk_size); if (!pbatlen) {
pbatlen = 1;
} }
if (alg <= CBD_ALG_NONE || alg >= CBD_ALG_MAX) { if (alg <= CBD_ALG_NONE || alg >= CBD_ALG_MAX) {
error("Compression algorithm %d unknown\n", (int)alg); error("Compression algorithm %d unknown\n", (int)alg);
@ -78,55 +70,79 @@ cbd_format(const char* dev,
if (level < 1 || level > 9) { if (level < 1 || level > 9) {
error("Compression level %u out of bounds\n", level); error("Compression level %u out of bounds\n", level);
} }
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);
}
printf("%s: paramaters...\n", __func__); printf("%s: parameters...\n", __func__);
printf(" psize=%lu\n", (unsigned long)psize); printf(" pshift=%u\n", (unsigned int)pshift);
printf(" lshift=%u\n", (unsigned int)lshift);
printf(" pbatlen=%hu\n", (unsigned short)pbatlen); printf(" pbatlen=%hu\n", (unsigned short)pbatlen);
printf(" lshift=%hu\n", (unsigned short)lshift); printf(" alg=%d\n", (int)alg);
printf(" level=%u\n", level);
printf(" psize=%lu\n", (unsigned long)psize);
printf(" lsize=%lu\n", (unsigned long)lsize); printf(" lsize=%lu\n", (unsigned long)lsize);
memset(&header, 0, sizeof(header)); memset(&header, 0, sizeof(header));
memcpy(header.magic, CBD_MAGIC, sizeof(header.magic)); memcpy(header.magic, CBD_MAGIC, sizeof(header.magic));
header.version_major = CBD_VERSION_MAJOR; header.version_major = CBD_VERSION_MAJOR;
header.version_minor = CBD_VERSION_MINOR; header.version_minor = CBD_VERSION_MINOR;
header.params.flags = 0; header.params.flags = 0;
header.params.algorithm = alg; header.params.compression = 0;
header.params.compression = level; cbd_compression_alg_put(&header.params, alg);
header.params.pbat_len = pbatlen; cbd_compression_level_put(&header.params, level);
header.params.pblk_shift = pshift;
header.params.lblk_shift = lshift; header.params.lblk_shift = lshift;
header.params.nr_pblk = psize / PBLK_SIZE; header.params.lba_elem_pblk_bytes =
((psize / pblk_size) <= 0xffff ? 2 :
((psize / pblk_size) <= 0xffffffff ? 4 : 6));
header.params.pbat_len = pbatlen;
/* XXX: Initial estimate */ /* XXX: Initial estimate */
header.params.lblk_per_zone = zone_data_len(&header.params) * (lsize / lblk_size) / (psize / PBLK_SIZE); 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); 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.nr_zones = ((psize / pblk_size) - CBD_HEADER_BLOCKS) / zone_len(&header.params);
header.params.lblk_per_zone = DIV_ROUND_UP(lsize / lblk_size, header.params.nr_zones); header.params.lblk_per_zone = DIV_ROUND_UP(lsize / lblk_size, header.params.nr_zones);
printf("%s: parameters...\n", __func__); printf("%s: header...\n", __func__);
printf(" algorithm=%d\n", (int)header.params.algorithm); printf(" compression=0x%02x\n", (unsigned int)header.params.compression);
printf(" compression=%u\n", (unsigned int)header.params.compression); printf(" pblk_shift=%hu\n", (unsigned short)header.params.pblk_shift);
printf(" lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift); printf(" lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift);
printf(" nr_pblk=%lu\n", (unsigned long)header.params.nr_pblk); printf(" lba_elem_pblk_bytes=%hu\n", (unsigned short)header.params.lba_elem_pblk_bytes);
printf(" pbat_len=%hu\n", (unsigned short)header.params.pbat_len);
printf(" nr_zones=%lu\n", (unsigned long)header.params.nr_zones); printf(" nr_zones=%lu\n", (unsigned long)header.params.nr_zones);
printf(" lblk_per_zone=%lu\n", (unsigned long)header.params.lblk_per_zone); printf(" lblk_per_zone=%lu\n", (unsigned long)header.params.lblk_per_zone);
memset(pblkbuf, 0, sizeof(pblkbuf)); memset(buf, 0, sizeof(buf));
cbd_header_put(pblkbuf, &header); cbd_header_put(buf, &header);
pblk = 0; pblk = 0;
pblk_write(devfd, pblk, 1, pblkbuf); pblk_write(devfd, pblk_size, pblk, 1, buf);
pblk += CBD_HEADER_BLOCKS; pblk += CBD_HEADER_BLOCKS;
printf("Writing %lu zones starting at %lu\n", printf("Writing %lu zones ...\n",
(unsigned long)header.params.nr_zones, (unsigned long)pblk); (unsigned long)header.params.nr_zones);
memset(pblkbuf, 0, sizeof(pblkbuf)); memset(buf, 0, sizeof(buf));
for (zone_idx = 0; zone_idx < header.params.nr_zones; ++zone_idx) { for (zone_idx = 0; zone_idx < header.params.nr_zones; ++zone_idx) {
uint32_t count; uint32_t count;
uint32_t n; uint32_t n;
pblk = zone_off(&header.params, zone_idx); pblk = zone_off(&header.params, zone_idx);
count = zone_metadata_len(&header.params); 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) { for (n = 0; n < count; ++n) {
pblk_write(devfd, pblk + n, 1, pblkbuf); pblk_write(devfd, pblk_size, pblk + n, 1, buf);
} }
} }

View File

@ -8,26 +8,25 @@ static uint64_t
device_logical_size(const char* dev) device_logical_size(const char* dev)
{ {
int fd; int fd;
uint8_t pblkbuf[PBLK_SIZE]; uint8_t buf[SECTOR_SIZE];
struct cbd_header header; struct cbd_header header;
uint64_t lblk_size; uint64_t lblk_total;
fd = open(dev, O_RDONLY); fd = open(dev, O_RDONLY);
if (fd < 0) { if (fd < 0) {
error("Cannot open device\n"); error("Cannot open device\n");
} }
if (read(fd, pblkbuf, sizeof(pblkbuf)) != sizeof(pblkbuf)) { if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
error("Cannot read device\n"); error("Cannot read device\n");
} }
close(fd); close(fd);
cbd_header_get(pblkbuf, &header); cbd_header_get(buf, &header);
if (memcmp(header.magic, CBD_MAGIC, sizeof(header.magic)) != 0) { if (memcmp(header.magic, CBD_MAGIC, sizeof(header.magic)) != 0) {
error("Bad magic\n"); error("Bad magic\n");
} }
lblk_total = header.params.lblk_per_zone * header.params.nr_zones;
lblk_size = header.params.lblk_per_zone * header.params.nr_zones; return lblk_total * lblk_size(&header.params);
return (lblk_size << (header.params.lblk_shift + PBLK_SHIFT));
} }
int int

View File

@ -6,18 +6,18 @@ int
cbd_stats(const char* dev, struct cbd_stats* stats) cbd_stats(const char* dev, struct cbd_stats* stats)
{ {
int fd; int fd;
uint8_t pblkbuf[PBLK_SIZE]; uint8_t buf[SECTOR_SIZE];
struct cbd_header header; struct cbd_header header;
fd = open(dev, O_RDONLY); fd = open(dev, O_RDONLY);
if (fd < 0) { if (fd < 0) {
error("Cannot open device\n"); error("Cannot open device\n");
} }
if (read(fd, pblkbuf, sizeof(pblkbuf)) != sizeof(pblkbuf)) { if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
error("Cannot read device\n"); error("Cannot read device\n");
} }
close(fd); close(fd);
cbd_header_get(pblkbuf, &header); cbd_header_get(buf, &header);
if (memcmp(header.magic, CBD_MAGIC, sizeof(header.magic)) != 0) { if (memcmp(header.magic, CBD_MAGIC, sizeof(header.magic)) != 0) {
error("Bad magic\n"); error("Bad magic\n");
} }