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:
- Sectors are always 512 bytes (kernel constant).
- Physical blocks are always 4kb (internal constant).
- Logical blocks are variable 4kb .. 1gb.
- Physical blocks are variable 512b .. 4kb.
- Logical blocks are variable 4kb .. 4mb.
- All integers are little endian.
Block device layout:
- byte[4096] header
/* Offset 0 */
- pblk[0] header (512 bytes)
/* Offset 0: magic and version */
- byte[4] magic
- u16 version_major
- u16 version_minor
/* Offset 8: parameters */
- u16 flags
- u8 algorithm (1=lz4, 2=zlib, ...) [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 lblk_shift (1..18) [4 = 64kb]
- u64 nr_pblk
- u32 nr_zones
- u32 lblk_per_zone
- byte[32] reserved
/* Offset 64 */
- u64 pblk_alloc
- byte[] reserved
- byte[] zone ... vector of zone
- byte[40] reserved
/* Offset 64: stats */
- u64 pblk_used
- u64 lblk_used
- 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:
- Min: header plus one zone (header, pbat, lbat, data)
@ -43,8 +51,8 @@ There are six different lblk_alloc sizes:
Zone layout:
- byte[4k*pbat_len] Physical block allocation table (pbat)
- lblk_alloc_x_y[] Logical block allocation table (lbat)
Note: padded to pblk size
- data[4k*pbat_len*4k*8] Data
One pblk per bit in pbat
- byte[pblk_size*pbat_len] Physical block allocation table (pbat)
- lblk_alloc_x_y[] Logical block allocation table (lbat)
Note: padded to pblk size
- data[] Data
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;
}
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 void __attribute__((noreturn))
@ -83,19 +131,23 @@ usage(void)
"\n");
fprintf(stderr, "Commands:\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"
" -S --pysical-size Physical size [device size]\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"
" -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"
" -c and -s are different ways of specifying the compressed device size.\n"
" Only one may be used, not both.\n"
" -l and -L are different ways of specifying the logical block size.\n"
" Only one may be used, not both.\n"
" Profiles:\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"
" open [opts] <device> <name> Open an existing compressed device\n"
" create [opts] <device> <name> Alias for open\n"
@ -115,52 +167,51 @@ usage(void)
static int
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[] = {
{ "physical-size", required_argument, NULL, 'S' },
{ "logical-blksize", required_argument, NULL, 'L' },
{ "pbat-len", required_argument, NULL, 'P' },
{ "compress-factor", required_argument, NULL, 'c' },
{ "logical-shift", required_argument, NULL, 'l' },
{ "size", required_argument, NULL, 's' },
{ "compress-alg", required_argument, NULL, 'z' },
{ "compress-level", required_argument, NULL, 'Z' },
{ NULL, no_argument, NULL, 0 }
{ "pbat-len", required_argument, NULL, 'P' },
{ "physical-size", required_argument, NULL, 'S' },
{ "compress-factor", required_argument, NULL, 'c' },
{ "logical-blksize", required_argument, NULL, 'l' },
{ "physical-blksize", required_argument, NULL, 'p' },
{ "size", required_argument, NULL, 's' },
{ "compress-alg", required_argument, NULL, 'z' },
{ "compress-level", required_argument, NULL, 'Z' },
{ "profile", required_argument, NULL, 0x1 },
{ NULL, no_argument, NULL, 0 }
};
char opt;
uint64_t optval;
uint64_t psize = 0;
uint16_t pbatlen = 1;
uint16_t lshift = 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;
uint level = 1;
uint8_t pshift;
uint8_t lshift;
const char* dev;
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
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':
if (!parse_numeric_arg(optarg, &optval)) {
error("Failed to parse \"%s\"\n", optarg);
}
psize = optval;
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':
error("Implement me!\n");
break;
@ -168,7 +219,19 @@ do_format(int argc, char** argv)
if (!parse_numeric_arg(optarg, &optval)) {
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;
case 's':
if (!parse_numeric_arg(optarg, &optval)) {
@ -197,16 +260,29 @@ do_format(int argc, char** argv)
}
level = optval;
break;
case 0x1:
if (!parse_profile(optarg, &pblksize, &lblksize, &alg, &level)) {
error("Invalid profile \"%s\"\n", optarg);
}
break;
default:
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) {
usage();
}
dev = argv[optind++];
cbd_format(dev, psize, pbatlen, lshift, lsize, alg, level);
cbd_format(dev, pshift, lshift, pbatlen, alg, level, psize, lsize);
return 0;
}

View File

