diff --git a/cbd/cbd.c b/cbd/cbd.c index b5d6cce..05ba5a9 100644 --- a/cbd/cbd.c +++ b/cbd/cbd.c @@ -85,6 +85,7 @@ usage(void) " 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" " -c --compress-factor Compression factor [2.0]\n" " -l --logical-shift Logical block shift [4]\n" " -s --size Logical size\n" @@ -100,6 +101,7 @@ usage(void) " create [opts] Alias for open\n" " close [opts] Close an opened compressed device\n" " check [opts] Check and repair a compressed device\n" + " -f --force Force check even if device seems clean\n" " -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" @@ -112,10 +114,11 @@ usage(void) static int do_format(int argc, char** argv) { - static const char short_opts[] = "S:L:c:l:s:z:Z:"; + static const char short_opts[] = "S:L:P:c:l: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' }, @@ -126,6 +129,7 @@ do_format(int argc, char** argv) char opt; uint64_t optval; uint64_t psize = 0; + uint16_t pbatlen = 1; uint16_t lshift = 0; uint64_t lsize = 0; enum cbd_alg alg = CBD_ALG_LZ4; @@ -150,6 +154,12 @@ do_format(int argc, char** argv) } 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; @@ -195,7 +205,7 @@ do_format(int argc, char** argv) } dev = argv[optind++]; - cbd_format(dev, psize, lshift, lsize, alg, level); + cbd_format(dev, psize, pbatlen, lshift, lsize, alg, level); return 0; } @@ -253,25 +263,23 @@ do_stats(int argc, char** argv) static int do_check(int argc, char** argv) { - static const char short_opts[] = "ny"; + static const char short_opts[] = "fny"; static const struct option long_opts[] = { + { "force", no_argument, NULL, 'f' }, { "assume-no", no_argument, NULL, 'n' }, { "assume-yes", no_argument, NULL, 'y' }, { NULL, no_argument, NULL, 0 } }; char opt; + bool force = false; tristate_t auto_response = t_none; const char* dev; while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { switch (opt) { - case 'y': - if (auto_response == t_false) { - fprintf(stderr, "Cannot specify both -y and -n\n"); - usage(); - } - auto_response = t_true; + case 'f': + force = true; break; case 'n': if (auto_response == t_true) { @@ -280,6 +288,13 @@ do_check(int argc, char** argv) } auto_response = t_false; break; + case 'y': + if (auto_response == t_false) { + fprintf(stderr, "Cannot specify both -y and -n\n"); + usage(); + } + auto_response = t_true; + break; default: usage(); } @@ -289,7 +304,7 @@ do_check(int argc, char** argv) } dev = argv[optind++]; - cbd_check(dev, auto_response); + cbd_check(dev, force, auto_response); return 0; } diff --git a/dm-compress/compress.c b/dm-compress/compress.c index 35f8ad9..ccab4c2 100644 --- a/dm-compress/compress.c +++ b/dm-compress/compress.c @@ -162,6 +162,36 @@ out: return ret; } +static int +compress_write_header(struct compress* c) +{ + int ret = 0; + struct page* pblkpage; + u8* pblkbuf; + struct cbd_header header; + struct page* iopagev[1]; + + pblkpage = cbd_alloc_page(); + if (!pblkpage) { + return -ENOMEM; + } + pblkbuf = page_address(pblkpage); + 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; + memcpy(&header.params, &c->params, sizeof(header.params)); + cbd_header_put(pblkbuf, &header); + iopagev[0] = pblkpage; + ret = pblk_write_wait(c->params.priv, 0, 1, iopagev); + if (ret) { + printk(KERN_ERR "%s: failed to write header\n", __func__); + } + cbd_free_page(pblkpage); + + return ret; +} + static struct lbd* compress_lbdcache_swap(struct compress* c, u64 lblk, struct lbd* oldlbd) { @@ -365,6 +395,18 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv) if (ret) { goto err; } + if (c->params.flags & CBD_FLAG_DIRTY) { + printk(KERN_INFO "Warning: device was not properly closed\n"); + } + if (dm_table_get_mode(ti->table) & FMODE_WRITE) { + u16 save_flags = c->params.flags; + c->params.flags |= CBD_FLAG_DIRTY; + ret = compress_write_header(c); + c->params.flags = save_flags; + if (ret) { + goto err; + } + } /* XXX: validate minumum pblk using zone_off(max_zone+1) */ if (c->params.nr_pblk > dev_nr_pblks) { @@ -413,11 +455,19 @@ err: static void compress_dtr(struct dm_target *ti) { + int ret; struct compress *c; printk(KERN_INFO "%s: enter\n", __func__); c = ti->private; + + if (dm_table_get_mode(ti->table) & FMODE_WRITE) { + ret = compress_write_header(c); + if (ret) { + printk(KERN_INFO "Warning: failed to write header\n"); + } + } lbdcache_dtr(c->lc); kfree(c->lc); if (c->io_workq) { diff --git a/dm-compress/util.c b/dm-compress/util.c index df940ea..0f3a16e 100644 --- a/dm-compress/util.c +++ b/dm-compress/util.c @@ -144,23 +144,19 @@ pblk_read_wait(struct block_device* bdev, } int -pblk_read(struct block_device* bdev, - u64 pblk, u32 count, struct page** pagev, - pblk_endio_t endio, void* endio_priv) +pblk_write_wait(struct block_device* bdev, + u64 pblk, u32 count, struct page** pagev) { int ret; struct bio* bio; - bio = pblk_io_prepare(bdev, REQ_OP_READ, pblk, count, pagev); + bio = pblk_io_prepare(bdev, REQ_OP_WRITE, pblk, count, pagev); if (!bio) { printk(KERN_ERR "%s: out of memory\n", __func__); return -ENOMEM; } - bio->bi_end_io = endio; - bio->bi_private = endio_priv; - - ret = submit_bio(bio); - if (ret != 0) { + ret = submit_bio_wait(bio); + if (ret) { printk(KERN_ERR "%s: submit_bio_wait failed: %d\n", __func__, ret); } bio_put(bio); diff --git a/include/libcbd.h b/include/libcbd.h index 10291aa..42377b0 100644 --- a/include/libcbd.h +++ b/include/libcbd.h @@ -4,6 +4,7 @@ /* Kernel compatibility */ #include #include +#include #include #ifndef BITS_PER_BYTE @@ -60,6 +61,7 @@ int cbd_close(const char* name); int cbd_stats(const char* name); int cbd_check(const char* dev, + bool force, tristate_t auto_response); int cbd_resize(const char* dev, uint64_t lsize); diff --git a/include/linux/dm-compress.h b/include/linux/dm-compress.h index bdcde2f..2d5ad94 100644 --- a/include/linux/dm-compress.h +++ b/include/linux/dm-compress.h @@ -28,6 +28,8 @@ static const u8 CBD_MAGIC[] = { 'C', 'B', 'D', '\0' }; static const u16 CBD_VERSION_MAJOR = 1; static const u16 CBD_VERSION_MINOR = 1; +#define CBD_FLAG_DIRTY 0x01 + enum cbd_alg { CBD_ALG_NONE, CBD_ALG_LZ4, @@ -37,6 +39,7 @@ enum cbd_alg { }; struct cbd_params { + u16 flags; u8 algorithm; /* enum cbd_alg */ u8 compression; /* 0..9 */ u16 pbat_len; @@ -295,6 +298,7 @@ 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); @@ -310,6 +314,7 @@ 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); @@ -471,9 +476,8 @@ void cbd_free_pagev(struct page** pagev, size_t len); /* Core low-level I/O */ int pblk_read_wait(struct block_device* bdev, u64 pblk, u32 count, struct page** pagev); -int pblk_read(struct block_device* bdev, - u64 pblk, u32 count, struct page** pagev, - pblk_endio_t endio, void* endio_priv); +int pblk_write_wait(struct block_device* bdev, + u64 pblk, u32 count, struct page** pagev); void pblk_write(struct block_device* bdev, u64 pblk, u32 count, struct page** pagev); diff --git a/libcbd/check.c b/libcbd/check.c index e2cd1b2..16c472b 100644 --- a/libcbd/check.c +++ b/libcbd/check.c @@ -184,6 +184,7 @@ check_zone_metadata(const struct cbd_params* params, int cbd_check(const char* dev, + bool force, tristate_t auto_response) { int devfd; @@ -200,6 +201,11 @@ cbd_check(const char* dev, pblk_read(devfd, 0, 1, pblkbuf); cbd_header_get(pblkbuf, &header); check_header(&header); + if (!force && !(header.params.flags & CBD_FLAG_DIRTY)) { + printf("%s: clean\n", dev); + close(devfd); + return 0; + } zmvec = calloc(header.params.nr_zones, sizeof(struct zone_metadata)); for (zone = 0; zone < header.params.nr_zones; ++zone) { @@ -223,5 +229,7 @@ cbd_check(const char* dev, } free(zmvec); + close(devfd); + return 0; } diff --git a/libcbd/format.c b/libcbd/format.c index 8c4224b..2f79c8a 100644 --- a/libcbd/format.c +++ b/libcbd/format.c @@ -88,6 +88,7 @@ cbd_format(const char* dev, 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;