Fix a bunch of things

* Fix command line handling.
* Move option/parameter validation to libcbd.
* Make resize argument the logical size.
* Make blkdev_pblk_* take dm_compress instead of block_device.
* Reinstate dm_compress.io_failed.
* Other misc stuff.
This commit is contained in:
Tom Marshall 2019-10-10 13:21:36 -07:00
parent 36dec597ac
commit 07f4221a5f
8 changed files with 130 additions and 126 deletions

115
cbd/cbd.c
View File

@ -84,7 +84,6 @@ usage(void)
fprintf(stderr, "Commands:\n"
" format [opts] <device> Create (format) a compressed device\n"
" -S --pysical-size Physical size [device size]\n"
" -O --offset Offset in device [0]\n"
" -L --logical-blksize Logical block size\n"
" -c --compress-factor Compression factor [2.0]\n"
" -l --logical-shift Logical block shift [4]\n"
@ -102,7 +101,7 @@ usage(void)
" -n --assume-no Assume \"no\" no all questions\n"
" -y --assume-yes Assume \"yes\" to all questions\n"
" resize [opts] <device> Resize an existing compressed device\n"
" -S --physical-size New (physical) size [use all]\n"
" -s --size New logical size [use all]\n"
" stats [opts] <name> Show device statistics\n"
"\n");
exit(1);
@ -111,22 +110,20 @@ usage(void)
static int
do_format(int argc, char** argv)
{
static const char short_opts[] = "S:O:L:c:l:s:";
static const char short_opts[] = "S:L:c:l:s:";
static const struct option long_opts[] = {
{ "physical-size", 1, NULL, 'S' },
{ "offset", 1, NULL, 'O' },
{ "logical-blksize", 1, NULL, 'L' },
{ "compress-factor", 1, NULL, 'c' },
{ "logical-shift", 1, NULL, 'l' },
{ "size", 1, NULL, 's' },
{ NULL, 0, NULL, 0 }
{ "physical-size", required_argument, NULL, 'S' },
{ "logical-blksize", required_argument, NULL, 'L' },
{ "compress-factor", required_argument, NULL, 'c' },
{ "logical-shift", required_argument, NULL, 'l' },
{ "size", required_argument, NULL, 's' },
{ NULL, no_argument, NULL, 0 }
};
char opt;
uint64_t optval;
uint64_t poff = 0;
uint64_t psize = 0;
uint64_t lsize = 0;
uint16_t lshift = 0;
uint64_t lsize = 0;
const char* dev;
@ -137,23 +134,12 @@ do_format(int argc, char** argv)
error("Failed to parse \"%s\"\n", optarg);
}
psize = optval;
if (psize % PBLK_SIZE) {
error("Size \"%s\" is not a multiple of %u bytes\n", optarg, (uint)PBLK_SIZE);
}
break;
case 'O':
if (!parse_arg(optarg, &optval)) {
error("Failed to parse \"%s\"\n", optarg);
}
poff = optval;
break;
case 'L':
if (!parse_arg(optarg, &optval)) {
error("Failed to parse \"%s\"\n", optarg);
}
if ((optval & (optval-1)) ||
optval < (1 << (PBLK_SHIFT + LBLK_SHIFT_MIN)) ||
optval > (1 << (PBLK_SHIFT + LBLK_SHIFT_MAX))) {
if ((optval & (optval-1)) || optval < PBLK_SIZE) {
error("Size \"%s\" is not a valid logical block size\n", optarg);
}
lshift = (optval >> PBLK_SHIFT);
@ -165,9 +151,6 @@ do_format(int argc, char** argv)
if (!parse_arg(optarg, &optval)) {
error("Failed to parse \"%s\"\n", optarg);
}
if (optval < LBLK_SHIFT_MIN || optval > LBLK_SHIFT_MAX) {
error("Size \"%s\" is not a valid logical block shift\n", optarg);
}
lshift = optval;
break;
case 's':
@ -175,9 +158,6 @@ do_format(int argc, char** argv)
error("Failed to parse \"%s\"\n", optarg);
}
lsize = optval;
if (lsize % PBLK_SIZE) {
error("Size \"%s\" is not a multiple of %u bytes\n", optarg, (uint)PBLK_SIZE);
}
break;
default:
usage();
@ -188,7 +168,7 @@ do_format(int argc, char** argv)
}
dev = argv[optind++];
cbd_format(dev, poff, psize, lsize, lshift);
cbd_format(dev, psize, lshift, lsize);
return 0;
}
@ -197,19 +177,18 @@ static int
do_open(int argc, char** argv)
{
char dev[PATH_MAX];
char name[PATH_MAX];
const char* name;
if (argc != 3) {
usage();
}
strcpy(dev, argv[1]);
strcpy(name, argv[2]);
if (dev[0] != '/') {
sprintf(dev, "/dev/mapper/%s", argv[1]);
}
name = argv[2];
cbd_open(dev, 0, 0, name);
cbd_open(dev, name);
return 0;
}
@ -229,14 +208,29 @@ do_close(int argc, char** argv)
return 0;
}
static int
do_stats(int argc, char** argv)
{
const char* name;
if (argc != 2) {
usage();
}
name = argv[1];
cbd_stats(name);
return 0;
}
static int
do_check(int argc, char** argv)
{
static const char short_opts[] = "ny";
static const struct option long_opts[] = {
{ "assume-no", 0, NULL, 'n' },
{ "assume-yes", 0, NULL, 'y' },
{ NULL, 0, NULL, 0 }
{ "assume-no", no_argument, NULL, 'n' },
{ "assume-yes", no_argument, NULL, 'y' },
{ NULL, no_argument, NULL, 0 }
};
char opt;
tristate_t auto_response = t_none;
@ -276,27 +270,25 @@ do_check(int argc, char** argv)
static int
do_resize(int argc, char** argv)
{
static const char short_opts[] = "S:";
static const char short_opts[] = "s:";
static const struct option long_opts[] = {
{ "physical-size", 1, NULL, 'S' },
{ NULL, 0, NULL, 0 }
{ "size", required_argument, NULL, 's' },
{ NULL, no_argument, NULL, 0 }
};
char opt;
uint64_t poff = 0;
uint64_t psize = 0;
uint64_t optval;
uint64_t lsize = 0;
const char* dev;
char dev[PATH_MAX];
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
switch (opt) {
case 'S':
if (!parse_arg(optarg, &psize)) {
case 's':
if (!parse_arg(optarg, &optval)) {
fprintf(stderr, "Failed to parse \"%s\"\n", optarg);
usage();
}
if (psize % PBLK_SIZE) {
fprintf(stderr, "Size \"%s\" is not a multiple of %u bytes\n", optarg, (uint)PBLK_SIZE);
}
lsize = optval;
break;
default:
usage();
@ -305,24 +297,13 @@ do_resize(int argc, char** argv)
if (argc - optind != 1) {
usage();
}
dev = argv[optind++];
cbd_resize(dev, poff, psize / PBLK_SHIFT);
return 0;
}
static int
do_stats(int argc, char** argv)
{
const char* dev;
if (argc != 1) {
usage();
strcpy(dev, argv[optind]);
if (dev[0] != '/') {
sprintf(dev, "/dev/mapper/%s", argv[optind]);
}
dev = argv[0];
++optind;
cbd_stats(dev);
cbd_resize(dev, lsize);
return 0;
}
@ -339,15 +320,15 @@ static struct cmd_dispatch dispatch[] =
{ "open", do_open },
{ "create", do_open },
{ "close", do_close },
{ "stats", do_stats },
{ "check", do_check },
{ "resize", do_resize },
{ "stats", do_stats },
};
int
main(int argc, char** argv)
{
static const char short_opts[] = "v";
static const char short_opts[] = "+v";
static const struct option long_opts[] = {
{ "verbose", 0, NULL, 'v' },
{ NULL, 0, NULL, 0 }

View File

@ -53,12 +53,10 @@ struct dm_compress_io {
struct dm_compress
{
struct dm_dev* dev;
bool io_failed;
struct cbd_params params;
/* XXX: dm_target.off */
sector_t dm_off;
u8* lz4_wrkmem;
u8* lz4_cbuf;
@ -170,7 +168,7 @@ compress_free_pages(void* ptr, size_t size)
**************************************/
static struct bio*
blkdev_pblk_io_prepare(struct block_device* dev, unsigned int op, u64 pblk, u32 count, void *data)
blkdev_pblk_io_prepare(struct dm_compress* dc, unsigned int op, u64 pblk, u32 count, void *data)
{
unsigned long data_addr;
struct bio* bio;
@ -184,7 +182,7 @@ blkdev_pblk_io_prepare(struct block_device* dev, unsigned int op, u64 pblk, u32
printk(KERN_ERR "%s: out of memory\n", __func__);
return NULL;
}
bio_set_dev(bio, dev);
bio_set_dev(bio, dc->dev->bdev);
bio->bi_opf = op;
bio->bi_iter.bi_sector = (pblk << (PBLK_SHIFT - SECTOR_SHIFT));
@ -200,12 +198,12 @@ blkdev_pblk_io_prepare(struct block_device* dev, unsigned int op, u64 pblk, u32
}
static int
blkdev_pblk_read(struct block_device* dev, u64 pblk, u32 count, void *data)
blkdev_pblk_read(struct dm_compress* dc, u64 pblk, u32 count, void *data)
{
int ret;
struct bio* bio;
bio = blkdev_pblk_io_prepare(dev, REQ_OP_READ, pblk, count, data);
bio = blkdev_pblk_io_prepare(dc, REQ_OP_READ, pblk, count, data);
if (!bio) {
printk(KERN_ERR "%s: out of memory\n", __func__);
return -ENOMEM;
@ -226,20 +224,25 @@ blkdev_pblk_write_endio(struct bio* bio)
void* data = page_address(bio->bi_io_vec[0].bv_page);
unsigned int count = bio->bi_max_vecs;
compress_free_pages(data, count);
if (bio->bi_status != BLK_STS_OK) {
struct dm_compress* dc = bio->bi_private;
dc->io_failed = true;
}
bio_put(bio);
}
static void
blkdev_pblk_write(struct block_device* dev, u64 pblk, u32 count, void *data)
blkdev_pblk_write(struct dm_compress* dc, u64 pblk, u32 count, void *data)
{
struct bio* bio;
bio = blkdev_pblk_io_prepare(dev, REQ_OP_WRITE, pblk, count, data);
bio = blkdev_pblk_io_prepare(dc, REQ_OP_WRITE, pblk, count, data);
if (!bio) {
printk(KERN_ERR "%s: out of memory\n", __func__);
return;
}
bio->bi_end_io = blkdev_pblk_write_endio;
bio->bi_private = dc;
submit_bio(bio);
}
@ -264,7 +267,7 @@ pblk_alloc_write(struct dm_compress* dc)
return -ENOMEM;
}
memcpy(pg, dc->pblk_alloc, count * PBLK_SIZE);
blkdev_pblk_write(dc->dev->bdev, pblk, count, pg);
blkdev_pblk_write(dc, pblk, count, pg);
dc->pblk_alloc_dirty = false;
@ -305,7 +308,7 @@ pblk_alloc_read(struct dm_compress* dc, u32 idx)
pblk = pblk_alloc_off(&dc->params, idx);
count = pblk_alloc_len(&dc->params);
ret = blkdev_pblk_read(dc->dev->bdev, pblk, count, dc->pblk_alloc);
ret = blkdev_pblk_read(dc, pblk, count, dc->pblk_alloc);
if (ret) {
return ret;
}
@ -425,7 +428,7 @@ lblk_alloc_elem_write(struct dm_compress* dc)
return -ENOMEM;
}
memcpy(pg, dc->lblk_alloc, count * PBLK_SIZE);
blkdev_pblk_write(dc->dev->bdev, pblk, count, pg);
blkdev_pblk_write(dc, pblk, count, pg);
return 0;
}
@ -455,7 +458,7 @@ lblk_alloc_elem_read(struct dm_compress* dc, u64 lblk)
count = 1 + (elem_end - 1) / PBLK_SIZE - (elem_off / PBLK_SIZE);
pblk = lblk_alloc_off(&dc->params, zone) + rel_pblk;
if (dc->lblk_alloc_pblk != pblk || dc->lblk_alloc_len < count) {
ret = blkdev_pblk_read(dc->dev->bdev, pblk, count, dc->lblk_alloc);
ret = blkdev_pblk_read(dc, pblk, count, dc->lblk_alloc);
if (ret != 0) {
return ret;
}
@ -581,7 +584,7 @@ lblk_write(struct dm_compress* dc)
return -ENOMEM;
}
memcpy(pg, c_buf, PBLK_SIZE);
blkdev_pblk_write(dc->dev->bdev, pblk, 1, pg);
blkdev_pblk_write(dc, pblk, 1, pg);
c_buf += PBLK_SIZE;
}
else {
@ -674,7 +677,7 @@ lblk_read(struct dm_compress* dc, u64 idx)
for (n = 0; n * PBLK_SIZE < c_len; ++n, p += PBLK_SIZE) {
pblk = dc->lblk_alloc_elem->pblk[n];
BUG_ON(pblk == 0);
ret = blkdev_pblk_read(dc->dev->bdev, pblk, 1, p);
ret = blkdev_pblk_read(dc, pblk, 1, p);
if (ret != 0) {
return ret;
}
@ -787,7 +790,7 @@ compress_open(struct dm_compress* dc, u64 dev_nr_pblks)
return -ENOMEM;
}
err = blkdev_pblk_read(dc->dev->bdev, 0, 1, pblkbuf);
err = blkdev_pblk_read(dc, 0, 1, pblkbuf);
if (err) {
printk(KERN_ERR "%s: failed to read header\n", __func__);
goto out;
@ -1040,7 +1043,6 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
kfree(dc);
return -EINVAL;
}
dc->dm_off = ti->begin;
ti->private = dc;
@ -1088,6 +1090,10 @@ compress_map(struct dm_target *ti, struct bio *bio)
struct dm_compress *dc = (struct dm_compress *)ti->private;
struct dm_compress_io *io;
if (dc->io_failed) {
return DM_MAPIO_KILL;
}
/* from dm-crypt.c */
if (unlikely(bio->bi_opf & REQ_PREFLUSH || bio_op(bio) == REQ_OP_DISCARD)) {
bio_set_dev(bio, dc->dev->bdev);

View File

@ -50,17 +50,16 @@ typedef enum {
} tristate_t;
int cbd_format(const char* dev,
uint64_t poff, uint64_t psize,
uint64_t lsize, uint16_t lshift);
uint64_t psize, uint16_t lshift, uint64_t lsize);
int cbd_open(const char* dev,
uint64_t loff, uint64_t lsize,
const char* name);
int cbd_close(const char* name);
int cbd_stats(const char* name);
int cbd_check(const char* dev, tristate_t auto_response);
int cbd_check(const char* dev,
tristate_t auto_response);
int cbd_resize(const char* dev,
uint64_t poff, uint64_t psize);
uint64_t lsize);
#endif

View File

@ -4,6 +4,9 @@
#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)

View File

@ -9,14 +9,14 @@ struct zone_metadata
};
static void
pblk_read(int fd, size_t pblk, size_t count, u8* data)
pblk_read(int fd, u64 pblk, u32 count, u8* data)
{
off_t off;
off_t pos;
size_t remain;
ssize_t ret;
off = lseek(fd, pblk * PBLK_SIZE, SEEK_SET);
if (off == (off_t)-1) {
pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET);
if (pos == (off_t)-1) {
error("Failed to seek\n");
}

View File

@ -3,14 +3,14 @@
#include <cbdutil.h>
static void
pblk_write(int fd, size_t pblk, size_t count, const u8* data)
pblk_write(int fd, u64 pblk, u32 count, const u8* data)
{
off_t off;
off_t pos;
size_t remain;
ssize_t ret;
off = lseek(fd, pblk * PBLK_SIZE, SEEK_SET);
if (off == (off_t)-1) {
pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET);
if (pos == (off_t)-1) {
error("Failed to seek\n");
}
@ -27,10 +27,10 @@ pblk_write(int fd, size_t pblk, size_t count, const u8* data)
int
cbd_format(const char* dev,
uint64_t poff, uint64_t psize,
uint64_t lsize, uint16_t lshift)
uint64_t psize, uint16_t lshift, uint64_t lsize)
{
int devfd;
uint32_t lblk_size;
struct cbd_header header;
uint8_t pblkbuf[PBLK_SIZE];
uint64_t pblk;
@ -42,23 +42,36 @@ cbd_format(const char* dev,
}
if (!psize) {
off_t len;
len = lseek(devfd, 0, SEEK_END);
if (len == (off_t)-1) {
off_t pos;
pos = lseek(devfd, 0, SEEK_END);
if (pos == (off_t)-1) {
error("Cannot seek device\n");
}
psize = len >> PBLK_SHIFT;
}
if (!lsize) {
lsize = psize * CBD_DEFAULT_COMPRESSION_FACTOR;
psize = pos / PBLK_SIZE * PBLK_SIZE;
}
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);
}
if (lsize % (1 << (lshift + PBLK_SHIFT))) {
error("Logical size %lu is not a multiple of %u bytes\n", (ulong)psize, (uint)lblk_size);
}
printf("%s: paramaters...\n", __func__);
printf(" poff=%lu psize=%lu\n", (unsigned long)poff, (unsigned long)psize);
printf(" lsize=%lu lshift=%hu\n", (unsigned long)lsize, (unsigned short)lshift);
printf(" psize=%lu\n", (unsigned long)psize);
printf(" lshift=%hu\n", (unsigned short)lshift);
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;
@ -66,12 +79,12 @@ cbd_format(const char* dev,
header.params.algorithm = CBD_ALG_LZ4;
header.params.compression = 1;
header.params.lblk_shift = lshift;
header.params.nr_pblk = psize;
header.params.nr_pblk = psize / PBLK_SIZE;
/* XXX: Initial estimate */
header.params.lblk_per_zone = zone_data_len(&header.params) * (lsize >> lshift) / psize;
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 - CBD_HEADER_BLOCKS) / zone_len(&header.params);
header.params.lblk_per_zone = DIV_ROUND_UP((lsize >> lshift), header.params.nr_zones);
header.params.nr_zones = ((psize >> PBLK_SHIFT) - 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(" lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift);
printf(" nr_pblk=%lu\n", (unsigned long)header.params.nr_pblk);
@ -81,7 +94,7 @@ cbd_format(const char* dev,
memset(pblkbuf, 0, sizeof(pblkbuf));
cbd_header_put(pblkbuf, &header);
pblk = poff;
pblk = 0;
pblk_write(devfd, pblk, 1, pblkbuf);
pblk += CBD_HEADER_BLOCKS;

View File

@ -10,6 +10,7 @@ device_logical_size(const char* dev)
int fd;
uint8_t pblkbuf[PBLK_SIZE];
struct cbd_header header;
uint64_t lblk_size;
fd = open(dev, O_RDONLY);
if (fd < 0) {
@ -18,18 +19,23 @@ device_logical_size(const char* dev)
if (read(fd, pblkbuf, sizeof(pblkbuf)) != sizeof(pblkbuf)) {
error("Cannot read device\n");
}
cbd_header_get(pblkbuf, &header);
close(fd);
cbd_header_get(pblkbuf, &header);
if (memcmp(header.magic, CBD_MAGIC, sizeof(header.magic)) != 0) {
error("Bad magic\n");
}
return (header.params.lblk_per_zone << header.params.lblk_shift) * header.params.nr_zones;
lblk_size = header.params.lblk_per_zone * header.params.nr_zones;
return (lblk_size << (header.params.lblk_shift + PBLK_SHIFT));
}
int
cbd_open(const char* dev,
uint64_t loff, uint64_t lsize,
const char* name)
{
int ret;
uint64_t lsize;
struct stat st;
struct dm_task* dmt;
uint32_t cookie = 0;
@ -41,10 +47,7 @@ cbd_open(const char* dev,
if (!S_ISBLK(st.st_mode)) {
error("Not a block device\n");
}
if (!lsize) {
lsize = device_logical_size(dev);
}
lsize = device_logical_size(dev);
dmt = dm_task_create(DM_DEVICE_CREATE);
if (!dmt) {
@ -54,12 +57,11 @@ cbd_open(const char* dev,
if (ret == 0) {
error("dm_task_set_name failed\n");
}
printf("%s: start_sector=%lu num_sectors=%lu\n", __func__,
(unsigned long)(loff * PBLK_PER_SECTOR),
(unsigned long)(lsize * PBLK_PER_SECTOR));
printf("%s: start_sector=0 num_sectors=%lu\n", __func__,
(unsigned long)(lsize / SECTOR_SIZE));
ret = dm_task_add_target(dmt,
loff * PBLK_PER_SECTOR,
lsize * PBLK_PER_SECTOR,
0,
lsize / SECTOR_SIZE,
"compress",
dev);
if (ret == 0) {

View File

@ -4,7 +4,7 @@
int
cbd_resize(const char* dev,
uint64_t poff, uint64_t psize)
uint64_t lsize)
{
error("Not implemented\n");