From 8229ef90bd8623f8b0f1e047eb236ec43c985ada Mon Sep 17 00:00:00 2001 From: Tom Marshall Date: Tue, 12 Nov 2019 22:25:46 +0100 Subject: [PATCH] Make pblk len variable, add format profiles, and cleanup --- README | 40 ++++++---- cbd/cbd.c | 146 +++++++++++++++++++++++++++--------- dm-compress/compress.c | 92 +++++++++++------------ dm-compress/lbatview.c | 10 +-- dm-compress/lbd.c | 44 ++++++----- dm-compress/pbat.c | 12 +-- dm-compress/util.c | 15 ++-- include/libcbd.h | 22 +++++- include/linux/dm-compress.h | 137 ++++++++++++++++++++------------- libcbd/check.c | 66 ++++++++-------- libcbd/format.c | 120 ++++++++++++++++------------- libcbd/open.c | 13 ++-- libcbd/stats.c | 6 +- 13 files changed, 442 insertions(+), 281 deletions(-) diff --git a/README b/README index 09cbce2..af07ff5 100644 --- a/README +++ b/README @@ -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 diff --git a/cbd/cbd.c b/cbd/cbd.c index 6308913..72517f2 100644 --- a/cbd/cbd.c +++ b/cbd/cbd.c @@ -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] 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] Open an existing compressed device\n" " create [opts] 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; } diff --git a/dm-compress/compress.c b/dm-compress/compress.c index 0dff902..8e4b83c 100644 --- a/dm-compress/compress.c +++ b/dm-compress/compress.c @@ -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; } diff --git a/dm-compress/lbatview.c b/dm-compress/lbatview.c index 66bb9f3..30e6eb3 100644 --- a/dm-compress/lbatview.c +++ b/dm-compress/lbatview.c @@ -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; diff --git a/dm-compress/lbd.c b/dm-compress/lbd.c index 01bea61..8222d0f 100644 --- a/dm-compress/lbd.c +++ b/dm-compress/lbd.c @@ -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); diff --git a/dm-compress/pbat.c b/dm-compress/pbat.c index 391a75b..e68e3e8 100644 --- a/dm-compress/pbat.c +++ b/dm-compress/pbat.c @@ -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; diff --git a/dm-compress/util.c b/dm-compress/util.c index 6b2f535..10a0faf 100644 --- a/dm-compress/util.c +++ b/dm-compress/util.c @@ -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; diff --git a/include/libcbd.h b/include/libcbd.h index 160b631..2b8c596 100644 --- a/include/libcbd.h +++ b/include/libcbd.h @@ -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 #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); diff --git a/include/linux/dm-compress.h b/include/linux/dm-compress.h index 4d48aa4..4b35dbf 100644 --- a/include/linux/dm-compress.h +++ b/include/linux/dm-compress.h @@ -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 diff --git a/libcbd/check.c b/libcbd/check.c index 24b0740..0a607db 100644 --- a/libcbd/check.c +++ b/libcbd/check.c @@ -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); diff --git a/libcbd/format.c b/libcbd/format.c index 2f79c8a..112d234 100644 --- a/libcbd/format.c +++ b/libcbd/format.c @@ -3,20 +3,20 @@ #include 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); } } diff --git a/libcbd/open.c b/libcbd/open.c index c3cc1bd..90611b6 100644 --- a/libcbd/open.c +++ b/libcbd/open.c @@ -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 diff --git a/libcbd/stats.c b/libcbd/stats.c index e35d58a..c95c785 100644 --- a/libcbd/stats.c +++ b/libcbd/stats.c @@ -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"); }