diff --git a/cbd/cbd.c b/cbd/cbd.c index aa0f80f..f0b47c3 100644 --- a/cbd/cbd.c +++ b/cbd/cbd.c @@ -84,7 +84,6 @@ usage(void) fprintf(stderr, "Commands:\n" " format [opts] 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] 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] 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 } diff --git a/dm-compress/dm-compress.c b/dm-compress/dm-compress.c index e5cea1a..bf2c011 100644 --- a/dm-compress/dm-compress.c +++ b/dm-compress/dm-compress.c @@ -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); diff --git a/include/libcbd.h b/include/libcbd.h index b782978..ae2efe5 100644 --- a/include/libcbd.h +++ b/include/libcbd.h @@ -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 diff --git a/include/linux/dm-compress.h b/include/linux/dm-compress.h index 0295be0..2608281 100644 --- a/include/linux/dm-compress.h +++ b/include/linux/dm-compress.h @@ -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) diff --git a/libcbd/check.c b/libcbd/check.c index 89b669c..01fac80 100644 --- a/libcbd/check.c +++ b/libcbd/check.c @@ -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"); } diff --git a/libcbd/format.c b/libcbd/format.c index a8b4b34..16dc430 100644 --- a/libcbd/format.c +++ b/libcbd/format.c @@ -3,14 +3,14 @@ #include 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; diff --git a/libcbd/open.c b/libcbd/open.c index aebd20b..9ea7ac5 100644 --- a/libcbd/open.c +++ b/libcbd/open.c @@ -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) { diff --git a/libcbd/resize.c b/libcbd/resize.c index 9d4bc95..0bc9586 100644 --- a/libcbd/resize.c +++ b/libcbd/resize.c @@ -4,7 +4,7 @@ int cbd_resize(const char* dev, - uint64_t poff, uint64_t psize) + uint64_t lsize) { error("Not implemented\n");