@ -65,15 +65,9 @@ struct compress
static struct kobject* compress_kobj;
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;
}
static inline u64
dm_target_pblk_size(struct dm_target* ti)
{
return ti->len >> (PBLK_SHIFT - SECTOR_SHIFT);
return ti->len * (pblk_size(params) >> SECTOR_SHIFT);
}
/**************************************
@ -119,44 +113,58 @@ compress_read_header(struct compress* c)
ret = -EINVAL;
goto out;
}
if (header.params.algorithm == CBD_ALG_NONE ||
header.params.algorithm >= CBD_ALG_MAX) {
if (cbd_compression_alg_get(&header.params) == CBD_ALG_NONE ||
cbd_compression_alg_get(&header.params) >= CBD_ALG_MAX) {
printk(KERN_ERR "%s: bad algorithm\n", __func__);
ret = -EINVAL;
goto out;
}
#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__);
ret = -EINVAL;
goto out;
}
#endif
#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__);
ret = -EINVAL;
goto out;
}
#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__);
ret = -EINVAL;
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 ||
header.params.lblk_shift > LBLK_SHIFT_MAX) {
printk(KERN_ERR "%s: bad lblk_shift\n", __func__);
ret = -EINVAL;
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 " algorithm=%hu\n", (unsigned short)header.params.algorithm);
printk(KERN_INFO " compression=%hu\n", (unsigned short)header.params.compression);
printk(KERN_INFO " pbat_len=%hu\n", (unsigned short)header.params.pbat_len);
printk(KERN_INFO " compression=0x%02x\n", (unsigned int)header.params.compression);
printk(KERN_INFO " pblk_shift=%hu\n", (unsigned short)header.params.pblk_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 " lblk_per_zone=%u\n", (unsigned int)header.params.lblk_per_zone);
printk(KERN_INFO "%s: stats...\n", __func__);
@ -208,7 +216,7 @@ compress_read(struct compress *c, struct bio *bio)
struct lbd* lbd = NULL;
struct bio_vec bv;
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) {
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 bio_vec bv;
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) {
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);
switch (a->attr_id) {
case attr_lblk_size:
val = PBLK_SIZE * lblk_per_pblk(&c->kparams.params);
val = lblk_size(&c->kparams.params);
break;
case attr_pblk_used:
val = c->kstats.stats.pblk_used;
break;
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;
break;
case attr_lblk_used:
@ -463,7 +472,7 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
unsigned int argn;
u32 cache_pages = 0;
struct compress *c = NULL;
u64 backing_nr_pblks;
u64 target_nr_pblks;
printk(KERN_INFO "%s: enter: argc=%u\n", __func__, argc);
for (argn = 0; argn < argc; ++argn) {
@ -509,13 +518,7 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
ti->private = c;
backing_nr_pblks = blkdev_pblk_size(c->dev->bdev);
if ((backing_nr_pblks >> 48) != 0) {
ti->error = "Device too large";
ret = -EINVAL;
goto err;
}
ti->per_io_data_size = ALIGN(sizeof(struct compress_io), ARCH_KMALLOC_MINALIGN);
ret = compress_register_sysfs(c);
if (ret) {
@ -525,23 +528,27 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
c->kparams.dev = c->dev->bdev;
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) {
/* Minimum of 1/1k RAM and 1/64k device size */
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()) {
cache_pages = 32 * 2 * num_online_cpus();
}
}
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) {
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 (c->kparams.params.nr_pblk > backing_nr_pblks) {
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__);
if (target_nr_pblks < zone_off(&c->kparams.params, c->kparams.params.nr_zones)) {
printk(KERN_ERR "%s: Device too small\n", __func__);
ret = -EINVAL;
goto err;
}

View File

@ -238,7 +238,6 @@ lbatview_free_pblk(struct lbatview* lv, u64 pblk)
ret = pbat_free(pbat, pblk);
BUG_ON(ret != 0);
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);
if (ret) {
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. */
u32 lbat_elem_off = zone_rel_lblk * lba_len(&lv->kparams->params);
/* 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;
}
@ -340,13 +340,13 @@ lbatview_elem_realloc(struct lbatview* lv, u64 lblk, u32 len)
elem_off = lbatview_elem_off(lv, lblk);
req_nalloc = (len == CBD_UNCOMPRESSED) ?
lblk_per_pblk(&lv->kparams->params) :
DIV_ROUND_UP(len, PBLK_SIZE);
DIV_ROUND_UP(len, pblk_size(&lv->kparams->params));
elem_lelen = 0;
lbatview_rmem(lv, elem_off, lba_elem_len_bytes(&lv->kparams->params), &elem_lelen);
elem_len = __le32_to_cpu(elem_lelen);
cur_nalloc = (elem_len == CBD_UNCOMPRESSED) ?
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;
while (cur_nalloc < req_nalloc) {
@ -558,7 +558,7 @@ lbatviewcache_get(struct lbatviewcache* lvc, u64 lblk)
zone_lbat_pblk = lbat_off(lvc->params, zone);
rel_lblk = lblk - lvc->params->lblk_per_zone * zone;
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;
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);
BUG_ON(state == NULL);
clen = LZ4_compress_fast(lbd->buf, state->buf,
PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params),
PBLK_SIZE * (lblk_per_pblk(&lbd->kparams->params) - 1),
lbd->kparams->params.compression, state->lz4_workmem);
lblk_size(&lbd->kparams->params),
lblk_size(&lbd->kparams->params) -
pblk_size(&lbd->kparams->params),
cbd_compression_level_get(&lbd->kparams->params),
state->lz4_workmem);
if (clen <= 0) {
put_cpu();
return 0;
@ -119,7 +121,7 @@ lblk_decompress_lz4(struct lbd* lbd)
int ret;
int cpu;
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();
state = lblk_get_compress_state(lbd->percpu, cpu);
@ -156,9 +158,10 @@ lblk_compress_zlib(struct lbd* lbd)
ret = zlib_deflateReset(stream);
BUG_ON(ret != Z_OK);
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->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);
if (ret != Z_STREAM_END) {
put_cpu();
@ -178,7 +181,7 @@ lblk_decompress_zlib(struct lbd* lbd)
int cpu;
struct lblk_compress_state* state;
z_stream* stream;
u32 dlen = PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params);
u32 dlen = lblk_size(&lbd->kparams->params);
cpu = get_cpu();
state = lblk_get_compress_state(lbd->percpu, cpu);
@ -218,12 +221,12 @@ static size_t
lblk_compress(struct lbd* lbd)
{
#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);
}
#endif
#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);
}
#endif
@ -237,12 +240,12 @@ static bool
lblk_decompress(struct lbd* lbd)
{
#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);
}
#endif
#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);
}
#endif
@ -339,11 +342,11 @@ lbd_flush(struct lbd* lbd)
}
lbd->c_len = lblk_compress(lbd);
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) {
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 {
lbd->c_len = CBD_UNCOMPRESSED;
@ -400,12 +403,12 @@ lbd_read(struct lbd* lbd)
}
lbd->c_len = lbatview_elem_len(lbd->lv, lbd->lblk);
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 {
count = (lbd->c_len == CBD_UNCOMPRESSED) ?
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) {
pblk = lbatview_elem_pblk(lbd->lv, lbd->lblk, n);
if (pblk == PBLK_NONE) {
@ -494,7 +497,7 @@ void
lbd_data_read(struct lbd* lbd, u32 off, u32 len, u8* buf)
{
/* 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__);
return;
}
@ -507,7 +510,7 @@ void
lbd_data_write(struct lbd* lbd, u32 off, u32 len, const u8* buf)
{
/* 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__);
return;
}
@ -556,12 +559,12 @@ lbdcache_alloc_compress_state(void* percpu, const struct cbd_params* params, int
}
statep = per_cpu_ptr(percpu, cpu);
*statep = state;
state->buf = vmalloc(PBLK_SIZE * lblk_per_pblk(params));
state->buf = vmalloc(lblk_size(params));
if (!state->buf) {
return false;
}
#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);
if (!state->lz4_workmem) {
return false;
@ -573,7 +576,8 @@ lbdcache_alloc_compress_state(void* percpu, const struct cbd_params* params, int
if (!state->zlib_cstream.workspace) {
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_DEFAULT_STRATEGY);
BUG_ON(ret != Z_OK);

View File

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

View File

@ -99,7 +99,7 @@ cbd_free_pagev(struct page** pagev, size_t len)
static struct bio*
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;
u32 n;
@ -112,9 +112,9 @@ pblk_io_prepare(struct block_device* bdev, unsigned int op,
bio_set_dev(bio, bdev);
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) {
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();
}
}
@ -129,7 +129,8 @@ pblk_read_wait(struct compress_params* kparams,
int ret;
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) {
printk(KERN_ERR "%s: out of memory\n", __func__);
return -ENOMEM;
@ -150,7 +151,8 @@ pblk_write_wait(struct compress_params* kparams,
int ret;
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) {
printk(KERN_ERR "%s: out of memory\n", __func__);
return -ENOMEM;
@ -195,7 +197,8 @@ pblk_write(struct compress_params* kparams,
struct bio* bio;
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) {
printk(KERN_ERR "%s: out of memory\n", __func__);
kparams->params.flags |= CBD_FLAG_ERROR;

View File

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

View File

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

View File

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

View File

@ -3,20 +3,20 @@
#include <cbdutil.h>
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;
size_t remain;
ssize_t ret;
pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET);
pos = lseek(fd, pblk * pblk_size, SEEK_SET);
if (pos == (off_t)-1) {
error("Failed to seek\n");
}
remain = count * PBLK_SIZE;
remain = count * pblk_size;
while (remain) {
ret = write(fd, data, count * PBLK_SIZE);
ret = write(fd, data, remain);
if (ret <= 0) {
error("Failed to write\n");
}
@ -27,14 +27,16 @@ pblk_write(int fd, u64 pblk, u32 count, const u8* data)
int
cbd_format(const char* dev,
uint64_t psize, uint16_t pbatlen,
uint16_t lshift, uint64_t lsize,
enum cbd_alg alg, uint level)
uint8_t pshift, uint8_t lshift,
uint16_t pbatlen,
enum cbd_alg alg, uint level,
uint64_t psize, uint64_t lsize)
{
int devfd;
uint32_t lblk_size;
uint pblk_size;
uint lblk_size;
struct cbd_header header;
uint8_t pblkbuf[PBLK_SIZE];
uint8_t buf[PAGE_SIZE];
uint64_t pblk;
uint64_t zone_idx;
@ -43,34 +45,24 @@ cbd_format(const char* dev,
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 (!pshift) {
pshift = CBD_DEFAULT_PHYSICAL_BLOCK_SHIFT;
}
if (!pbatlen) {
pbatlen = 1;
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);
}
pblk_size = SECTOR_SIZE * (1 << pshift);
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);
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))) {
error("Logical size %lu is not a multiple of %u bytes\n", (ulong)psize, (uint)lblk_size);
lblk_size = pblk_size * (1 << lshift);
if (!pbatlen) {
pbatlen = 1;
}
if (alg <= CBD_ALG_NONE || alg >= CBD_ALG_MAX) {
error("Compression algorithm %d unknown\n", (int)alg);
@ -78,55 +70,79 @@ cbd_format(const char* dev,
if (level < 1 || level > 9) {
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(" psize=%lu\n", (unsigned long)psize);
printf("%s: parameters...\n", __func__);
printf(" pshift=%u\n", (unsigned int)pshift);
printf(" lshift=%u\n", (unsigned int)lshift);
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);
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.flags = 0;
header.params.algorithm = alg;
header.params.compression = level;
header.params.pbat_len = pbatlen;
header.params.compression = 0;
cbd_compression_alg_put(&header.params, alg);
cbd_compression_level_put(&header.params, level);
header.params.pblk_shift = pshift;
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 */
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);
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);
printf("%s: parameters...\n", __func__);
printf(" algorithm=%d\n", (int)header.params.algorithm);
printf(" compression=%u\n", (unsigned int)header.params.compression);
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);
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(" lblk_per_zone=%lu\n", (unsigned long)header.params.lblk_per_zone);
memset(pblkbuf, 0, sizeof(pblkbuf));
cbd_header_put(pblkbuf, &header);
memset(buf, 0, sizeof(buf));
cbd_header_put(buf, &header);
pblk = 0;
pblk_write(devfd, pblk, 1, pblkbuf);
pblk_write(devfd, pblk_size, pblk, 1, buf);
pblk += CBD_HEADER_BLOCKS;
printf("Writing %lu zones starting at %lu\n",
(unsigned long)header.params.nr_zones, (unsigned long)pblk);
printf("Writing %lu zones ...\n",
(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) {
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);
pblk_write(devfd, pblk_size, pblk + n, 1, buf);
}
}

View File

@ -8,26 +8,25 @@ static uint64_t
device_logical_size(const char* dev)
{
int fd;
uint8_t pblkbuf[PBLK_SIZE];
uint8_t buf[SECTOR_SIZE];
struct cbd_header header;
uint64_t lblk_size;
uint64_t lblk_total;
fd = open(dev, O_RDONLY);
if (fd < 0) {
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");
}
close(fd);
cbd_header_get(pblkbuf, &header);
cbd_header_get(buf, &header);
if (memcmp(header.magic, CBD_MAGIC, sizeof(header.magic)) != 0) {
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_size << (header.params.lblk_shift + PBLK_SHIFT));
return lblk_total * lblk_size(&header.params);
}
int

View File

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