Make pblk len variable, add format profiles, and cleanup
This commit is contained in:
parent
efc83e0dc2
commit
8229ef90bd
40
README
40
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
|
||||
|
|
146
cbd/cbd.c
146
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] <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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
120
libcbd/format.c
120
libcbd/format.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue