Make cbd check actually do a check and do some cleanup
* cbd check now works (ish). * Added full-check arg to cbd check, link with liblz4, libz. * Added libcbd/util.c with goodies like verbose, ask_user_bool. * Rework kernel side params, stats to separate from user space. * Lock kernel stats when updating. * Add lblk_used to stats. ... and probably some other forgotten things.
This commit is contained in:
parent
d43a37531f
commit
ceb0eb3230
5
Makefile
5
Makefile
|
@ -80,7 +80,8 @@ LIB_SRCS := \
|
||||||
format.c \
|
format.c \
|
||||||
open.c \
|
open.c \
|
||||||
resize.c \
|
resize.c \
|
||||||
stats.c
|
stats.c \
|
||||||
|
util.c
|
||||||
BIN_SRCS := \
|
BIN_SRCS := \
|
||||||
cbd.c
|
cbd.c
|
||||||
KMOD_SRCS := \
|
KMOD_SRCS := \
|
||||||
|
@ -98,7 +99,7 @@ LIB_OBJDIR := $(OUT_OBJ)/$(LIB_NAME)
|
||||||
LIB_OBJS := $(addprefix $(LIB_OBJDIR)/,$(LIB_SRCS:.c=$(OBJ_EXT)))
|
LIB_OBJS := $(addprefix $(LIB_OBJDIR)/,$(LIB_SRCS:.c=$(OBJ_EXT)))
|
||||||
BIN_OBJDIR := $(OUT_OBJ)/$(BIN_NAME)
|
BIN_OBJDIR := $(OUT_OBJ)/$(BIN_NAME)
|
||||||
BIN_OBJS := $(addprefix $(BIN_OBJDIR)/,$(BIN_SRCS:.c=$(OBJ_EXT)))
|
BIN_OBJS := $(addprefix $(BIN_OBJDIR)/,$(BIN_SRCS:.c=$(OBJ_EXT)))
|
||||||
EXE_LIBS := -ldevmapper
|
EXE_LIBS := -ldevmapper -llz4 -lz
|
||||||
KMOD_OBJDIR := $(OUT_OBJ)/$(KMOD_NAME)
|
KMOD_OBJDIR := $(OUT_OBJ)/$(KMOD_NAME)
|
||||||
|
|
||||||
# Transforms
|
# Transforms
|
||||||
|
|
14
cbd/cbd.c
14
cbd/cbd.c
|
@ -102,6 +102,7 @@ usage(void)
|
||||||
" close [opts] <name> Close an opened compressed device\n"
|
" close [opts] <name> Close an opened compressed device\n"
|
||||||
" check [opts] <device> Check and repair a compressed device\n"
|
" check [opts] <device> Check and repair a compressed device\n"
|
||||||
" -f --force Force check even if device seems clean\n"
|
" -f --force Force check even if device seems clean\n"
|
||||||
|
" -F --full-check Do a full check, including verifying data\n"
|
||||||
" -n --assume-no Assume \"no\" no all questions\n"
|
" -n --assume-no Assume \"no\" no all questions\n"
|
||||||
" -y --assume-yes Assume \"yes\" to all questions\n"
|
" -y --assume-yes Assume \"yes\" to all questions\n"
|
||||||
" resize [opts] <device> Resize an existing compressed device\n"
|
" resize [opts] <device> Resize an existing compressed device\n"
|
||||||
|
@ -266,15 +267,17 @@ do_stats(int argc, char** argv)
|
||||||
static int
|
static int
|
||||||
do_check(int argc, char** argv)
|
do_check(int argc, char** argv)
|
||||||
{
|
{
|
||||||
static const char short_opts[] = "fny";
|
static const char short_opts[] = "fFny";
|
||||||
static const struct option long_opts[] = {
|
static const struct option long_opts[] = {
|
||||||
{ "force", no_argument, NULL, 'f' },
|
{ "force", no_argument, NULL, 'f' },
|
||||||
|
{ "full-check", no_argument, NULL, 'F' },
|
||||||
{ "assume-no", no_argument, NULL, 'n' },
|
{ "assume-no", no_argument, NULL, 'n' },
|
||||||
{ "assume-yes", no_argument, NULL, 'y' },
|
{ "assume-yes", no_argument, NULL, 'y' },
|
||||||
{ NULL, no_argument, NULL, 0 }
|
{ NULL, no_argument, NULL, 0 }
|
||||||
};
|
};
|
||||||
char opt;
|
char opt;
|
||||||
bool force = false;
|
bool force = false;
|
||||||
|
bool full_check = false;
|
||||||
tristate_t auto_response = t_none;
|
tristate_t auto_response = t_none;
|
||||||
|
|
||||||
const char* dev;
|
const char* dev;
|
||||||
|
@ -284,6 +287,9 @@ do_check(int argc, char** argv)
|
||||||
case 'f':
|
case 'f':
|
||||||
force = true;
|
force = true;
|
||||||
break;
|
break;
|
||||||
|
case 'F':
|
||||||
|
full_check = true;
|
||||||
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
if (auto_response == t_true) {
|
if (auto_response == t_true) {
|
||||||
fprintf(stderr, "Cannot specify both -y and -n\n");
|
fprintf(stderr, "Cannot specify both -y and -n\n");
|
||||||
|
@ -307,7 +313,7 @@ do_check(int argc, char** argv)
|
||||||
}
|
}
|
||||||
dev = argv[optind++];
|
dev = argv[optind++];
|
||||||
|
|
||||||
cbd_check(dev, force, auto_response);
|
cbd_check(dev, force, auto_response, full_check);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -379,13 +385,15 @@ main(int argc, char** argv)
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
char opt;
|
char opt;
|
||||||
int verbose_level = 0; /* XXX: make global or ...? */
|
|
||||||
|
|
||||||
const char* cmd;
|
const char* cmd;
|
||||||
uint n;
|
uint n;
|
||||||
|
|
||||||
progname = argv[0];
|
progname = argv[0];
|
||||||
|
|
||||||
|
/* Disable stdout buffering. */
|
||||||
|
setbuf(stdout, NULL);
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
|
while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'v':
|
case 'v':
|
||||||
|
|
|
@ -52,8 +52,8 @@ struct compress
|
||||||
{
|
{
|
||||||
struct dm_dev* dev;
|
struct dm_dev* dev;
|
||||||
|
|
||||||
struct cbd_params params;
|
struct compress_params kparams;
|
||||||
struct cbd_stats stats;
|
struct compress_stats kstats;
|
||||||
struct lbdcache* lc;
|
struct lbdcache* lc;
|
||||||
|
|
||||||
struct workqueue_struct* io_workq;
|
struct workqueue_struct* io_workq;
|
||||||
|
@ -91,15 +91,14 @@ compress_read_header(struct compress* c)
|
||||||
pblkbuf = page_address(pblkpage);
|
pblkbuf = page_address(pblkpage);
|
||||||
iopagev[0] = pblkpage;
|
iopagev[0] = pblkpage;
|
||||||
|
|
||||||
header.params.priv = c->dev->bdev;
|
c->kparams.dev = c->dev->bdev;
|
||||||
ret = pblk_read_wait(&header.params, 0, 1, iopagev);
|
ret = pblk_read_wait(&c->kparams, 0, 1, iopagev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: failed to read header\n", __func__);
|
printk(KERN_ERR "%s: failed to read header\n", __func__);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
cbd_header_get(pblkbuf, &header);
|
cbd_header_get(pblkbuf, &header);
|
||||||
header.params.priv = c->dev->bdev;
|
|
||||||
|
|
||||||
if (memcmp(header.magic, CBD_MAGIC, sizeof(header.magic)) != 0) {
|
if (memcmp(header.magic, CBD_MAGIC, sizeof(header.magic)) != 0) {
|
||||||
printk(KERN_ERR "%s: bad magic\n", __func__);
|
printk(KERN_ERR "%s: bad magic\n", __func__);
|
||||||
|
@ -157,8 +156,8 @@ compress_read_header(struct compress* c)
|
||||||
printk(KERN_INFO " nr_zones=%u\n", (unsigned int)header.params.nr_zones);
|
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 " lblk_per_zone=%u\n", (unsigned int)header.params.lblk_per_zone);
|
||||||
|
|
||||||
memcpy(&c->params, &header.params, sizeof(header.params));
|
memcpy(&c->kparams.params, &header.params, sizeof(header.params));
|
||||||
memcpy(&c->stats, &header.stats, sizeof(header.stats));
|
memcpy(&c->kstats.stats, &header.stats, sizeof(header.stats));
|
||||||
|
|
||||||
out:
|
out:
|
||||||
cbd_free_page(pblkpage);
|
cbd_free_page(pblkpage);
|
||||||
|
@ -183,11 +182,11 @@ compress_write_header(struct compress* c)
|
||||||
memcpy(header.magic, CBD_MAGIC, sizeof(header.magic));
|
memcpy(header.magic, CBD_MAGIC, sizeof(header.magic));
|
||||||
header.version_major = CBD_VERSION_MAJOR;
|
header.version_major = CBD_VERSION_MAJOR;
|
||||||
header.version_minor = CBD_VERSION_MINOR;
|
header.version_minor = CBD_VERSION_MINOR;
|
||||||
memcpy(&header.params, &c->params, sizeof(header.params));
|
memcpy(&header.params, &c->kparams.params, sizeof(header.params));
|
||||||
memcpy(&header.stats, &c->stats, sizeof(header.stats));
|
memcpy(&header.stats, &c->kstats.stats, sizeof(header.stats));
|
||||||
cbd_header_put(pblkbuf, &header);
|
cbd_header_put(pblkbuf, &header);
|
||||||
iopagev[0] = pblkpage;
|
iopagev[0] = pblkpage;
|
||||||
ret = pblk_write_wait(&c->params, 0, 1, iopagev);
|
ret = pblk_write_wait(&c->kparams, 0, 1, iopagev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: failed to write header\n", __func__);
|
printk(KERN_ERR "%s: failed to write header\n", __func__);
|
||||||
}
|
}
|
||||||
|
@ -202,7 +201,7 @@ compress_read(struct compress *c, struct bio *bio)
|
||||||
struct lbd* lbd = NULL;
|
struct lbd* lbd = NULL;
|
||||||
struct bio_vec bv;
|
struct bio_vec bv;
|
||||||
struct bvec_iter iter;
|
struct bvec_iter iter;
|
||||||
u32 lblk_per_sector = lblk_per_pblk(&c->params) * PBLK_PER_SECTOR;
|
u32 lblk_per_sector = lblk_per_pblk(&c->kparams.params) * PBLK_PER_SECTOR;
|
||||||
|
|
||||||
bio_for_each_segment(bv, bio, iter) {
|
bio_for_each_segment(bv, bio, iter) {
|
||||||
u64 lblk = iter.bi_sector / lblk_per_sector;
|
u64 lblk = iter.bi_sector / lblk_per_sector;
|
||||||
|
@ -229,7 +228,7 @@ compress_write(struct compress *c, struct bio *bio)
|
||||||
struct lbd* lbd = NULL;
|
struct lbd* lbd = NULL;
|
||||||
struct bio_vec bv;
|
struct bio_vec bv;
|
||||||
struct bvec_iter iter;
|
struct bvec_iter iter;
|
||||||
u32 lblk_per_sector = lblk_per_pblk(&c->params) * PBLK_PER_SECTOR;
|
u32 lblk_per_sector = lblk_per_pblk(&c->kparams.params) * PBLK_PER_SECTOR;
|
||||||
|
|
||||||
bio_for_each_segment(bv, bio, iter) {
|
bio_for_each_segment(bv, bio, iter) {
|
||||||
u64 lblk = iter.bi_sector / lblk_per_sector;
|
u64 lblk = iter.bi_sector / lblk_per_sector;
|
||||||
|
@ -388,27 +387,27 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||||
if (ret) {
|
if (ret) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (c->params.flags & CBD_FLAG_DIRTY) {
|
if (c->kparams.params.flags & CBD_FLAG_DIRTY) {
|
||||||
printk(KERN_INFO "Warning: device was not properly closed\n");
|
printk(KERN_INFO "Warning: device was not properly closed\n");
|
||||||
}
|
}
|
||||||
if (dm_table_get_mode(ti->table) & FMODE_WRITE) {
|
if (dm_table_get_mode(ti->table) & FMODE_WRITE) {
|
||||||
u16 save_flags = c->params.flags;
|
u16 save_flags = c->kparams.params.flags;
|
||||||
c->params.flags |= CBD_FLAG_DIRTY;
|
c->kparams.params.flags |= CBD_FLAG_DIRTY;
|
||||||
ret = compress_write_header(c);
|
ret = compress_write_header(c);
|
||||||
c->params.flags = save_flags;
|
c->kparams.params.flags = save_flags;
|
||||||
if (ret) {
|
if (ret) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: validate minumum pblk using zone_off(max_zone+1) */
|
/* XXX: validate minumum pblk using zone_off(max_zone+1) */
|
||||||
if (c->params.nr_pblk > backing_nr_pblks) {
|
if (c->kparams.params.nr_pblk > backing_nr_pblks) {
|
||||||
printk(KERN_ERR "%s: bad nr_pblk\n", __func__);
|
printk(KERN_ERR "%s: bad nr_pblk\n", __func__);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->params.nr_zones > zone_for_pblk(&c->params, backing_nr_pblks)) {
|
if (c->kparams.params.nr_zones > zone_for_pblk(&c->kparams.params, backing_nr_pblks)) {
|
||||||
printk(KERN_ERR "%s: bad nr_zones\n", __func__);
|
printk(KERN_ERR "%s: bad nr_zones\n", __func__);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -422,7 +421,7 @@ compress_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (!lbdcache_ctr(c->lc, &c->params, &c->stats, cache_pages)) {
|
if (!lbdcache_ctr(c->lc, &c->kparams, &c->kstats, cache_pages)) {
|
||||||
printk(KERN_ERR "Failed to init logical block cache\n");
|
printk(KERN_ERR "Failed to init logical block cache\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -476,7 +475,7 @@ compress_map(struct dm_target *ti, struct bio *bio)
|
||||||
struct compress *c = ti->private;
|
struct compress *c = ti->private;
|
||||||
struct compress_io *cio;
|
struct compress_io *cio;
|
||||||
|
|
||||||
if (c->params.flags & CBD_FLAG_ERROR) {
|
if (c->kparams.params.flags & CBD_FLAG_ERROR) {
|
||||||
bio->bi_status = BLK_STS_IOERR;
|
bio->bi_status = BLK_STS_IOERR;
|
||||||
bio_endio(bio);
|
bio_endio(bio);
|
||||||
return DM_MAPIO_SUBMITTED; /* XXXX: DM_MAPIO_KILL? */
|
return DM_MAPIO_SUBMITTED; /* XXXX: DM_MAPIO_KILL? */
|
||||||
|
|
|
@ -36,14 +36,14 @@ struct lbatpage {
|
||||||
unsigned int ref;
|
unsigned int ref;
|
||||||
|
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct cbd_params* params;
|
struct compress_params* kparams;
|
||||||
struct page* page;
|
struct page* page;
|
||||||
u8* buf;
|
u8* buf;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
lbatpage_ctr(struct lbatpage* lp, struct cbd_params* params)
|
lbatpage_ctr(struct lbatpage* lp, struct compress_params* kparams)
|
||||||
{
|
{
|
||||||
memset(lp, 0, sizeof(struct lbatpage));
|
memset(lp, 0, sizeof(struct lbatpage));
|
||||||
INIT_LIST_HEAD(&lp->list);
|
INIT_LIST_HEAD(&lp->list);
|
||||||
|
@ -51,7 +51,7 @@ lbatpage_ctr(struct lbatpage* lp, struct cbd_params* params)
|
||||||
mutex_init(&lp->reflock);
|
mutex_init(&lp->reflock);
|
||||||
lp->ref = 0;
|
lp->ref = 0;
|
||||||
mutex_init(&lp->lock);
|
mutex_init(&lp->lock);
|
||||||
lp->params = params;
|
lp->kparams = kparams;
|
||||||
lp->page = cbd_alloc_page();
|
lp->page = cbd_alloc_page();
|
||||||
if (!lp->page) {
|
if (!lp->page) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -91,7 +91,7 @@ lbatpage_flush(struct lbatpage* lp)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
iopagev[0] = lp->page;
|
iopagev[0] = lp->page;
|
||||||
pblk_write(lp->params, lp->pblk, 1, iopagev);
|
pblk_write(lp->kparams, lp->pblk, 1, iopagev);
|
||||||
mutex_unlock(&lp->lock);
|
mutex_unlock(&lp->lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -110,7 +110,7 @@ lbatpage_read(struct lbatpage* lp)
|
||||||
struct page* pagev[1];
|
struct page* pagev[1];
|
||||||
|
|
||||||
pagev[0] = lp->page;
|
pagev[0] = lp->page;
|
||||||
ret = pblk_read_wait(lp->params, lp->pblk, 1, pagev);
|
ret = pblk_read_wait(lp->kparams, lp->pblk, 1, pagev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,6 @@ lbatpage_put_buf(struct lbatpage* lp)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lbatpagecache {
|
struct lbatpagecache {
|
||||||
struct cbd_params* params;
|
|
||||||
struct mutex cache_lock;
|
struct mutex cache_lock;
|
||||||
struct list_head cache_head;
|
struct list_head cache_head;
|
||||||
unsigned int cache_len;
|
unsigned int cache_len;
|
||||||
|
@ -167,14 +166,13 @@ lbatpagecache_size(void)
|
||||||
|
|
||||||
bool
|
bool
|
||||||
lbatpagecache_ctr(struct lbatpagecache* lpc,
|
lbatpagecache_ctr(struct lbatpagecache* lpc,
|
||||||
struct cbd_params* params, u32 cache_pages)
|
struct compress_params* kparams, u32 cache_pages)
|
||||||
{
|
{
|
||||||
struct lbatpage* cache;
|
struct lbatpage* cache;
|
||||||
u32 cache_len;
|
u32 cache_len;
|
||||||
u32 n;
|
u32 n;
|
||||||
|
|
||||||
memset(lpc, 0, sizeof(struct lbatpagecache));
|
memset(lpc, 0, sizeof(struct lbatpagecache));
|
||||||
lpc->params = params;
|
|
||||||
|
|
||||||
/* lbatpagecache gets 15/32 of cache pages */
|
/* lbatpagecache gets 15/32 of cache pages */
|
||||||
cache_len = (cache_pages * 15 / 32);
|
cache_len = (cache_pages * 15 / 32);
|
||||||
|
@ -192,7 +190,7 @@ lbatpagecache_ctr(struct lbatpagecache* lpc,
|
||||||
lpc->cache_len = cache_len;
|
lpc->cache_len = cache_len;
|
||||||
lpc->cache = cache;
|
lpc->cache = cache;
|
||||||
for (n = 0; n < cache_len; ++n) {
|
for (n = 0; n < cache_len; ++n) {
|
||||||
if (!lbatpage_ctr(&cache[n], lpc->params)) {
|
if (!lbatpage_ctr(&cache[n], kparams)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
list_add_tail(&cache[n].list, &lpc->cache_head);
|
list_add_tail(&cache[n].list, &lpc->cache_head);
|
||||||
|
@ -221,7 +219,6 @@ lbatpagecache_dtr(struct lbatpagecache* lpc)
|
||||||
lpc->cache = NULL;
|
lpc->cache = NULL;
|
||||||
lpc->cache_len = 0;
|
lpc->cache_len = 0;
|
||||||
INIT_LIST_HEAD(&lpc->cache_head);
|
INIT_LIST_HEAD(&lpc->cache_head);
|
||||||
lpc->params = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lbatpage*
|
struct lbatpage*
|
||||||
|
|
|
@ -36,17 +36,19 @@ struct lbatview {
|
||||||
unsigned int ref;
|
unsigned int ref;
|
||||||
|
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct cbd_params* params;
|
struct compress_params* kparams;
|
||||||
struct pbatcache* pbatcache;
|
struct compress_stats* kstats;
|
||||||
struct pbat* pbat;
|
struct pbatcache* pc;
|
||||||
struct lbatpagecache* lpc;
|
struct lbatpagecache* lpc;
|
||||||
|
struct pbat* pbat;
|
||||||
struct lbatpage* pages[2];
|
struct lbatpage* pages[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
lbatview_ctr(struct lbatview* lv,
|
lbatview_ctr(struct lbatview* lv,
|
||||||
struct cbd_params* params,
|
struct compress_params* kparams,
|
||||||
struct pbatcache* pbatcache,
|
struct compress_stats* kstats,
|
||||||
|
struct pbatcache* pc,
|
||||||
struct lbatpagecache* lpc)
|
struct lbatpagecache* lpc)
|
||||||
{
|
{
|
||||||
memset(lv, 0, sizeof(struct lbatview));
|
memset(lv, 0, sizeof(struct lbatview));
|
||||||
|
@ -55,10 +57,11 @@ lbatview_ctr(struct lbatview* lv,
|
||||||
mutex_init(&lv->reflock);
|
mutex_init(&lv->reflock);
|
||||||
lv->ref = 0;
|
lv->ref = 0;
|
||||||
mutex_init(&lv->lock);
|
mutex_init(&lv->lock);
|
||||||
lv->params = params;
|
lv->kparams = kparams;
|
||||||
lv->pbatcache = pbatcache;
|
lv->kstats = kstats;
|
||||||
lv->pbat = NULL;
|
lv->pc = pc;
|
||||||
lv->lpc = lpc;
|
lv->lpc = lpc;
|
||||||
|
lv->pbat = NULL;
|
||||||
lv->pages[0] = lv->pages[1] = NULL;
|
lv->pages[0] = lv->pages[1] = NULL;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -67,13 +70,14 @@ lbatview_ctr(struct lbatview* lv,
|
||||||
static void
|
static void
|
||||||
lbatview_dtr(struct lbatview* lv)
|
lbatview_dtr(struct lbatview* lv)
|
||||||
{
|
{
|
||||||
pbatcache_put(lv->pbatcache, lv->pbat);
|
|
||||||
lv->pbat = NULL;
|
|
||||||
lbatpagecache_put(lv->lpc, lv->pages[1]);
|
lbatpagecache_put(lv->lpc, lv->pages[1]);
|
||||||
lv->pages[1] = NULL;
|
lv->pages[1] = NULL;
|
||||||
lbatpagecache_put(lv->lpc, lv->pages[0]);
|
lbatpagecache_put(lv->lpc, lv->pages[0]);
|
||||||
lv->pages[0] = NULL;
|
lv->pages[0] = NULL;
|
||||||
|
pbatcache_put(lv->pc, lv->pbat);
|
||||||
|
lv->pbat = NULL;
|
||||||
lv->lpc = NULL;
|
lv->lpc = NULL;
|
||||||
|
lv->pc = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -97,7 +101,7 @@ lbatview_flush(struct lbatview* lv)
|
||||||
}
|
}
|
||||||
lv->pages[0] = NULL;
|
lv->pages[0] = NULL;
|
||||||
}
|
}
|
||||||
err = pbatcache_put(lv->pbatcache, lv->pbat);
|
err = pbatcache_put(lv->pc, lv->pbat);
|
||||||
lv->pbat = NULL;
|
lv->pbat = NULL;
|
||||||
if (err) {
|
if (err) {
|
||||||
ret = err;
|
ret = err;
|
||||||
|
@ -144,7 +148,7 @@ static u64
|
||||||
lbatview_alloc_pblk(struct lbatview* lv)
|
lbatview_alloc_pblk(struct lbatview* lv)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 zone = zone_for_pblk(lv->params, lv->pblk);
|
u32 zone = zone_for_pblk(&lv->kparams->params, lv->pblk);
|
||||||
u64 pblk;
|
u64 pblk;
|
||||||
u32 zone_off;
|
u32 zone_off;
|
||||||
struct pbat* pbat;
|
struct pbat* pbat;
|
||||||
|
@ -154,53 +158,53 @@ lbatview_alloc_pblk(struct lbatview* lv)
|
||||||
if (pblk != PBLK_NONE) {
|
if (pblk != PBLK_NONE) {
|
||||||
return pblk;
|
return pblk;
|
||||||
}
|
}
|
||||||
ret = pbatcache_put(lv->pbatcache, lv->pbat);
|
ret = pbatcache_put(lv->pc, lv->pbat);
|
||||||
lv->pbat = NULL;
|
lv->pbat = NULL;
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
||||||
return PBLK_NONE;
|
return PBLK_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pbat = pbatcache_get(lv->pbatcache, zone, true);
|
pbat = pbatcache_get(lv->pc, zone, true);
|
||||||
if (pbat) {
|
if (pbat) {
|
||||||
pblk = pbat_alloc(pbat);
|
pblk = pbat_alloc(pbat);
|
||||||
if (pblk != PBLK_NONE) {
|
if (pblk != PBLK_NONE) {
|
||||||
lv->pbat = pbat;
|
lv->pbat = pbat;
|
||||||
return pblk;
|
return pblk;
|
||||||
}
|
}
|
||||||
ret = pbatcache_put(lv->pbatcache, pbat);
|
ret = pbatcache_put(lv->pc, pbat);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
||||||
return PBLK_NONE;
|
return PBLK_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (zone_off = 1;
|
for (zone_off = 1;
|
||||||
zone_off <= zone || zone + zone_off < lv->params->nr_zones;
|
zone_off <= zone || zone + zone_off < lv->kparams->params.nr_zones;
|
||||||
++zone_off) {
|
++zone_off) {
|
||||||
if (zone_off <= zone) {
|
if (zone_off <= zone) {
|
||||||
pbat = pbatcache_get(lv->pbatcache, zone - zone_off, true);
|
pbat = pbatcache_get(lv->pc, zone - zone_off, true);
|
||||||
if (pbat) {
|
if (pbat) {
|
||||||
pblk = pbat_alloc(pbat);
|
pblk = pbat_alloc(pbat);
|
||||||
if (pblk != PBLK_NONE) {
|
if (pblk != PBLK_NONE) {
|
||||||
lv->pbat = pbat;
|
lv->pbat = pbat;
|
||||||
return pblk;
|
return pblk;
|
||||||
}
|
}
|
||||||
ret = pbatcache_put(lv->pbatcache, pbat);
|
ret = pbatcache_put(lv->pc, pbat);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
||||||
return PBLK_NONE;
|
return PBLK_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (zone + zone_off < lv->params->nr_zones) {
|
if (zone + zone_off < lv->kparams->params.nr_zones) {
|
||||||
pbat = pbatcache_get(lv->pbatcache, zone + zone_off, true);
|
pbat = pbatcache_get(lv->pc, zone + zone_off, true);
|
||||||
if (pbat) {
|
if (pbat) {
|
||||||
pblk = pbat_alloc(pbat);
|
pblk = pbat_alloc(pbat);
|
||||||
if (pblk != PBLK_NONE) {
|
if (pblk != PBLK_NONE) {
|
||||||
lv->pbat = pbat;
|
lv->pbat = pbat;
|
||||||
return pblk;
|
return pblk;
|
||||||
}
|
}
|
||||||
ret = pbatcache_put(lv->pbatcache, pbat);
|
ret = pbatcache_put(lv->pc, pbat);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
||||||
return PBLK_NONE;
|
return PBLK_NONE;
|
||||||
|
@ -217,16 +221,16 @@ static int
|
||||||
lbatview_free_pblk(struct lbatview* lv, u64 pblk)
|
lbatview_free_pblk(struct lbatview* lv, u64 pblk)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 zone = zone_for_pblk(lv->params, lv->pblk);
|
u32 zone = zone_for_pblk(&lv->kparams->params, lv->pblk);
|
||||||
u32 pblk_zone;
|
u32 pblk_zone;
|
||||||
struct pbat* pbat;
|
struct pbat* pbat;
|
||||||
|
|
||||||
pblk_zone = zone_for_pblk(lv->params, pblk);
|
pblk_zone = zone_for_pblk(&lv->kparams->params, pblk);
|
||||||
if (pblk_zone == ZONE_NONE || pblk_zone >= lv->params->nr_zones) {
|
if (pblk_zone == ZONE_NONE || pblk_zone >= lv->kparams->params.nr_zones) {
|
||||||
printk(KERN_ERR "%s: pblk=%lu: zone out of bounds\n", __func__, (unsigned long)pblk);
|
printk(KERN_ERR "%s: pblk=%lu: zone out of bounds\n", __func__, (unsigned long)pblk);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
pbat = pbatcache_get(lv->pbatcache, pblk_zone, false);
|
pbat = pbatcache_get(lv->pc, pblk_zone, false);
|
||||||
if (!pbat) {
|
if (!pbat) {
|
||||||
printk(KERN_ERR "%s: pbatcache_get failed\n", __func__);
|
printk(KERN_ERR "%s: pbatcache_get failed\n", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -235,14 +239,14 @@ lbatview_free_pblk(struct lbatview* lv, u64 pblk)
|
||||||
BUG_ON(ret != 0);
|
BUG_ON(ret != 0);
|
||||||
if (lv->pbat && pbat_zone(lv->pbat) != zone && pblk_zone == zone) {
|
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);
|
printk(KERN_INFO "%s: freed block %lu in zone %u switching back\n", __func__, (unsigned long)pblk, zone);
|
||||||
ret = pbatcache_put(lv->pbatcache, lv->pbat);
|
ret = pbatcache_put(lv->pc, lv->pbat);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
||||||
}
|
}
|
||||||
lv->pbat = pbat;
|
lv->pbat = pbat;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ret = pbatcache_put(lv->pbatcache, pbat);
|
ret = pbatcache_put(lv->pc, pbat);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
printk(KERN_ERR "%s: pbatcache_put failed\n", __func__);
|
||||||
}
|
}
|
||||||
|
@ -254,13 +258,13 @@ lbatview_free_pblk(struct lbatview* lv, u64 pblk)
|
||||||
static u32
|
static u32
|
||||||
lbatview_elem_off(struct lbatview* lv, u64 lblk)
|
lbatview_elem_off(struct lbatview* lv, u64 lblk)
|
||||||
{
|
{
|
||||||
u32 lv_zone = zone_for_pblk(lv->params, lv->pblk);
|
u32 lv_zone = zone_for_pblk(&lv->kparams->params, lv->pblk);
|
||||||
/* The relative lblk in the zone. */
|
/* The relative lblk in the zone. */
|
||||||
u32 zone_rel_lblk = lblk - (lv_zone * lv->params->lblk_per_zone);
|
u32 zone_rel_lblk = lblk - (lv_zone * lv->kparams->params.lblk_per_zone);
|
||||||
/* The offset of the element in the (full) lbat. */
|
/* The offset of the element in the (full) lbat. */
|
||||||
u32 lbat_elem_off = zone_rel_lblk * lba_len(lv->params);
|
u32 lbat_elem_off = zone_rel_lblk * lba_len(&lv->kparams->params);
|
||||||
/* The offset of the first view pblk. */
|
/* The offset of the first view pblk. */
|
||||||
u32 lbatview_off = PBLK_SIZE * (lv->pblk - lbat_off(lv->params, lv_zone));
|
u32 lbatview_off = PBLK_SIZE * (lv->pblk - lbat_off(&lv->kparams->params, lv_zone));
|
||||||
|
|
||||||
return lbat_elem_off - lbatview_off;
|
return lbat_elem_off - lbatview_off;
|
||||||
}
|
}
|
||||||
|
@ -318,7 +322,7 @@ lbatview_wmem(struct lbatview* lv, u32 off, u32 len, void* buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
lbatview_elem_realloc(struct lbatview* lv, u64 lblk, u32 len, struct cbd_stats* stats)
|
lbatview_elem_realloc(struct lbatview* lv, u64 lblk, u32 len)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int err;
|
int err;
|
||||||
|
@ -335,19 +339,19 @@ lbatview_elem_realloc(struct lbatview* lv, u64 lblk, u32 len, struct cbd_stats*
|
||||||
mutex_lock(&lv->lock);
|
mutex_lock(&lv->lock);
|
||||||
elem_off = lbatview_elem_off(lv, lblk);
|
elem_off = lbatview_elem_off(lv, lblk);
|
||||||
req_nalloc = (len == CBD_UNCOMPRESSED) ?
|
req_nalloc = (len == CBD_UNCOMPRESSED) ?
|
||||||
lblk_per_pblk(lv->params) :
|
lblk_per_pblk(&lv->kparams->params) :
|
||||||
DIV_ROUND_UP(len, PBLK_SIZE);
|
DIV_ROUND_UP(len, PBLK_SIZE);
|
||||||
elem_lelen = 0;
|
elem_lelen = 0;
|
||||||
lbatview_rmem(lv, elem_off, lba_elem_len_bytes(lv->params), &elem_lelen);
|
lbatview_rmem(lv, elem_off, lba_elem_len_bytes(&lv->kparams->params), &elem_lelen);
|
||||||
elem_len = __le32_to_cpu(elem_lelen);
|
elem_len = __le32_to_cpu(elem_lelen);
|
||||||
cur_nalloc = (elem_len == CBD_UNCOMPRESSED) ?
|
cur_nalloc = (elem_len == CBD_UNCOMPRESSED) ?
|
||||||
lblk_per_pblk(lv->params) :
|
lblk_per_pblk(&lv->kparams->params) :
|
||||||
DIV_ROUND_UP(elem_len, PBLK_SIZE);
|
DIV_ROUND_UP(elem_len, PBLK_SIZE);
|
||||||
old_nalloc = cur_nalloc;
|
old_nalloc = cur_nalloc;
|
||||||
|
|
||||||
while (cur_nalloc < req_nalloc) {
|
while (cur_nalloc < req_nalloc) {
|
||||||
off = elem_off + lba_elem_len_bytes(lv->params) +
|
off = elem_off + lba_elem_len_bytes(&lv->kparams->params) +
|
||||||
cur_nalloc * lba_elem_pblk_bytes(lv->params);
|
cur_nalloc * lba_elem_pblk_bytes(&lv->kparams->params);
|
||||||
pblk = lbatview_alloc_pblk(lv);
|
pblk = lbatview_alloc_pblk(lv);
|
||||||
if (pblk == PBLK_NONE) {
|
if (pblk == PBLK_NONE) {
|
||||||
printk(KERN_ERR "%s: lbatview_alloc_pblk failed\n", __func__);
|
printk(KERN_ERR "%s: lbatview_alloc_pblk failed\n", __func__);
|
||||||
|
@ -356,16 +360,16 @@ lbatview_elem_realloc(struct lbatview* lv, u64 lblk, u32 len, struct cbd_stats*
|
||||||
goto do_free;
|
goto do_free;
|
||||||
}
|
}
|
||||||
elem_lepblk = __cpu_to_le64(pblk);
|
elem_lepblk = __cpu_to_le64(pblk);
|
||||||
lbatview_wmem(lv, off, lba_elem_pblk_bytes(lv->params), &elem_lepblk);
|
lbatview_wmem(lv, off, lba_elem_pblk_bytes(&lv->kparams->params), &elem_lepblk);
|
||||||
++cur_nalloc;
|
++cur_nalloc;
|
||||||
}
|
}
|
||||||
do_free:
|
do_free:
|
||||||
while (cur_nalloc > req_nalloc) {
|
while (cur_nalloc > req_nalloc) {
|
||||||
--cur_nalloc;
|
--cur_nalloc;
|
||||||
off = elem_off + lba_elem_len_bytes(lv->params) +
|
off = elem_off + lba_elem_len_bytes(&lv->kparams->params) +
|
||||||
cur_nalloc * lba_elem_pblk_bytes(lv->params);
|
cur_nalloc * lba_elem_pblk_bytes(&lv->kparams->params);
|
||||||
elem_lepblk = 0;
|
elem_lepblk = 0;
|
||||||
lbatview_rmem(lv, off, lba_elem_pblk_bytes(lv->params), &elem_lepblk);
|
lbatview_rmem(lv, off, lba_elem_pblk_bytes(&lv->kparams->params), &elem_lepblk);
|
||||||
pblk = __le64_to_cpu(elem_lepblk);
|
pblk = __le64_to_cpu(elem_lepblk);
|
||||||
err = lbatview_free_pblk(lv, pblk);
|
err = lbatview_free_pblk(lv, pblk);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -376,8 +380,20 @@ do_free:
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
elem_lelen = __cpu_to_le32(len);
|
elem_lelen = __cpu_to_le32(len);
|
||||||
lbatview_wmem(lv, elem_off, lba_elem_len_bytes(lv->params), &elem_lelen);
|
lbatview_wmem(lv, elem_off, lba_elem_len_bytes(&lv->kparams->params), &elem_lelen);
|
||||||
stats->pblk_alloc += req_nalloc - old_nalloc;
|
mutex_lock(&lv->kstats->lock);
|
||||||
|
lv->kstats->stats.pblk_alloc += req_nalloc - old_nalloc;
|
||||||
|
if (old_nalloc == 0) {
|
||||||
|
if (req_nalloc != 0) {
|
||||||
|
++lv->kstats->stats.lblk_alloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (req_nalloc == 0) {
|
||||||
|
--lv->kstats->stats.lblk_alloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutex_unlock(&lv->kstats->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&lv->lock);
|
mutex_unlock(&lv->lock);
|
||||||
|
@ -393,7 +409,7 @@ lbatview_elem_len(struct lbatview* lv, u64 lblk)
|
||||||
mutex_lock(&lv->lock);
|
mutex_lock(&lv->lock);
|
||||||
off = lbatview_elem_off(lv, lblk);
|
off = lbatview_elem_off(lv, lblk);
|
||||||
elem_lelen = 0;
|
elem_lelen = 0;
|
||||||
lbatview_rmem(lv, off, lba_elem_len_bytes(lv->params), &elem_lelen);
|
lbatview_rmem(lv, off, lba_elem_len_bytes(&lv->kparams->params), &elem_lelen);
|
||||||
mutex_unlock(&lv->lock);
|
mutex_unlock(&lv->lock);
|
||||||
|
|
||||||
return __le32_to_cpu(elem_lelen);
|
return __le32_to_cpu(elem_lelen);
|
||||||
|
@ -409,19 +425,19 @@ lbatview_elem_pblk(struct lbatview* lv, u64 lblk, u32 idx)
|
||||||
|
|
||||||
mutex_lock(&lv->lock);
|
mutex_lock(&lv->lock);
|
||||||
off = lbatview_elem_off(lv, lblk) +
|
off = lbatview_elem_off(lv, lblk) +
|
||||||
lba_elem_len_bytes(lv->params) +
|
lba_elem_len_bytes(&lv->kparams->params) +
|
||||||
idx * lba_elem_pblk_bytes(lv->params);
|
idx * lba_elem_pblk_bytes(&lv->kparams->params);
|
||||||
elem_lepblk = 0;
|
elem_lepblk = 0;
|
||||||
lbatview_rmem(lv, off, lba_elem_pblk_bytes(lv->params), &elem_lepblk);
|
lbatview_rmem(lv, off, lba_elem_pblk_bytes(&lv->kparams->params), &elem_lepblk);
|
||||||
mutex_unlock(&lv->lock);
|
mutex_unlock(&lv->lock);
|
||||||
pblk = __le64_to_cpu(elem_lepblk);
|
pblk = __le64_to_cpu(elem_lepblk);
|
||||||
pblk_zone = zone_for_pblk(lv->params, pblk);
|
pblk_zone = zone_for_pblk(&lv->kparams->params, pblk);
|
||||||
if (pblk_zone == ZONE_NONE || pblk_zone >= lv->params->nr_zones) {
|
if (pblk_zone == ZONE_NONE || pblk_zone >= lv->kparams->params.nr_zones) {
|
||||||
printk(KERN_ERR "%s: pblk %lu out of range at lblk=%lu n=%u\n",
|
printk(KERN_ERR "%s: pblk %lu out of range at lblk=%lu n=%u\n",
|
||||||
__func__, (unsigned long)pblk, (unsigned long)lblk, idx);
|
__func__, (unsigned long)pblk, (unsigned long)lblk, idx);
|
||||||
return PBLK_NONE;
|
return PBLK_NONE;
|
||||||
}
|
}
|
||||||
if (pblk < zone_data_off(lv->params, pblk_zone)) {
|
if (pblk < zone_data_off(&lv->kparams->params, pblk_zone)) {
|
||||||
printk(KERN_ERR "%s: pblk in metadata at lblk=%lu n=%u\n",
|
printk(KERN_ERR "%s: pblk in metadata at lblk=%lu n=%u\n",
|
||||||
__func__, (unsigned long)pblk, idx);
|
__func__, (unsigned long)pblk, idx);
|
||||||
return PBLK_NONE;
|
return PBLK_NONE;
|
||||||
|
@ -448,26 +464,27 @@ lbatviewcache_size(void)
|
||||||
|
|
||||||
bool
|
bool
|
||||||
lbatviewcache_ctr(struct lbatviewcache* lvc,
|
lbatviewcache_ctr(struct lbatviewcache* lvc,
|
||||||
struct cbd_params* params, u32 cache_pages)
|
struct compress_params* kparams, struct compress_stats* stats,
|
||||||
|
u32 cache_pages)
|
||||||
{
|
{
|
||||||
struct lbatview* cache;
|
struct lbatview* cache;
|
||||||
u32 cache_len;
|
u32 cache_len;
|
||||||
u32 n;
|
u32 n;
|
||||||
|
|
||||||
memset(lvc, 0, sizeof(struct lbatviewcache));
|
memset(lvc, 0, sizeof(struct lbatviewcache));
|
||||||
lvc->params = params;
|
lvc->params = &kparams->params;
|
||||||
lvc->pc = kmalloc(pbatcache_size(), GFP_KERNEL);
|
lvc->pc = kmalloc(pbatcache_size(), GFP_KERNEL);
|
||||||
if (!lvc->pc) {
|
if (!lvc->pc) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!pbatcache_ctr(lvc->pc, params, cache_pages)) {
|
if (!pbatcache_ctr(lvc->pc, kparams, cache_pages)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lvc->lpc = kmalloc(lbatpagecache_size(), GFP_KERNEL);
|
lvc->lpc = kmalloc(lbatpagecache_size(), GFP_KERNEL);
|
||||||
if (!lvc->lpc) {
|
if (!lvc->lpc) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!lbatpagecache_ctr(lvc->lpc, params, cache_pages)) {
|
if (!lbatpagecache_ctr(lvc->lpc, kparams, cache_pages)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* lbatviewcache gets one entry per lbatpage (XXX: 5/6?) */
|
/* lbatviewcache gets one entry per lbatpage (XXX: 5/6?) */
|
||||||
|
@ -486,7 +503,7 @@ lbatviewcache_ctr(struct lbatviewcache* lvc,
|
||||||
lvc->cache_len = cache_len;
|
lvc->cache_len = cache_len;
|
||||||
lvc->cache = cache;
|
lvc->cache = cache;
|
||||||
for (n = 0; n < cache_len; ++n) {
|
for (n = 0; n < cache_len; ++n) {
|
||||||
if (!lbatview_ctr(&cache[n], lvc->params, lvc->pc, lvc->lpc)) {
|
if (!lbatview_ctr(&cache[n], kparams, stats, lvc->pc, lvc->lpc)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
list_add_tail(&cache[n].list, &lvc->cache_head);
|
list_add_tail(&cache[n].list, &lvc->cache_head);
|
||||||
|
|
|
@ -39,7 +39,7 @@ struct lbd {
|
||||||
unsigned int ref;
|
unsigned int ref;
|
||||||
|
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct cbd_params* params;
|
struct compress_params* kparams;
|
||||||
struct lbatviewcache* lvc;
|
struct lbatviewcache* lvc;
|
||||||
struct lbatview* lv;
|
struct lbatview* lv;
|
||||||
void* percpu;
|
void* percpu;
|
||||||
|
@ -99,9 +99,9 @@ lblk_compress_lz4(struct lbd* lbd)
|
||||||
state = lblk_get_compress_state(lbd->percpu, cpu);
|
state = lblk_get_compress_state(lbd->percpu, cpu);
|
||||||
BUG_ON(state == NULL);
|
BUG_ON(state == NULL);
|
||||||
clen = LZ4_compress_fast(lbd->buf, state->buf,
|
clen = LZ4_compress_fast(lbd->buf, state->buf,
|
||||||
PBLK_SIZE * lblk_per_pblk(lbd->params),
|
PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params),
|
||||||
PBLK_SIZE * (lblk_per_pblk(lbd->params) - 1),
|
PBLK_SIZE * (lblk_per_pblk(&lbd->kparams->params) - 1),
|
||||||
lbd->params->compression, state->lz4_workmem);
|
lbd->kparams->params.compression, state->lz4_workmem);
|
||||||
if (clen <= 0) {
|
if (clen <= 0) {
|
||||||
put_cpu();
|
put_cpu();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -118,7 +118,7 @@ lblk_decompress_lz4(struct lbd* lbd)
|
||||||
int ret;
|
int ret;
|
||||||
int cpu;
|
int cpu;
|
||||||
struct lblk_compress_state* state;
|
struct lblk_compress_state* state;
|
||||||
u32 dlen = PBLK_SIZE * lblk_per_pblk(lbd->params);
|
u32 dlen = PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params);
|
||||||
|
|
||||||
cpu = get_cpu();
|
cpu = get_cpu();
|
||||||
state = lblk_get_compress_state(lbd->percpu, cpu);
|
state = lblk_get_compress_state(lbd->percpu, cpu);
|
||||||
|
@ -155,9 +155,9 @@ lblk_compress_zlib(struct lbd* lbd)
|
||||||
ret = zlib_deflateReset(stream);
|
ret = zlib_deflateReset(stream);
|
||||||
BUG_ON(ret != Z_OK);
|
BUG_ON(ret != Z_OK);
|
||||||
stream->next_in = lbd->buf;
|
stream->next_in = lbd->buf;
|
||||||
stream->avail_in = PBLK_SIZE * lblk_per_pblk(lbd->params);
|
stream->avail_in = PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params);
|
||||||
stream->next_out = state->buf;
|
stream->next_out = state->buf;
|
||||||
stream->avail_out = PBLK_SIZE * (lblk_per_pblk(lbd->params) - 1);
|
stream->avail_out = PBLK_SIZE * (lblk_per_pblk(&lbd->kparams->params) - 1);
|
||||||
ret = zlib_deflate(stream, Z_FINISH);
|
ret = zlib_deflate(stream, Z_FINISH);
|
||||||
if (ret != Z_STREAM_END) {
|
if (ret != Z_STREAM_END) {
|
||||||
put_cpu();
|
put_cpu();
|
||||||
|
@ -177,7 +177,7 @@ lblk_decompress_zlib(struct lbd* lbd)
|
||||||
int cpu;
|
int cpu;
|
||||||
struct lblk_compress_state* state;
|
struct lblk_compress_state* state;
|
||||||
z_stream* stream;
|
z_stream* stream;
|
||||||
u32 dlen = PBLK_SIZE * lblk_per_pblk(lbd->params);
|
u32 dlen = PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params);
|
||||||
|
|
||||||
cpu = get_cpu();
|
cpu = get_cpu();
|
||||||
state = lblk_get_compress_state(lbd->percpu, cpu);
|
state = lblk_get_compress_state(lbd->percpu, cpu);
|
||||||
|
@ -217,12 +217,12 @@ static size_t
|
||||||
lblk_compress(struct lbd* lbd)
|
lblk_compress(struct lbd* lbd)
|
||||||
{
|
{
|
||||||
#ifdef COMPRESS_HAVE_LZ4
|
#ifdef COMPRESS_HAVE_LZ4
|
||||||
if (lbd->params->algorithm == CBD_ALG_LZ4) {
|
if (lbd->kparams->params.algorithm == CBD_ALG_LZ4) {
|
||||||
return lblk_compress_lz4(lbd);
|
return lblk_compress_lz4(lbd);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef COMPRESS_HAVE_ZLIB
|
#ifdef COMPRESS_HAVE_ZLIB
|
||||||
if (lbd->params->algorithm == CBD_ALG_ZLIB) {
|
if (lbd->kparams->params.algorithm == CBD_ALG_ZLIB) {
|
||||||
return lblk_compress_zlib(lbd);
|
return lblk_compress_zlib(lbd);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -236,12 +236,12 @@ static bool
|
||||||
lblk_decompress(struct lbd* lbd)
|
lblk_decompress(struct lbd* lbd)
|
||||||
{
|
{
|
||||||
#ifdef COMPRESS_HAVE_LZ4
|
#ifdef COMPRESS_HAVE_LZ4
|
||||||
if (lbd->params->algorithm == CBD_ALG_LZ4) {
|
if (lbd->kparams->params.algorithm == CBD_ALG_LZ4) {
|
||||||
return lblk_decompress_lz4(lbd);
|
return lblk_decompress_lz4(lbd);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef COMPRESS_HAVE_ZLIB
|
#ifdef COMPRESS_HAVE_ZLIB
|
||||||
if (lbd->params->algorithm == CBD_ALG_ZLIB) {
|
if (lbd->kparams->params.algorithm == CBD_ALG_ZLIB) {
|
||||||
return lblk_decompress_zlib(lbd);
|
return lblk_decompress_zlib(lbd);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -250,11 +250,11 @@ lblk_decompress(struct lbd* lbd)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
lbd_ctr(struct lbd* lbd,
|
lbd_ctr(struct lbd* lbd,
|
||||||
struct cbd_params* params,
|
struct compress_params* kparams,
|
||||||
struct lbatviewcache* lvc,
|
struct lbatviewcache* lvc,
|
||||||
void* percpu)
|
void* percpu)
|
||||||
{
|
{
|
||||||
u32 nr_pages = lblk_per_pblk(params);
|
u32 nr_pages = lblk_per_pblk(&kparams->params);
|
||||||
|
|
||||||
memset(lbd, 0, sizeof(struct lbd));
|
memset(lbd, 0, sizeof(struct lbd));
|
||||||
INIT_LIST_HEAD(&lbd->lru_list);
|
INIT_LIST_HEAD(&lbd->lru_list);
|
||||||
|
@ -264,7 +264,7 @@ lbd_ctr(struct lbd* lbd,
|
||||||
mutex_init(&lbd->reflock);
|
mutex_init(&lbd->reflock);
|
||||||
lbd->ref = 0;
|
lbd->ref = 0;
|
||||||
mutex_init(&lbd->lock);
|
mutex_init(&lbd->lock);
|
||||||
lbd->params = params;
|
lbd->kparams = kparams;
|
||||||
lbd->lvc = lvc;
|
lbd->lvc = lvc;
|
||||||
lbd->lv = NULL;
|
lbd->lv = NULL;
|
||||||
lbd->percpu = percpu;
|
lbd->percpu = percpu;
|
||||||
|
@ -287,7 +287,7 @@ lbd_ctr(struct lbd* lbd,
|
||||||
static void
|
static void
|
||||||
lbd_dtr(struct lbd* lbd)
|
lbd_dtr(struct lbd* lbd)
|
||||||
{
|
{
|
||||||
u32 nr_pages = lblk_per_pblk(lbd->params);
|
u32 nr_pages = lblk_per_pblk(&lbd->kparams->params);
|
||||||
|
|
||||||
if (lbatviewcache_put(lbd->lvc, lbd->lv) != 0) {
|
if (lbatviewcache_put(lbd->lvc, lbd->lv) != 0) {
|
||||||
printk(KERN_ERR "%s: lbatviewcache_put failed\n", __func__);
|
printk(KERN_ERR "%s: lbatviewcache_put failed\n", __func__);
|
||||||
|
@ -310,13 +310,13 @@ lbd_error(struct lbd* lbd)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lbd_flush(struct lbd* lbd, struct cbd_stats* stats)
|
lbd_flush(struct lbd* lbd)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int err;
|
int err;
|
||||||
u32 n;
|
u32 n;
|
||||||
u64 pblk;
|
u64 pblk;
|
||||||
u32 nr_pages = lblk_per_pblk(lbd->params);
|
u32 nr_pages = lblk_per_pblk(&lbd->kparams->params);
|
||||||
u32 count;
|
u32 count;
|
||||||
struct page* iopagev[1];
|
struct page* iopagev[1];
|
||||||
|
|
||||||
|
@ -329,9 +329,9 @@ lbd_flush(struct lbd* lbd, struct cbd_stats* stats)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lblk_is_zeros(lbd->params, lbd)) {
|
if (lblk_is_zeros(&lbd->kparams->params, lbd)) {
|
||||||
lbd->c_len = CBD_UNCOMPRESSED;
|
lbd->c_len = CBD_UNCOMPRESSED;
|
||||||
ret = lbatview_elem_realloc(lbd->lv, lbd->lblk, 0, stats);
|
ret = lbatview_elem_realloc(lbd->lv, lbd->lblk, 0);
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
lbd->c_len = lblk_compress(lbd);
|
lbd->c_len = lblk_compress(lbd);
|
||||||
|
@ -344,20 +344,20 @@ lbd_flush(struct lbd* lbd, struct cbd_stats* stats)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lbd->c_len = CBD_UNCOMPRESSED;
|
lbd->c_len = CBD_UNCOMPRESSED;
|
||||||
count = lblk_per_pblk(lbd->params);
|
count = lblk_per_pblk(&lbd->kparams->params);
|
||||||
}
|
}
|
||||||
ret = lbatview_elem_realloc(lbd->lv, lbd->lblk, lbd->c_len, stats);
|
ret = lbatview_elem_realloc(lbd->lv, lbd->lblk, lbd->c_len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
lbd->params->flags |= CBD_FLAG_ERROR;
|
lbd->kparams->params.flags |= CBD_FLAG_ERROR;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
for (n = 0; n < count; ++n) {
|
for (n = 0; n < count; ++n) {
|
||||||
pblk = lbatview_elem_pblk(lbd->lv, lbd->lblk, n);
|
pblk = lbatview_elem_pblk(lbd->lv, lbd->lblk, n);
|
||||||
BUG_ON(pblk == PBLK_NONE);
|
BUG_ON(pblk == PBLK_NONE);
|
||||||
iopagev[0] = lbd->pagev[n];
|
iopagev[0] = lbd->pagev[n];
|
||||||
pblk_write(lbd->params, pblk, 1, iopagev);
|
pblk_write(lbd->kparams, pblk, 1, iopagev);
|
||||||
}
|
}
|
||||||
while (n < lblk_per_pblk(lbd->params)) {
|
while (n < lblk_per_pblk(&lbd->kparams->params)) {
|
||||||
unlock_page(lbd->pagev[n]);
|
unlock_page(lbd->pagev[n]);
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
|
@ -394,11 +394,11 @@ lbd_read(struct lbd* lbd)
|
||||||
}
|
}
|
||||||
lbd->c_len = lbatview_elem_len(lbd->lv, lbd->lblk);
|
lbd->c_len = lbatview_elem_len(lbd->lv, lbd->lblk);
|
||||||
if (lbd->c_len == 0) {
|
if (lbd->c_len == 0) {
|
||||||
memset(lbd->buf, 0, PBLK_SIZE * lblk_per_pblk(lbd->params));
|
memset(lbd->buf, 0, PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
count = (lbd->c_len == CBD_UNCOMPRESSED) ?
|
count = (lbd->c_len == CBD_UNCOMPRESSED) ?
|
||||||
lblk_per_pblk(lbd->params) :
|
lblk_per_pblk(&lbd->kparams->params) :
|
||||||
DIV_ROUND_UP(lbd->c_len, PBLK_SIZE);
|
DIV_ROUND_UP(lbd->c_len, PBLK_SIZE);
|
||||||
for (n = 0; n < count; ++n) {
|
for (n = 0; n < count; ++n) {
|
||||||
pblk = lbatview_elem_pblk(lbd->lv, lbd->lblk, n);
|
pblk = lbatview_elem_pblk(lbd->lv, lbd->lblk, n);
|
||||||
|
@ -408,7 +408,7 @@ lbd_read(struct lbd* lbd)
|
||||||
}
|
}
|
||||||
iopagev[0] = lbd->pagev[n];
|
iopagev[0] = lbd->pagev[n];
|
||||||
/* XXX: Issue non-blocking reads? */
|
/* XXX: Issue non-blocking reads? */
|
||||||
ret = pblk_read_wait(lbd->params, pblk, 1, iopagev);
|
ret = pblk_read_wait(lbd->kparams, pblk, 1, iopagev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -431,7 +431,7 @@ static int
|
||||||
lbd_reset(struct lbd* lbd, u64 lblk)
|
lbd_reset(struct lbd* lbd, u64 lblk)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 nr_pages = lblk_per_pblk(lbd->params);
|
u32 nr_pages = lblk_per_pblk(&lbd->kparams->params);
|
||||||
u32 n;
|
u32 n;
|
||||||
|
|
||||||
if (lbd->lv) { printk(KERN_ERR "%s: lbatview leak\n", __func__); }
|
if (lbd->lv) { printk(KERN_ERR "%s: lbatview leak\n", __func__); }
|
||||||
|
@ -485,7 +485,7 @@ void
|
||||||
lbd_data_read(struct lbd* lbd, u32 off, u32 len, u8* buf)
|
lbd_data_read(struct lbd* lbd, u32 off, u32 len, u8* buf)
|
||||||
{
|
{
|
||||||
/* XXX: convert to BUG_ON */
|
/* XXX: convert to BUG_ON */
|
||||||
if (off + len > PBLK_SIZE * lblk_per_pblk(lbd->params)) {
|
if (off + len > PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params)) {
|
||||||
printk(KERN_ERR "%s: out of bounds\n", __func__);
|
printk(KERN_ERR "%s: out of bounds\n", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -498,7 +498,7 @@ void
|
||||||
lbd_data_write(struct lbd* lbd, u32 off, u32 len, const u8* buf)
|
lbd_data_write(struct lbd* lbd, u32 off, u32 len, const u8* buf)
|
||||||
{
|
{
|
||||||
/* XXX: convert to BUG_ON */
|
/* XXX: convert to BUG_ON */
|
||||||
if (off + len > PBLK_SIZE * lblk_per_pblk(lbd->params)) {
|
if (off + len > PBLK_SIZE * lblk_per_pblk(&lbd->kparams->params)) {
|
||||||
printk(KERN_ERR "%s: out of bounds\n", __func__);
|
printk(KERN_ERR "%s: out of bounds\n", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -511,7 +511,6 @@ lbd_data_write(struct lbd* lbd, u32 off, u32 len, const u8* buf)
|
||||||
struct lbdcache
|
struct lbdcache
|
||||||
{
|
{
|
||||||
struct cbd_params* params;
|
struct cbd_params* params;
|
||||||
struct cbd_stats* stats;
|
|
||||||
void* percpu;
|
void* percpu;
|
||||||
struct lbatviewcache* lvc;
|
struct lbatviewcache* lvc;
|
||||||
struct mutex cache_lock;
|
struct mutex cache_lock;
|
||||||
|
@ -605,7 +604,7 @@ lbdcache_free_compress_state(void* percpu, const struct cbd_params* params, int
|
||||||
|
|
||||||
bool
|
bool
|
||||||
lbdcache_ctr(struct lbdcache* lc,
|
lbdcache_ctr(struct lbdcache* lc,
|
||||||
struct cbd_params* params, struct cbd_stats* stats,
|
struct compress_params* kparams, struct compress_stats* kstats,
|
||||||
u32 cache_pages)
|
u32 cache_pages)
|
||||||
{
|
{
|
||||||
int cpu;
|
int cpu;
|
||||||
|
@ -614,11 +613,10 @@ lbdcache_ctr(struct lbdcache* lc,
|
||||||
u32 n;
|
u32 n;
|
||||||
|
|
||||||
memset(lc, 0, sizeof(struct lbdcache));
|
memset(lc, 0, sizeof(struct lbdcache));
|
||||||
lc->params = params;
|
lc->params = &kparams->params;
|
||||||
lc->stats = stats;
|
|
||||||
lc->percpu = alloc_percpu(void*);
|
lc->percpu = alloc_percpu(void*);
|
||||||
for (cpu = 0; cpu < num_online_cpus(); ++cpu) {
|
for (cpu = 0; cpu < num_online_cpus(); ++cpu) {
|
||||||
if (!lbdcache_alloc_compress_state(lc->percpu, params, cpu)) {
|
if (!lbdcache_alloc_compress_state(lc->percpu, lc->params, cpu)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -626,12 +624,12 @@ lbdcache_ctr(struct lbdcache* lc,
|
||||||
if (!lc->lvc) {
|
if (!lc->lvc) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!lbatviewcache_ctr(lc->lvc, params, cache_pages)) {
|
if (!lbatviewcache_ctr(lc->lvc, kparams, kstats, cache_pages)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* lbdcache gets 1/2 of cache_pages */
|
/* lbdcache gets 1/2 of cache_pages */
|
||||||
cache_len = (cache_pages * 1 / 2) / lblk_per_pblk(params);
|
cache_len = (cache_pages * 1 / 2) / lblk_per_pblk(lc->params);
|
||||||
if (!cache_len) {
|
if (!cache_len) {
|
||||||
printk(KERN_ERR "%s: Cache too small\n", __func__);
|
printk(KERN_ERR "%s: Cache too small\n", __func__);
|
||||||
return false;
|
return false;
|
||||||
|
@ -646,7 +644,7 @@ lbdcache_ctr(struct lbdcache* lc,
|
||||||
lc->cache_len = cache_len;
|
lc->cache_len = cache_len;
|
||||||
lc->cache = cache;
|
lc->cache = cache;
|
||||||
for (n = 0; n < cache_len; ++n) {
|
for (n = 0; n < cache_len; ++n) {
|
||||||
if (!lbd_ctr(&cache[n], params, lc->lvc, lc->percpu)) {
|
if (!lbd_ctr(&cache[n], kparams, lc->lvc, lc->percpu)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
list_add_tail(&cache[n].lru_list, &lc->cache_head);
|
list_add_tail(&cache[n].lru_list, &lc->cache_head);
|
||||||
|
@ -669,7 +667,7 @@ lbdcache_dtr(struct lbdcache* lc)
|
||||||
cancel_delayed_work_sync(&lc->flush_dwork);
|
cancel_delayed_work_sync(&lc->flush_dwork);
|
||||||
flush_delayed_work(&lc->flush_dwork);
|
flush_delayed_work(&lc->flush_dwork);
|
||||||
list_for_each_entry(lbd, &lc->flush_head, flush_list) {
|
list_for_each_entry(lbd, &lc->flush_head, flush_list) {
|
||||||
ret = lbd_flush(lbd, lc->stats);
|
ret = lbd_flush(lbd);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: lbd_flush failed\n", __func__);
|
printk(KERN_ERR "%s: lbd_flush failed\n", __func__);
|
||||||
}
|
}
|
||||||
|
@ -727,7 +725,7 @@ lbdcache_flush(struct work_struct* work)
|
||||||
mutex_unlock(&lc->flush_lock);
|
mutex_unlock(&lc->flush_lock);
|
||||||
list_for_each_entry(lbd, &flushq, flush_list) {
|
list_for_each_entry(lbd, &flushq, flush_list) {
|
||||||
lbd->ref = 0;
|
lbd->ref = 0;
|
||||||
ret = lbd_flush(lbd, lc->stats);
|
ret = lbd_flush(lbd);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: lbd_flush failed\n", __func__);
|
printk(KERN_ERR "%s: lbd_flush failed\n", __func__);
|
||||||
}
|
}
|
||||||
|
@ -801,7 +799,7 @@ lbdcache_get(struct lbdcache* lc, u64 lblk)
|
||||||
mutex_unlock(&lc->cache_lock);
|
mutex_unlock(&lc->cache_lock);
|
||||||
mutex_unlock(&lc->flush_lock);
|
mutex_unlock(&lc->flush_lock);
|
||||||
lbd->ref = 0;
|
lbd->ref = 0;
|
||||||
ret = lbd_flush(lbd, lc->stats);
|
ret = lbd_flush(lbd);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: lbd_flush failed\n", __func__);
|
printk(KERN_ERR "%s: lbd_flush failed\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ struct pbat {
|
||||||
unsigned int ref;
|
unsigned int ref;
|
||||||
|
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct cbd_params* params;
|
struct compress_params* kparams;
|
||||||
bool full;
|
bool full;
|
||||||
u32 last_alloc;
|
u32 last_alloc;
|
||||||
struct page** pagev;
|
struct page** pagev;
|
||||||
|
@ -45,9 +45,9 @@ struct pbat {
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
pbat_ctr(struct pbat* pbat,
|
pbat_ctr(struct pbat* pbat,
|
||||||
struct cbd_params* params)
|
struct compress_params* kparams)
|
||||||
{
|
{
|
||||||
u32 nr_pages = pbat_len(params);
|
u32 nr_pages = pbat_len(&kparams->params);
|
||||||
|
|
||||||
memset(pbat, 0, sizeof(struct pbat));
|
memset(pbat, 0, sizeof(struct pbat));
|
||||||
INIT_LIST_HEAD(&pbat->list);
|
INIT_LIST_HEAD(&pbat->list);
|
||||||
|
@ -55,7 +55,7 @@ pbat_ctr(struct pbat* pbat,
|
||||||
mutex_init(&pbat->reflock);
|
mutex_init(&pbat->reflock);
|
||||||
pbat->ref = 0;
|
pbat->ref = 0;
|
||||||
mutex_init(&pbat->lock);
|
mutex_init(&pbat->lock);
|
||||||
pbat->params = params;
|
pbat->kparams = kparams;
|
||||||
pbat->full = false;
|
pbat->full = false;
|
||||||
pbat->last_alloc = 0;
|
pbat->last_alloc = 0;
|
||||||
pbat->pagev = kzalloc(nr_pages * sizeof(struct page*), GFP_KERNEL);
|
pbat->pagev = kzalloc(nr_pages * sizeof(struct page*), GFP_KERNEL);
|
||||||
|
@ -81,7 +81,7 @@ pbat_ctr(struct pbat* pbat,
|
||||||
static void
|
static void
|
||||||
pbat_dtr(struct pbat* pbat)
|
pbat_dtr(struct pbat* pbat)
|
||||||
{
|
{
|
||||||
u32 nr_pages = pbat_len(pbat->params);
|
u32 nr_pages = pbat_len(&pbat->kparams->params);
|
||||||
u32 n;
|
u32 n;
|
||||||
|
|
||||||
for (n = 0; n < nr_pages; ++n) {
|
for (n = 0; n < nr_pages; ++n) {
|
||||||
|
@ -106,7 +106,7 @@ static int
|
||||||
pbat_flush(struct pbat* pbat)
|
pbat_flush(struct pbat* pbat)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 nr_pages = pbat_len(pbat->params);
|
u32 nr_pages = pbat_len(&pbat->kparams->params);
|
||||||
u32 n;
|
u32 n;
|
||||||
u64 pblk;
|
u64 pblk;
|
||||||
|
|
||||||
|
@ -118,8 +118,8 @@ pbat_flush(struct pbat* pbat)
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
pblk = pbat_off(pbat->params, pbat->zone);
|
pblk = pbat_off(&pbat->kparams->params, pbat->zone);
|
||||||
pblk_write(pbat->params, pblk, nr_pages, pbat->pagev);
|
pblk_write(pbat->kparams, pblk, nr_pages, pbat->pagev);
|
||||||
mutex_unlock(&pbat->lock);
|
mutex_unlock(&pbat->lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -137,15 +137,15 @@ static int
|
||||||
pbat_read(struct pbat* pbat)
|
pbat_read(struct pbat* pbat)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 nr_pages = pbat_len(pbat->params);
|
u32 nr_pages = pbat_len(&pbat->kparams->params);
|
||||||
u64 pblk;
|
u64 pblk;
|
||||||
|
|
||||||
/* XXX: can't happen because pbatcache will not use a page with an error */
|
/* XXX: can't happen because pbatcache will not use a page with an error */
|
||||||
if (PageError(pbat->pagev[0])) {
|
if (PageError(pbat->pagev[0])) {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
pblk = pbat_off(pbat->params, pbat->zone);
|
pblk = pbat_off(&pbat->kparams->params, pbat->zone);
|
||||||
ret = pblk_read_wait(pbat->params, pblk, nr_pages, pbat->pagev);
|
ret = pblk_read_wait(pbat->kparams, pblk, nr_pages, pbat->pagev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ static int
|
||||||
pbat_reset(struct pbat* pbat, u32 zone)
|
pbat_reset(struct pbat* pbat, u32 zone)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 nr_pages = pbat_len(pbat->params);
|
u32 nr_pages = pbat_len(&pbat->kparams->params);
|
||||||
u32 n;
|
u32 n;
|
||||||
|
|
||||||
for (n = 0; n < nr_pages; ++n) {
|
for (n = 0; n < nr_pages; ++n) {
|
||||||
|
@ -186,7 +186,7 @@ pbat_zone(struct pbat* pbat)
|
||||||
u64
|
u64
|
||||||
pbat_alloc(struct pbat* pbat)
|
pbat_alloc(struct pbat* pbat)
|
||||||
{
|
{
|
||||||
u32 pblk_count = pbat_len(pbat->params) * PBLK_SIZE_BITS;
|
u32 pblk_count = pbat_len(&pbat->kparams->params) * PBLK_SIZE_BITS;
|
||||||
u32 idx;
|
u32 idx;
|
||||||
u64 pblk;
|
u64 pblk;
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ pbat_alloc(struct pbat* pbat)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
pbat->last_alloc = idx;
|
pbat->last_alloc = idx;
|
||||||
pblk = idx + zone_data_off(pbat->params, pbat->zone);
|
pblk = idx + zone_data_off(&pbat->kparams->params, pbat->zone);
|
||||||
SetPageDirty(pbat->pagev[0]);
|
SetPageDirty(pbat->pagev[0]);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -213,17 +213,17 @@ out:
|
||||||
int
|
int
|
||||||
pbat_free(struct pbat* pbat, u64 pblk)
|
pbat_free(struct pbat* pbat, u64 pblk)
|
||||||
{
|
{
|
||||||
u32 pblk_count = pbat_len(pbat->params) * PBLK_SIZE_BITS;
|
u32 pblk_count = pbat_len(&pbat->kparams->params) * PBLK_SIZE_BITS;
|
||||||
u32 zone;
|
u32 zone;
|
||||||
u32 idx;
|
u32 idx;
|
||||||
|
|
||||||
zone = zone_for_pblk(pbat->params, pblk);
|
zone = zone_for_pblk(&pbat->kparams->params, pblk);
|
||||||
BUG_ON(zone != pbat->zone);
|
BUG_ON(zone != pbat->zone);
|
||||||
if (pblk < zone_data_off(pbat->params, zone)) {
|
if (pblk < zone_data_off(&pbat->kparams->params, zone)) {
|
||||||
printk(KERN_ERR "%s: pblk in metadata\n", __func__);
|
printk(KERN_ERR "%s: pblk in metadata\n", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
idx = pblk - zone_data_off(pbat->params, zone);
|
idx = pblk - zone_data_off(&pbat->kparams->params, zone);
|
||||||
BUG_ON(idx >= pblk_count);
|
BUG_ON(idx >= pblk_count);
|
||||||
mutex_lock(&pbat->lock);
|
mutex_lock(&pbat->lock);
|
||||||
cbd_bitmap_free(pbat->buf, idx);
|
cbd_bitmap_free(pbat->buf, idx);
|
||||||
|
@ -235,7 +235,6 @@ pbat_free(struct pbat* pbat, u64 pblk)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pbatcache {
|
struct pbatcache {
|
||||||
struct cbd_params* params;
|
|
||||||
struct mutex cache_lock;
|
struct mutex cache_lock;
|
||||||
struct list_head cache_head;
|
struct list_head cache_head;
|
||||||
unsigned int cache_len;
|
unsigned int cache_len;
|
||||||
|
@ -251,17 +250,16 @@ pbatcache_size(void)
|
||||||
|
|
||||||
bool
|
bool
|
||||||
pbatcache_ctr(struct pbatcache* pc,
|
pbatcache_ctr(struct pbatcache* pc,
|
||||||
struct cbd_params* params, u32 cache_pages)
|
struct compress_params* kparams, u32 cache_pages)
|
||||||
{
|
{
|
||||||
struct pbat* cache;
|
struct pbat* cache;
|
||||||
u32 cache_len;
|
u32 cache_len;
|
||||||
u32 n;
|
u32 n;
|
||||||
|
|
||||||
memset(pc, 0, sizeof(struct pbatcache));
|
memset(pc, 0, sizeof(struct pbatcache));
|
||||||
pc->params = params;
|
|
||||||
|
|
||||||
/* pbatcache gets 1/32 of cache_pages */
|
/* pbatcache gets 1/32 of cache_pages */
|
||||||
cache_len = (cache_pages * 1 / 32) / pbat_len(params);
|
cache_len = (cache_pages * 1 / 32) / pbat_len(&kparams->params);
|
||||||
if (!cache_len) {
|
if (!cache_len) {
|
||||||
printk(KERN_ERR "%s: Cache too small\n", __func__);
|
printk(KERN_ERR "%s: Cache too small\n", __func__);
|
||||||
return false;
|
return false;
|
||||||
|
@ -276,12 +274,12 @@ pbatcache_ctr(struct pbatcache* pc,
|
||||||
pc->cache_len = cache_len;
|
pc->cache_len = cache_len;
|
||||||
pc->cache = cache;
|
pc->cache = cache;
|
||||||
for (n = 0; n < cache_len; ++n) {
|
for (n = 0; n < cache_len; ++n) {
|
||||||
if (!pbat_ctr(&cache[n], pc->params)) {
|
if (!pbat_ctr(&cache[n], kparams)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
list_add_tail(&cache[n].list, &pc->cache_head);
|
list_add_tail(&cache[n].list, &pc->cache_head);
|
||||||
}
|
}
|
||||||
pc->full = kzalloc(DIV_ROUND_UP(params->nr_zones, BITS_PER_BYTE), GFP_KERNEL);
|
pc->full = kzalloc(DIV_ROUND_UP(kparams->params.nr_zones, BITS_PER_BYTE), GFP_KERNEL);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -307,7 +305,6 @@ pbatcache_dtr(struct pbatcache* pc)
|
||||||
pc->cache = NULL;
|
pc->cache = NULL;
|
||||||
pc->cache_len = 0;
|
pc->cache_len = 0;
|
||||||
INIT_LIST_HEAD(&pc->cache_head);
|
INIT_LIST_HEAD(&pc->cache_head);
|
||||||
pc->params = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pbat*
|
struct pbat*
|
||||||
|
|
|
@ -123,13 +123,13 @@ pblk_io_prepare(struct block_device* bdev, unsigned int op,
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
pblk_read_wait(struct cbd_params* params,
|
pblk_read_wait(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev)
|
u64 pblk, u32 count, struct page** pagev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct bio* bio;
|
struct bio* bio;
|
||||||
|
|
||||||
bio = pblk_io_prepare(params->priv, REQ_OP_READ, pblk, count, pagev);
|
bio = pblk_io_prepare(kparams->dev, REQ_OP_READ, pblk, count, pagev);
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
printk(KERN_ERR "%s: out of memory\n", __func__);
|
printk(KERN_ERR "%s: out of memory\n", __func__);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -144,13 +144,13 @@ pblk_read_wait(struct cbd_params* params,
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
pblk_write_wait(struct cbd_params* params,
|
pblk_write_wait(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev)
|
u64 pblk, u32 count, struct page** pagev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct bio* bio;
|
struct bio* bio;
|
||||||
|
|
||||||
bio = pblk_io_prepare(params->priv, REQ_OP_WRITE, pblk, count, pagev);
|
bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE, pblk, count, pagev);
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
printk(KERN_ERR "%s: out of memory\n", __func__);
|
printk(KERN_ERR "%s: out of memory\n", __func__);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -158,7 +158,7 @@ pblk_write_wait(struct cbd_params* params,
|
||||||
ret = submit_bio_wait(bio);
|
ret = submit_bio_wait(bio);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: submit_bio_wait failed: %d\n", __func__, ret);
|
printk(KERN_ERR "%s: submit_bio_wait failed: %d\n", __func__, ret);
|
||||||
params->flags |= CBD_FLAG_ERROR;
|
kparams->params.flags |= CBD_FLAG_ERROR;
|
||||||
}
|
}
|
||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
|
|
||||||
|
@ -168,13 +168,13 @@ pblk_write_wait(struct cbd_params* params,
|
||||||
void
|
void
|
||||||
pblk_write_endio(struct bio* bio)
|
pblk_write_endio(struct bio* bio)
|
||||||
{
|
{
|
||||||
struct cbd_params* params = bio->bi_private;
|
struct compress_params* kparams = bio->bi_private;
|
||||||
u32 n;
|
u32 n;
|
||||||
struct page* page;
|
struct page* page;
|
||||||
|
|
||||||
BUG_ON(!bio);
|
BUG_ON(!bio);
|
||||||
if (bio->bi_status != BLK_STS_OK) {
|
if (bio->bi_status != BLK_STS_OK) {
|
||||||
params->flags |= CBD_FLAG_ERROR;
|
kparams->params.flags |= CBD_FLAG_ERROR;
|
||||||
for (n = 0; n < bio->bi_max_vecs; ++n) {
|
for (n = 0; n < bio->bi_max_vecs; ++n) {
|
||||||
page = bio->bi_io_vec[n].bv_page;
|
page = bio->bi_io_vec[n].bv_page;
|
||||||
SetPageError(page);
|
SetPageError(page);
|
||||||
|
@ -189,16 +189,16 @@ pblk_write_endio(struct bio* bio)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pblk_write(struct cbd_params* params,
|
pblk_write(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev)
|
u64 pblk, u32 count, struct page** pagev)
|
||||||
{
|
{
|
||||||
struct bio* bio;
|
struct bio* bio;
|
||||||
u32 n;
|
u32 n;
|
||||||
|
|
||||||
bio = pblk_io_prepare(params->priv, REQ_OP_WRITE, pblk, count, pagev);
|
bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE, pblk, count, pagev);
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
printk(KERN_ERR "%s: out of memory\n", __func__);
|
printk(KERN_ERR "%s: out of memory\n", __func__);
|
||||||
params->flags |= CBD_FLAG_ERROR;
|
kparams->params.flags |= CBD_FLAG_ERROR;
|
||||||
for (n = 0; n < count; ++n) {
|
for (n = 0; n < count; ++n) {
|
||||||
SetPageError(pagev[n]);
|
SetPageError(pagev[n]);
|
||||||
unlock_page(pagev[n]);
|
unlock_page(pagev[n]);
|
||||||
|
@ -206,7 +206,7 @@ pblk_write(struct cbd_params* params,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bio->bi_end_io = pblk_write_endio;
|
bio->bi_end_io = pblk_write_endio;
|
||||||
bio->bi_private = params;
|
bio->bi_private = kparams;
|
||||||
|
|
||||||
submit_bio(bio);
|
submit_bio(bio);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
@ -34,14 +35,12 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static inline void __attribute__((noreturn))
|
extern uint verbose_level;
|
||||||
error(const char* fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
void __attribute__((noreturn))
|
||||||
vfprintf(stderr, fmt, ap);
|
error(const char* fmt, ...);
|
||||||
exit(EXIT_FAILURE);
|
int verbose(uint level, const char* fmt, ...);
|
||||||
}
|
|
||||||
|
bool ask_user_bool(const char* fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -62,7 +62,8 @@ int cbd_stats(const char* dev, struct cbd_stats* stats);
|
||||||
|
|
||||||
int cbd_check(const char* dev,
|
int cbd_check(const char* dev,
|
||||||
bool force,
|
bool force,
|
||||||
tristate_t auto_response);
|
tristate_t auto_response,
|
||||||
|
bool full_check);
|
||||||
int cbd_resize(const char* dev,
|
int cbd_resize(const char* dev,
|
||||||
uint64_t lsize);
|
uint64_t lsize);
|
||||||
|
|
||||||
|
|
|
@ -48,11 +48,11 @@ struct cbd_params {
|
||||||
u64 nr_pblk;
|
u64 nr_pblk;
|
||||||
u32 nr_zones;
|
u32 nr_zones;
|
||||||
u32 lblk_per_zone;
|
u32 lblk_per_zone;
|
||||||
void* priv;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cbd_stats {
|
struct cbd_stats {
|
||||||
u64 pblk_alloc;
|
u64 pblk_alloc;
|
||||||
|
u64 lblk_alloc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cbd_header {
|
struct cbd_header {
|
||||||
|
@ -352,6 +352,7 @@ cbd_header_get(const u8* buf, struct cbd_header* header)
|
||||||
header->params.lblk_per_zone = get32_le(&buf);
|
header->params.lblk_per_zone = get32_le(&buf);
|
||||||
buf += 32; /* Reserved */
|
buf += 32; /* Reserved */
|
||||||
header->stats.pblk_alloc = get64_le(&buf);
|
header->stats.pblk_alloc = get64_le(&buf);
|
||||||
|
header->stats.lblk_alloc = get64_le(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -370,6 +371,7 @@ cbd_header_put(u8* buf, const struct cbd_header* header)
|
||||||
put32_le(&buf, header->params.lblk_per_zone);
|
put32_le(&buf, header->params.lblk_per_zone);
|
||||||
buf += 32; /* Reserved */
|
buf += 32; /* Reserved */
|
||||||
put64_le(&buf, header->stats.pblk_alloc);
|
put64_le(&buf, header->stats.pblk_alloc);
|
||||||
|
put64_le(&buf, header->stats.lblk_alloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32
|
static inline u32
|
||||||
|
@ -509,6 +511,16 @@ lba_put(const struct cbd_params* params,
|
||||||
|
|
||||||
#define COMPRESS_FLUSH_DELAY (HZ / 10)
|
#define COMPRESS_FLUSH_DELAY (HZ / 10)
|
||||||
|
|
||||||
|
struct compress_params {
|
||||||
|
struct block_device* dev;
|
||||||
|
struct cbd_params params;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct compress_stats {
|
||||||
|
struct mutex lock;
|
||||||
|
struct cbd_stats stats;
|
||||||
|
};
|
||||||
|
|
||||||
typedef void (*pblk_endio_t)(struct bio*);
|
typedef void (*pblk_endio_t)(struct bio*);
|
||||||
|
|
||||||
/* Single page allocator */
|
/* Single page allocator */
|
||||||
|
@ -524,11 +536,11 @@ bool cbd_alloc_pagev(struct page** pagev, size_t len);
|
||||||
void cbd_free_pagev(struct page** pagev, size_t len);
|
void cbd_free_pagev(struct page** pagev, size_t len);
|
||||||
|
|
||||||
/* Core low-level I/O */
|
/* Core low-level I/O */
|
||||||
int pblk_read_wait(struct cbd_params* params,
|
int pblk_read_wait(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev);
|
u64 pblk, u32 count, struct page** pagev);
|
||||||
int pblk_write_wait(struct cbd_params* params,
|
int pblk_write_wait(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev);
|
u64 pblk, u32 count, struct page** pagev);
|
||||||
void pblk_write(struct cbd_params* params,
|
void pblk_write(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev);
|
u64 pblk, u32 count, struct page** pagev);
|
||||||
|
|
||||||
struct pbat;
|
struct pbat;
|
||||||
|
@ -539,7 +551,7 @@ int pbat_free(struct pbat* pbat, u64 pblk);
|
||||||
struct pbatcache;
|
struct pbatcache;
|
||||||
size_t pbatcache_size(void);
|
size_t pbatcache_size(void);
|
||||||
bool pbatcache_ctr(struct pbatcache* pbatcache,
|
bool pbatcache_ctr(struct pbatcache* pbatcache,
|
||||||
struct cbd_params* params, u32 cache_pages);
|
struct compress_params* kparams, u32 cache_pages);
|
||||||
void pbatcache_dtr(struct pbatcache* pbatcache);
|
void pbatcache_dtr(struct pbatcache* pbatcache);
|
||||||
struct pbat*
|
struct pbat*
|
||||||
pbatcache_get(struct pbatcache* pbatcache, u32 zone, bool avail);
|
pbatcache_get(struct pbatcache* pbatcache, u32 zone, bool avail);
|
||||||
|
@ -553,21 +565,22 @@ void lbatpage_put_buf(struct lbatpage* lp);
|
||||||
struct lbatpagecache;
|
struct lbatpagecache;
|
||||||
size_t lbatpagecache_size(void);
|
size_t lbatpagecache_size(void);
|
||||||
bool lbatpagecache_ctr(struct lbatpagecache* lpc,
|
bool lbatpagecache_ctr(struct lbatpagecache* lpc,
|
||||||
struct cbd_params* params, u32 cache_pages);
|
struct compress_params* kparams, u32 cache_pages);
|
||||||
void lbatpagecache_dtr(struct lbatpagecache* lpc);
|
void lbatpagecache_dtr(struct lbatpagecache* lpc);
|
||||||
struct lbatpage*
|
struct lbatpage*
|
||||||
lbatpagecache_get(struct lbatpagecache* lpc, u64 pblk);
|
lbatpagecache_get(struct lbatpagecache* lpc, u64 pblk);
|
||||||
int lbatpagecache_put(struct lbatpagecache* lpc, struct lbatpage* lpi);
|
int lbatpagecache_put(struct lbatpagecache* lpc, struct lbatpage* lpi);
|
||||||
|
|
||||||
struct lbatview;
|
struct lbatview;
|
||||||
int lbatview_elem_realloc(struct lbatview* lv, u64 lblk, u32 len, struct cbd_stats* stats);
|
int lbatview_elem_realloc(struct lbatview* lv, u64 lblk, u32 len);
|
||||||
u32 lbatview_elem_len(struct lbatview* lv, u64 lblk);
|
u32 lbatview_elem_len(struct lbatview* lv, u64 lblk);
|
||||||
u64 lbatview_elem_pblk(struct lbatview* lv, u64 lblk, u32 idx);
|
u64 lbatview_elem_pblk(struct lbatview* lv, u64 lblk, u32 idx);
|
||||||
|
|
||||||
struct lbatviewcache;
|
struct lbatviewcache;
|
||||||
size_t lbatviewcache_size(void);
|
size_t lbatviewcache_size(void);
|
||||||
bool lbatviewcache_ctr(struct lbatviewcache* lvc,
|
bool lbatviewcache_ctr(struct lbatviewcache* lvc,
|
||||||
struct cbd_params* params, u32 cache_pages);
|
struct compress_params* kparams, struct compress_stats* kstats,
|
||||||
|
u32 cache_pages);
|
||||||
void lbatviewcache_dtr(struct lbatviewcache* lvc);
|
void lbatviewcache_dtr(struct lbatviewcache* lvc);
|
||||||
struct lbatview*
|
struct lbatview*
|
||||||
lbatviewcache_get(struct lbatviewcache* lvc, u64 lblk);
|
lbatviewcache_get(struct lbatviewcache* lvc, u64 lblk);
|
||||||
|
@ -581,7 +594,7 @@ void lbd_data_write(struct lbd* lbd, u32 off, u32 len, const u8* buf);
|
||||||
struct lbdcache;
|
struct lbdcache;
|
||||||
size_t lbdcache_size(void);
|
size_t lbdcache_size(void);
|
||||||
bool lbdcache_ctr(struct lbdcache* lc,
|
bool lbdcache_ctr(struct lbdcache* lc,
|
||||||
struct cbd_params* params, struct cbd_stats* stats,
|
struct compress_params* kparams, struct compress_stats* kstats,
|
||||||
u32 cache_pages);
|
u32 cache_pages);
|
||||||
void lbdcache_dtr(struct lbdcache* lc);
|
void lbdcache_dtr(struct lbdcache* lc);
|
||||||
struct lbd*
|
struct lbd*
|
||||||
|
|
464
libcbd/check.c
464
libcbd/check.c
|
@ -2,10 +2,37 @@
|
||||||
|
|
||||||
#include <cbdutil.h>
|
#include <cbdutil.h>
|
||||||
|
|
||||||
struct zone_metadata
|
#include <lz4.h>
|
||||||
|
/* XXX */
|
||||||
|
typedef off_t off64_t;
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Problem:
|
||||||
|
* - Memory usage is rather high (1.5gb for 700gb device).
|
||||||
|
* - Startup is quite long.
|
||||||
|
* Fix:
|
||||||
|
* - Do not read lbat at start, read in check_lbat().
|
||||||
|
* - Do not read pbat at start, read in check_pbat().
|
||||||
|
*
|
||||||
|
* Update stats as we go (pblk_alloc etc.)
|
||||||
|
*
|
||||||
|
* With the above, struct zone_metadata name is not really accurate.
|
||||||
|
* Name it something else, like...???
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct check_state
|
||||||
{
|
{
|
||||||
u8* pbat;
|
int fd;
|
||||||
u8* lbat;
|
bool check_lblk_data;
|
||||||
|
bool clean;
|
||||||
|
u64 pblk_alloc;
|
||||||
|
u64 lblk_alloc;
|
||||||
|
u8** pbatv;
|
||||||
|
|
||||||
|
u8* compress_buf;
|
||||||
|
u8* lz4_workmem;
|
||||||
|
z_stream zlib_dstream;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -31,6 +58,53 @@ pblk_read(int fd, u64 pblk, u32 count, u8* data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pblk_write(int fd, u64 pblk, u32 count, const u8* data)
|
||||||
|
{
|
||||||
|
off_t pos;
|
||||||
|
size_t remain;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
pos = lseek(fd, pblk * PBLK_SIZE, SEEK_SET);
|
||||||
|
if (pos == (off_t)-1) {
|
||||||
|
error("Failed to seek\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
remain = count * PBLK_SIZE;
|
||||||
|
while (remain) {
|
||||||
|
ret = write(fd, data, remain);
|
||||||
|
if (ret <= 0) {
|
||||||
|
error("Failed to write\n");
|
||||||
|
}
|
||||||
|
remain -= ret;
|
||||||
|
data += ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
check_header(const struct cbd_header* header)
|
check_header(const struct cbd_header* header)
|
||||||
{
|
{
|
||||||
|
@ -56,180 +130,330 @@ check_header(const struct cbd_header* header)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static bool
|
||||||
check_one_lblk(const struct cbd_params* params,
|
check_decompress_lz4(struct check_state* state, const struct cbd_params* params, u8* buf, u32 clen)
|
||||||
u32 zone,
|
|
||||||
u32 lblk,
|
|
||||||
const struct zone_metadata* zm,
|
|
||||||
u8** pblk_used)
|
|
||||||
{
|
{
|
||||||
struct lba* lba;
|
int ret;
|
||||||
u8* lba_buf;
|
u32 dlen = PBLK_SIZE * lblk_per_pblk(params);
|
||||||
|
|
||||||
|
ret = LZ4_decompress_safe((const char*)buf, (char*)state->compress_buf, clen, dlen);
|
||||||
|
if (ret != dlen) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
check_decompress_zlib(struct check_state* state, const struct cbd_params* params, u8* buf, u32 clen)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
z_stream* stream;
|
||||||
|
u32 dlen = PBLK_SIZE * lblk_per_pblk(params);
|
||||||
|
|
||||||
|
stream = &state->zlib_dstream;
|
||||||
|
ret = inflateReset(stream);
|
||||||
|
assert(ret == Z_OK);
|
||||||
|
stream->next_in = buf;
|
||||||
|
stream->avail_in = clen;
|
||||||
|
stream->next_out = state->compress_buf;
|
||||||
|
stream->avail_out = dlen;
|
||||||
|
ret = inflate(stream, Z_SYNC_FLUSH);
|
||||||
|
if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
|
||||||
|
u8 zerostuff = 0;
|
||||||
|
stream->next_in = &zerostuff;
|
||||||
|
stream->avail_in = 1;
|
||||||
|
ret = inflate(stream, Z_FINISH);
|
||||||
|
}
|
||||||
|
if (ret != Z_STREAM_END || stream->total_out != dlen) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
check_decompress(struct check_state* state, const struct cbd_params* params, u8* buf, u32 clen)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
switch (params->algorithm) {
|
||||||
|
case CBD_ALG_LZ4:
|
||||||
|
ret = check_decompress_lz4(state, params, buf, clen);
|
||||||
|
break;
|
||||||
|
case CBD_ALG_ZLIB:
|
||||||
|
ret = check_decompress_zlib(state, params, buf, clen);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
check_lblk_data(struct check_state* state,
|
||||||
|
const struct cbd_params* params,
|
||||||
|
u64 lblk, u8* lba)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
u8* data;
|
||||||
|
u8* buf;
|
||||||
|
u32 len;
|
||||||
u32 n_alloc;
|
u32 n_alloc;
|
||||||
u32 n;
|
u32 n;
|
||||||
u64 pblk;
|
u64 pblk;
|
||||||
|
|
||||||
lba = calloc(1, offsetof(struct lba, pblk[lblk_per_pblk(params)]));
|
data = calloc(PBLK_SIZE, lblk_per_pblk(params));
|
||||||
lba_buf = zm->lbat + lblk * lba_len(params);
|
buf = lba;
|
||||||
lba_get(params, lba_buf, lba);
|
len = lba_len_get(params, buf);
|
||||||
if (lba->len) {
|
if (len == 0 || len == CBD_UNCOMPRESSED) {
|
||||||
if (lba->len == CBD_UNCOMPRESSED) {
|
return true;
|
||||||
printf(" lblk[%u]: UNCOMPRESSED\n", lblk);
|
}
|
||||||
}
|
n_alloc = DIV_ROUND_UP(len, PBLK_SIZE);
|
||||||
else {
|
for (n = 0; n < n_alloc; ++n) {
|
||||||
printf(" lblk[%u]: len=%u\n", lblk, lba->len);
|
pblk = lba_pblk_get(params, buf, n);
|
||||||
|
pblk_read(state->fd, pblk, 1, data + n * PBLK_SIZE);
|
||||||
|
}
|
||||||
|
ret = check_decompress(state, params, data, len);
|
||||||
|
free(data);
|
||||||
|
if (!ret) {
|
||||||
|
if (ask_user_bool("lblk %u: failed to decompress. Clear?", lblk)) {
|
||||||
|
memset(lba, 0, lba_len(params));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
state->clean = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
check_lblk_alloc(struct check_state* state,
|
||||||
|
const struct cbd_params* params,
|
||||||
|
u64 lblk, u8* lba)
|
||||||
|
{
|
||||||
|
u8* buf = lba;
|
||||||
|
u32 len;
|
||||||
|
u32 n_alloc;
|
||||||
|
u32 n;
|
||||||
|
u64 pblk;
|
||||||
|
u32 pblk_zone;
|
||||||
|
u32 pblk_off;
|
||||||
|
|
||||||
|
len = lba_len_get(params, buf);
|
||||||
|
if (!len) {
|
||||||
|
verbose(2, " lblk[%u]: EMPTY\n", lblk);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (len == CBD_UNCOMPRESSED) {
|
||||||
|
verbose(2, " lblk[%u]: UNCOMPRESSED\n", lblk);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf(" lblk[%u]: EMPTY\n", lblk);
|
verbose(2, " lblk[%u]: len=%u\n", lblk, len);
|
||||||
}
|
}
|
||||||
if (lba->len > PBLK_SIZE * lblk_per_pblk(params)) {
|
if (len > PBLK_SIZE * lblk_per_pblk(params)) {
|
||||||
printf(" :E: Length out of bounds\n");
|
if (ask_user_bool("lblk %u: length %u out of bounds. Clear?", lblk, len)) {
|
||||||
return;
|
memset(lba, 0, lba_len(params));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
state->clean = false;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
n_alloc = (lba->len == CBD_UNCOMPRESSED) ?
|
n_alloc = (len == CBD_UNCOMPRESSED) ?
|
||||||
lblk_per_pblk(params) :
|
lblk_per_pblk(params) :
|
||||||
DIV_ROUND_UP(lba->len, PBLK_SIZE);
|
DIV_ROUND_UP(len, PBLK_SIZE);
|
||||||
for (n = 0; n < n_alloc; ++n) {
|
for (n = 0; n < n_alloc; ++n) {
|
||||||
u32 pblk_zone;
|
pblk = lba_pblk_get(params, buf, n);
|
||||||
u32 rel_pblk;
|
|
||||||
pblk = lba->pblk[n];
|
|
||||||
if (pblk < CBD_HEADER_BLOCKS) {
|
if (pblk < CBD_HEADER_BLOCKS) {
|
||||||
printf(" [%u] :E: Alloc in header: %lu\n", n, pblk);
|
verbose(2, " [%u] :E: Alloc in header: %lu\n", n, pblk);
|
||||||
|
if (ask_user_bool("lblk %u: alloc %u in header. Clear?", lblk, n)) {
|
||||||
|
memset(lba, 0, lba_len(params));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
state->clean = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pblk_zone = (pblk - CBD_HEADER_BLOCKS) / zone_len(params);
|
pblk_zone = zone_for_pblk(params, pblk);
|
||||||
if (pblk_zone >= params->nr_zones) {
|
if (pblk_zone == ZONE_NONE || pblk_zone >= params->nr_zones) {
|
||||||
printf(" [%u] :E: Alloc beyond end: %lu\n", n, pblk);
|
verbose(2, " [%u] :E: Alloc beyond end: %lu\n", n, pblk);
|
||||||
|
if (ask_user_bool("lblk %u: alloc %u beyond end. Clear?", lblk, n)) {
|
||||||
|
memset(lba, 0, lba_len(params));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
state->clean = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pblk < zone_data_off(params, pblk_zone)) {
|
if (pblk < zone_data_off(params, pblk_zone)) {
|
||||||
printf(" [%u] :E: Alloc in metadata: %lu\n", n, pblk);
|
verbose(2, " [%u] :E: Alloc in metadata: %lu\n", n, pblk);
|
||||||
|
if (ask_user_bool("lblk %u alloc in medatada. Clear?", lblk)) {
|
||||||
|
memset(lba, 0, lba_len(params));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
state->clean = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
rel_pblk = pblk - zone_data_off(params, pblk_zone);
|
pblk_off = pblk - zone_data_off(params, pblk_zone);
|
||||||
/* XXX: Cannot happen? */
|
verbose(3, " [%u] pblk=%lu\n", n, (unsigned long)pblk);
|
||||||
if (rel_pblk >= pbat_len(params) * PBLK_SIZE_BITS) {
|
if (cbd_bitmap_isset(state->pbatv[pblk_zone], pblk_off)) {
|
||||||
printf(" [%u] :E: Alloc out of zone: %lu\n", n, pblk);
|
verbose(2, " [%u] :E: Duplicate allocation for pblk %lu\n", n, (unsigned long)pblk);
|
||||||
|
if (ask_user_bool("lblk %u duplicate alloc for pblk %lu. Clear?", lblk, pblk)) {
|
||||||
|
memset(lba, 0, lba_len(params));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
state->clean = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
printf(" [%u] pblk=%lu pblk_zone=%u rel_pblk=%u\n", n,
|
cbd_bitmap_set(state->pbatv[pblk_zone], pblk_off);
|
||||||
(unsigned long)pblk, pblk_zone, rel_pblk);
|
|
||||||
if (pblk_used[pblk_zone][rel_pblk/8] & (1 << (rel_pblk % 8))) {
|
|
||||||
printf(" [%u] :E: Duplicate allocation for zone %u block %u\n",
|
|
||||||
n, pblk_zone, rel_pblk);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pblk_used[pblk_zone][rel_pblk/8] |= (1 << (rel_pblk % 8));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(lba);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
check_one_zone(const struct cbd_params* params,
|
check_lbat(struct check_state* state, const struct cbd_params* params)
|
||||||
u32 zone,
|
|
||||||
const struct zone_metadata* zm,
|
|
||||||
u8** pblk_used)
|
|
||||||
{
|
{
|
||||||
u32 lblk_alloc_len;
|
|
||||||
u32 n;
|
|
||||||
bool zone_empty;
|
|
||||||
u32 lblk;
|
|
||||||
|
|
||||||
printf("Zone %u: lbat=[%lu..%lu] alloc=[%lu .. %lu]\n",
|
|
||||||
(unsigned int)zone,
|
|
||||||
(unsigned long)zone_off(params, zone),
|
|
||||||
(unsigned long)(zone_data_off(params, zone) - 1),
|
|
||||||
(unsigned long)zone_data_off(params, zone),
|
|
||||||
(unsigned long)zone_off(params, zone + 1));
|
|
||||||
zone_empty = true;
|
|
||||||
lblk_alloc_len = params->lblk_per_zone * lba_len(params);
|
|
||||||
for (n = 0; n < lblk_alloc_len; ++n) {
|
|
||||||
if (zm->lbat[n]) {
|
|
||||||
zone_empty = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (zone_empty) {
|
|
||||||
printf(" [empty]\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (lblk = 0; lblk < params->lblk_per_zone; ++lblk) {
|
|
||||||
check_one_lblk(params, zone, lblk, zm, pblk_used);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
check_zone_metadata(const struct cbd_params* params,
|
|
||||||
const struct zone_metadata* zmvec)
|
|
||||||
{
|
|
||||||
u8** pblk_used;
|
|
||||||
u32 zone;
|
u32 zone;
|
||||||
|
|
||||||
pblk_used = calloc(params->nr_zones, sizeof(void*));
|
|
||||||
for (zone = 0; zone < params->nr_zones; ++zone) {
|
for (zone = 0; zone < params->nr_zones; ++zone) {
|
||||||
pblk_used[zone] = calloc(pbat_len(params), PBLK_SIZE);
|
u8* lbat = calloc(PBLK_SIZE, lbat_len(params));
|
||||||
}
|
bool zone_empty = true;
|
||||||
|
bool changed = false;
|
||||||
|
u32 n;
|
||||||
|
|
||||||
for (zone = 0; zone < params->nr_zones; ++zone) {
|
lbat_read(state->fd, params, zone, lbat);
|
||||||
check_one_zone(params, zone, &zmvec[zone], pblk_used);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (zone = 0; zone < params->nr_zones; ++zone) {
|
verbose(2, "Zone %u: lbat=[%lu..%lu] alloc=[%lu .. %lu]\n",
|
||||||
free(pblk_used[zone]);
|
(unsigned int)zone,
|
||||||
|
(unsigned long)zone_off(params, zone),
|
||||||
|
(unsigned long)(zone_data_off(params, zone) - 1),
|
||||||
|
(unsigned long)zone_data_off(params, zone),
|
||||||
|
(unsigned long)zone_off(params, zone + 1));
|
||||||
|
for (n = 0; n < params->lblk_per_zone; ++n) {
|
||||||
|
u8* buf = lbat + n * lba_len(params);
|
||||||
|
if (lba_len_get(params, buf) != 0) {
|
||||||
|
zone_empty = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (zone_empty) {
|
||||||
|
verbose(2, " [empty]\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (n = 0; n < params->lblk_per_zone; ++n) {
|
||||||
|
u64 lblk = zone * params->lblk_per_zone + n;
|
||||||
|
u8* buf = lbat + n * lba_len(params);
|
||||||
|
u32 len;
|
||||||
|
if (check_lblk_alloc(state, params, lblk, buf)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (state->check_lblk_data) {
|
||||||
|
if (check_lblk_data(state, params, lblk, buf)) {
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len = lba_len_get(params, buf);
|
||||||
|
if (len != 0) {
|
||||||
|
++state->lblk_alloc;
|
||||||
|
state->pblk_alloc += DIV_ROUND_UP(len, PBLK_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
lbat_write(state->fd, params, zone, lbat);
|
||||||
|
}
|
||||||
|
free(lbat);
|
||||||
}
|
}
|
||||||
free(pblk_used);
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_pbat(struct check_state* state, const struct cbd_params* params)
|
||||||
|
{
|
||||||
|
u32 zone;
|
||||||
|
u8* pbat;
|
||||||
|
|
||||||
|
pbat = malloc(PBLK_SIZE * 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 (ask_user_bool("zone %u has incorrect pbat. Fix?", zone)) {
|
||||||
|
memcpy(pbat, state->pbatv[zone], PBLK_SIZE * pbat_len(params));
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state->clean = false;
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
pbat_write(state->fd, params, zone, state->pbatv[zone]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(pbat);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cbd_check(const char* dev,
|
cbd_check(const char* dev,
|
||||||
bool force,
|
bool force,
|
||||||
tristate_t auto_response)
|
tristate_t auto_response,
|
||||||
|
bool full_check)
|
||||||
{
|
{
|
||||||
int devfd;
|
struct check_state state;
|
||||||
struct cbd_header header;
|
struct cbd_header header;
|
||||||
uint8_t pblkbuf[PBLK_SIZE];
|
uint8_t pblkbuf[PBLK_SIZE];
|
||||||
struct zone_metadata* zmvec;
|
u32 n;
|
||||||
u32 zone;
|
|
||||||
|
|
||||||
devfd = open(dev, O_RDONLY);
|
memset(&state, 0, sizeof(state));
|
||||||
if (devfd < 0) {
|
state.fd = open(dev, O_RDWR);
|
||||||
|
if (state.fd < 0) {
|
||||||
error("Cannot open device\n");
|
error("Cannot open device\n");
|
||||||
}
|
}
|
||||||
|
state.check_lblk_data = full_check;
|
||||||
|
state.clean = true;
|
||||||
|
|
||||||
pblk_read(devfd, 0, 1, pblkbuf);
|
verbose(1, "Reading header\n");
|
||||||
|
pblk_read(state.fd, 0, 1, pblkbuf);
|
||||||
cbd_header_get(pblkbuf, &header);
|
cbd_header_get(pblkbuf, &header);
|
||||||
|
verbose(1, "Checking header\n");
|
||||||
check_header(&header);
|
check_header(&header);
|
||||||
if (!force && !(header.params.flags & CBD_FLAG_DIRTY)) {
|
if (!force && !(header.params.flags & CBD_FLAG_DIRTY)) {
|
||||||
printf("%s: clean\n", dev);
|
printf("%s: clean\n", dev);
|
||||||
close(devfd);
|
close(state.fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
zmvec = calloc(header.params.nr_zones, sizeof(struct zone_metadata));
|
state.pbatv = calloc(header.params.nr_zones, sizeof(u8*));
|
||||||
for (zone = 0; zone < header.params.nr_zones; ++zone) {
|
for (n = 0; n < header.params.nr_zones; ++n) {
|
||||||
zmvec[zone].pbat = calloc(pbat_len(&header.params), PBLK_SIZE);
|
state.pbatv[n] = calloc(PBLK_SIZE, pbat_len(&header.params));
|
||||||
pblk_read(devfd,
|
|
||||||
pbat_off(&header.params, zone),
|
|
||||||
pbat_len(&header.params),
|
|
||||||
zmvec[zone].pbat);
|
|
||||||
zmvec[zone].lbat = calloc(lbat_len(&header.params), PBLK_SIZE);
|
|
||||||
pblk_read(devfd,
|
|
||||||
lbat_off(&header.params, zone),
|
|
||||||
lbat_len(&header.params),
|
|
||||||
zmvec[zone].lbat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check_zone_metadata(&header.params, zmvec);
|
verbose(1, "Checking lbat\n");
|
||||||
|
check_lbat(&state, &header.params);
|
||||||
|
verbose(1, "Checking pbat\n");
|
||||||
|
check_pbat(&state, &header.params);
|
||||||
|
|
||||||
for (zone = 0; zone < header.params.nr_zones; ++zone) {
|
for (n = 0; n < header.params.nr_zones; ++n) {
|
||||||
free(zmvec[zone].lbat);
|
free(state.pbatv[n]);
|
||||||
free(zmvec[zone].pbat);
|
|
||||||
}
|
}
|
||||||
free(zmvec);
|
free(state.pbatv);
|
||||||
|
|
||||||
close(devfd);
|
if (state.clean) {
|
||||||
|
if (state.pblk_alloc != header.stats.pblk_alloc) {
|
||||||
|
verbose(1, "pblk alloc incorrect (%lu expected, %lu found), fixing\n",
|
||||||
|
(unsigned long)state.pblk_alloc,
|
||||||
|
(unsigned long)header.stats.pblk_alloc);
|
||||||
|
header.stats.pblk_alloc = state.pblk_alloc;
|
||||||
|
}
|
||||||
|
if (state.lblk_alloc != header.stats.lblk_alloc) {
|
||||||
|
verbose(1, "lblk alloc incorrect (%lu expected, %lu found), fixing\n",
|
||||||
|
(unsigned long)state.lblk_alloc,
|
||||||
|
(unsigned long)header.stats.lblk_alloc);
|
||||||
|
header.stats.lblk_alloc = state.lblk_alloc;
|
||||||
|
}
|
||||||
|
header.params.flags &= ~(CBD_FLAG_ERROR | CBD_FLAG_DIRTY);
|
||||||
|
cbd_header_put(pblkbuf, &header);
|
||||||
|
pblk_write(state.fd, 0, 1, pblkbuf);
|
||||||
|
}
|
||||||
|
close(state.fd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
#include <libcbd.h>
|
||||||
|
|
||||||
|
#include <cbdutil.h>
|
||||||
|
|
||||||
|
uint verbose_level;
|
||||||
|
|
||||||
|
void __attribute__((noreturn))
|
||||||
|
error(const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
verbose(uint level, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (verbose_level >= level) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vprintf(fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ask_user_bool(const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
char* line = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
int ret;
|
||||||
|
bool answer;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
again:
|
||||||
|
vprintf(fmt, ap);
|
||||||
|
printf(" [y/n]? ");
|
||||||
|
getline(&line, &len, stdin);
|
||||||
|
if (ret > 0) {
|
||||||
|
switch (line[0]) {
|
||||||
|
case 'y':
|
||||||
|
case 'Y':
|
||||||
|
answer = true;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
case 'N':
|
||||||
|
answer = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
if (ret <= 0) {
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
return answer;
|
||||||
|
}
|
Loading…
Reference in New Issue