Compare commits
1 Commits
90a76a5764
...
6e92d5071a
Author | SHA1 | Date |
---|---|---|
Tom Marshall | 6e92d5071a |
9
README
9
README
|
@ -14,11 +14,14 @@ Block device layout:
|
||||||
- u16 version_minor
|
- u16 version_minor
|
||||||
/* Offset 8: parameters */
|
/* Offset 8: parameters */
|
||||||
- u16 flags
|
- u16 flags
|
||||||
- u8 algorithm (1=lz4, 2=zlib, ...) [1]
|
- u8 compression
|
||||||
- u8 compression (1..9) [1]
|
hi nybble: algorithm (1=lz4, 2=zlib, ...) [1]
|
||||||
|
lo nybble: level (1..9) [1]
|
||||||
- u8 pblk_shift (0..3) [3 = 4kb]
|
- u8 pblk_shift (0..3) [3 = 4kb]
|
||||||
- u8 lblk_shift (1..10) [4 = 64kb (*)]
|
- u8 lblk_shift (1..10) [4 = 64kb (*)]
|
||||||
- u16 pbat_len [1]
|
- u8 lba_elem_pblk_bytes (2, 4, 6)
|
||||||
|
- u8 pbat_shift [0]
|
||||||
|
- u8 pad
|
||||||
- u32 nr_zones
|
- u32 nr_zones
|
||||||
- u32 lblk_per_zone
|
- u32 lblk_per_zone
|
||||||
- byte[40] reserved
|
- byte[40] reserved
|
||||||
|
|
15
cbd/cbd.c
15
cbd/cbd.c
|
@ -131,7 +131,7 @@ usage(void)
|
||||||
"\n");
|
"\n");
|
||||||
fprintf(stderr, "Commands:\n"
|
fprintf(stderr, "Commands:\n"
|
||||||
" format [opts] <device> Create (format) a compressed device\n"
|
" format [opts] <device> Create (format) a compressed device\n"
|
||||||
" -P --pbat-len Physical block allocation table length [1]\n"
|
" -P --pbat-size Physical block allocation table size [1]\n"
|
||||||
" -S --pysical-size Physical size [device size]\n"
|
" -S --pysical-size Physical size [device size]\n"
|
||||||
" -c --compress-factor Compression factor [2.0]\n"
|
" -c --compress-factor Compression factor [2.0]\n"
|
||||||
" -l --logical-blksize Logical block size\n"
|
" -l --logical-blksize Logical block size\n"
|
||||||
|
@ -169,7 +169,7 @@ do_format(int argc, char** argv)
|
||||||
{
|
{
|
||||||
static const char short_opts[] = "P:S:c:l:p:s:z:Z:";
|
static const char short_opts[] = "P:S:c:l:p:s:z:Z:";
|
||||||
static const struct option long_opts[] = {
|
static const struct option long_opts[] = {
|
||||||
{ "pbat-len", required_argument, NULL, 'P' },
|
{ "pbat-size", required_argument, NULL, 'P' },
|
||||||
{ "physical-size", required_argument, NULL, 'S' },
|
{ "physical-size", required_argument, NULL, 'S' },
|
||||||
{ "compress-factor", required_argument, NULL, 'c' },
|
{ "compress-factor", required_argument, NULL, 'c' },
|
||||||
{ "logical-blksize", required_argument, NULL, 'l' },
|
{ "logical-blksize", required_argument, NULL, 'l' },
|
||||||
|
@ -186,12 +186,13 @@ do_format(int argc, char** argv)
|
||||||
uint64_t lsize = 0;
|
uint64_t lsize = 0;
|
||||||
uint pblksize = PAGE_SIZE;
|
uint pblksize = PAGE_SIZE;
|
||||||
uint lblksize = 16 * PAGE_SIZE;
|
uint lblksize = 16 * PAGE_SIZE;
|
||||||
uint16_t pbatlen = 1;
|
uint pbatsize = 1;
|
||||||
enum cbd_alg alg = CBD_ALG_LZ4;
|
enum cbd_alg alg = CBD_ALG_LZ4;
|
||||||
uint level = 1;
|
uint level = 1;
|
||||||
|
|
||||||
uint8_t pshift;
|
uint8_t pshift;
|
||||||
uint8_t lshift;
|
uint8_t lshift;
|
||||||
|
uint8_t pbatshift;
|
||||||
|
|
||||||
const char* dev;
|
const char* dev;
|
||||||
|
|
||||||
|
@ -204,7 +205,7 @@ do_format(int argc, char** argv)
|
||||||
if (optval < 1) {
|
if (optval < 1) {
|
||||||
error("Size \"%s\" is not a valid pbat len\n", optarg);
|
error("Size \"%s\" is not a valid pbat len\n", optarg);
|
||||||
}
|
}
|
||||||
pbatlen = optval;
|
pbatsize = optval;
|
||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
if (!parse_numeric_arg(optarg, &optval)) {
|
if (!parse_numeric_arg(optarg, &optval)) {
|
||||||
|
@ -277,12 +278,16 @@ do_format(int argc, char** argv)
|
||||||
if (lshift < LBLK_SHIFT_MIN || lshift > LBLK_SHIFT_MAX) {
|
if (lshift < LBLK_SHIFT_MIN || lshift > LBLK_SHIFT_MAX) {
|
||||||
error("Invalid logical block size %u\n", lblksize);
|
error("Invalid logical block size %u\n", lblksize);
|
||||||
}
|
}
|
||||||
|
pbatshift = get_shift(pbatsize, 1);
|
||||||
|
if (pbatshift < PBAT_SHIFT_MIN || pbatshift > PBAT_SHIFT_MAX) {
|
||||||
|
error("Invalid pbat len %u\n", pbatsize);
|
||||||
|
}
|
||||||
if (argc - optind != 1) {
|
if (argc - optind != 1) {
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
dev = argv[optind++];
|
dev = argv[optind++];
|
||||||
|
|
||||||
cbd_format(dev, pshift, lshift, pbatlen, alg, level, psize, lsize);
|
cbd_format(dev, alg, level, pshift, lshift, pbatshift, psize, lsize);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,25 +78,23 @@ static int
|
||||||
compress_read_header(struct compress* c)
|
compress_read_header(struct compress* c)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct page* pblkpage;
|
struct page* page;
|
||||||
u8 *pblkbuf;
|
u8 *buf;
|
||||||
struct page* iopagev[1];
|
|
||||||
struct cbd_header header;
|
struct cbd_header header;
|
||||||
|
|
||||||
pblkpage = cbd_alloc_page();
|
page = cbd_alloc_page();
|
||||||
if (!pblkpage) {
|
if (!page) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
pblkbuf = page_address(pblkpage);
|
buf = page_address(page);
|
||||||
iopagev[0] = pblkpage;
|
|
||||||
|
|
||||||
ret = pblk_read_wait(&c->kparams, 0, 1, iopagev);
|
ret = pblk_read_wait(&c->kparams, 0, 1, page);
|
||||||
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(buf, &header);
|
||||||
|
|
||||||
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__);
|
||||||
|
@ -158,13 +156,23 @@ compress_read_header(struct compress* c)
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (pbat_len(&header.params) * pblk_size(&header.params) > PAGE_SIZE) {
|
||||||
|
printk(KERN_ERR "%s: pbat size too large\n", __func__);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (lba_len(&header.params) > pblk_size(&header.params)) {
|
||||||
|
printk(KERN_ERR "%s: lba elem size too large\n", __func__);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
printk(KERN_INFO "%s: parameters...\n", __func__);
|
printk(KERN_INFO "%s: parameters...\n", __func__);
|
||||||
printk(KERN_INFO " compression=0x%02x\n", (unsigned int)header.params.compression);
|
printk(KERN_INFO " compression=0x%02x\n", (unsigned int)header.params.compression);
|
||||||
printk(KERN_INFO " pblk_shift=%hu\n", (unsigned short)header.params.pblk_shift);
|
printk(KERN_INFO " pblk_shift=%hu\n", (unsigned short)header.params.pblk_shift);
|
||||||
printk(KERN_INFO " lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift);
|
printk(KERN_INFO " lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift);
|
||||||
printk(KERN_INFO " lba_elem_pblk_bytes=%hu\n", (unsigned short)header.params.lba_elem_pblk_bytes);
|
printk(KERN_INFO " lba_elem_pblk_bytes=%hu\n", (unsigned short)header.params.lba_elem_pblk_bytes);
|
||||||
printk(KERN_INFO " pbat_len=%hu\n", (unsigned short)header.params.pbat_len);
|
printk(KERN_INFO " pbat_shift=%hu\n", (unsigned short)header.params.pbat_shift);
|
||||||
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);
|
||||||
printk(KERN_INFO "%s: stats...\n", __func__);
|
printk(KERN_INFO "%s: stats...\n", __func__);
|
||||||
|
@ -175,7 +183,7 @@ compress_read_header(struct compress* c)
|
||||||
memcpy(&c->kstats.stats, &header.stats, sizeof(header.stats));
|
memcpy(&c->kstats.stats, &header.stats, sizeof(header.stats));
|
||||||
|
|
||||||
out:
|
out:
|
||||||
cbd_free_page(pblkpage);
|
cbd_free_page(page);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,29 +191,27 @@ static int
|
||||||
compress_write_header(struct compress* c)
|
compress_write_header(struct compress* c)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct page* pblkpage;
|
struct page* page;
|
||||||
u8* pblkbuf;
|
u8* buf;
|
||||||
struct cbd_header header;
|
struct cbd_header header;
|
||||||
struct page* iopagev[1];
|
|
||||||
|
|
||||||
pblkpage = cbd_alloc_page();
|
page = cbd_alloc_page();
|
||||||
if (!pblkpage) {
|
if (!page) {
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
pblkbuf = page_address(pblkpage);
|
buf = page_address(page);
|
||||||
memset(&header, 0, sizeof(header));
|
memset(&header, 0, sizeof(header));
|
||||||
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->kparams.params, sizeof(header.params));
|
memcpy(&header.params, &c->kparams.params, sizeof(header.params));
|
||||||
memcpy(&header.stats, &c->kstats.stats, sizeof(header.stats));
|
memcpy(&header.stats, &c->kstats.stats, sizeof(header.stats));
|
||||||
cbd_header_put(pblkbuf, &header);
|
cbd_header_put(buf, &header);
|
||||||
iopagev[0] = pblkpage;
|
ret = pblk_write_wait(&c->kparams, 0, 1, page);
|
||||||
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__);
|
||||||
}
|
}
|
||||||
cbd_free_page(pblkpage);
|
cbd_free_page(page);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,9 @@ lbatpblk_ctr(struct lbatpblk* lp,
|
||||||
static void
|
static void
|
||||||
lbatpblk_dtr(struct lbatpblk* lp)
|
lbatpblk_dtr(struct lbatpblk* lp)
|
||||||
{
|
{
|
||||||
|
if (lp->page) {
|
||||||
|
lock_page(lp->page);
|
||||||
|
}
|
||||||
lp->buf = NULL;
|
lp->buf = NULL;
|
||||||
cbd_free_page(lp->page);
|
cbd_free_page(lp->page);
|
||||||
lp->page = NULL;
|
lp->page = NULL;
|
||||||
|
@ -84,7 +87,6 @@ static int
|
||||||
lbatpblk_flush(struct lbatpblk* lp)
|
lbatpblk_flush(struct lbatpblk* lp)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct page* iopagev[1];
|
|
||||||
|
|
||||||
mutex_lock(&lp->lock);
|
mutex_lock(&lp->lock);
|
||||||
if (!PageDirty(lp->page)) {
|
if (!PageDirty(lp->page)) {
|
||||||
|
@ -94,8 +96,7 @@ lbatpblk_flush(struct lbatpblk* lp)
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
iopagev[0] = lp->page;
|
pblk_write(lp->kparams, lp->pblk, 1, lp->page);
|
||||||
pblk_write(lp->kparams, lp->pblk, 1, iopagev);
|
|
||||||
mutex_unlock(&lp->lock);
|
mutex_unlock(&lp->lock);
|
||||||
mutex_lock(&lp->kstats->lock);
|
mutex_lock(&lp->kstats->lock);
|
||||||
++lp->kstats->lbatpblk_w;
|
++lp->kstats->lbatpblk_w;
|
||||||
|
@ -114,10 +115,9 @@ static int
|
||||||
lbatpblk_read(struct lbatpblk* lp)
|
lbatpblk_read(struct lbatpblk* lp)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct page* pagev[1];
|
|
||||||
|
|
||||||
pagev[0] = lp->page;
|
BUG_ON(lbatpblk_error(lp));
|
||||||
ret = pblk_read_wait(lp->kparams, lp->pblk, 1, pagev);
|
ret = pblk_read_wait(lp->kparams, lp->pblk, 1, lp->page);
|
||||||
mutex_lock(&lp->kstats->lock);
|
mutex_lock(&lp->kstats->lock);
|
||||||
++lp->kstats->lbatpblk_r;
|
++lp->kstats->lbatpblk_r;
|
||||||
mutex_unlock(&lp->kstats->lock);
|
mutex_unlock(&lp->kstats->lock);
|
||||||
|
|
|
@ -272,13 +272,11 @@ lbatview_elem_off(struct lbatview* lv, u64 lblk)
|
||||||
static void
|
static void
|
||||||
lbatview_rmem(struct lbatview* lv, u32 off, u32 len, void* buf)
|
lbatview_rmem(struct lbatview* lv, u32 off, u32 len, void* buf)
|
||||||
{
|
{
|
||||||
/* XXX: Convert below to a BUG_ON */
|
u32 pblk_len = pblk_size(&lv->kparams->params);
|
||||||
if (off + len > 2 * PAGE_SIZE) {
|
|
||||||
printk(KERN_ERR "%s: *** out of bounds\n", __func__);
|
BUG_ON(off + len > 2 * pblk_len);
|
||||||
return;
|
if (off < pblk_len && off + len > pblk_len) {
|
||||||
}
|
u32 len0 = pblk_len - off;
|
||||||
if (off < PAGE_SIZE && off + len > PAGE_SIZE) {
|
|
||||||
u32 len0 = PAGE_SIZE - off;
|
|
||||||
u8* pagebuf0 = lbatpblk_get_buf(lv->pages[0], false);
|
u8* pagebuf0 = lbatpblk_get_buf(lv->pages[0], false);
|
||||||
u8* pagebuf1 = lbatpblk_get_buf(lv->pages[1], false);
|
u8* pagebuf1 = lbatpblk_get_buf(lv->pages[1], false);
|
||||||
memcpy(buf, pagebuf0 + off, len0);
|
memcpy(buf, pagebuf0 + off, len0);
|
||||||
|
@ -287,8 +285,8 @@ lbatview_rmem(struct lbatview* lv, u32 off, u32 len, void* buf)
|
||||||
lbatpblk_put_buf(lv->pages[0]);
|
lbatpblk_put_buf(lv->pages[0]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
u32 bufidx = off / PAGE_SIZE;
|
u32 bufidx = off / pblk_len;
|
||||||
u32 bufoff = off % PAGE_SIZE;
|
u32 bufoff = off % pblk_len;
|
||||||
u8* pagebuf = lbatpblk_get_buf(lv->pages[bufidx], false);
|
u8* pagebuf = lbatpblk_get_buf(lv->pages[bufidx], false);
|
||||||
memcpy(buf, pagebuf + bufoff, len);
|
memcpy(buf, pagebuf + bufoff, len);
|
||||||
lbatpblk_put_buf(lv->pages[bufidx]);
|
lbatpblk_put_buf(lv->pages[bufidx]);
|
||||||
|
@ -298,13 +296,11 @@ lbatview_rmem(struct lbatview* lv, u32 off, u32 len, void* buf)
|
||||||
static void
|
static void
|
||||||
lbatview_wmem(struct lbatview* lv, u32 off, u32 len, void* buf)
|
lbatview_wmem(struct lbatview* lv, u32 off, u32 len, void* buf)
|
||||||
{
|
{
|
||||||
/* XXX: Convert below to a BUG_ON */
|
u32 pblk_len = pblk_size(&lv->kparams->params);
|
||||||
if (off + len > 2 * PAGE_SIZE) {
|
|
||||||
printk(KERN_ERR "%s: *** out of bounds\n", __func__);
|
BUG_ON(off + len > 2 * pblk_len);
|
||||||
return;
|
if (off < pblk_len && off + len > pblk_len) {
|
||||||
}
|
u32 len0 = pblk_len - off;
|
||||||
if (off < PAGE_SIZE && off + len > PAGE_SIZE) {
|
|
||||||
u32 len0 = PAGE_SIZE - off;
|
|
||||||
u8* pagebuf0 = lbatpblk_get_buf(lv->pages[0], true);
|
u8* pagebuf0 = lbatpblk_get_buf(lv->pages[0], true);
|
||||||
u8* pagebuf1 = lbatpblk_get_buf(lv->pages[1], true);
|
u8* pagebuf1 = lbatpblk_get_buf(lv->pages[1], true);
|
||||||
memcpy(pagebuf0 + off, buf, len0);
|
memcpy(pagebuf0 + off, buf, len0);
|
||||||
|
@ -313,8 +309,8 @@ lbatview_wmem(struct lbatview* lv, u32 off, u32 len, void* buf)
|
||||||
lbatpblk_put_buf(lv->pages[0]);
|
lbatpblk_put_buf(lv->pages[0]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
u32 bufidx = off / PAGE_SIZE;
|
u32 bufidx = off / pblk_len;
|
||||||
u32 bufoff = off % PAGE_SIZE;
|
u32 bufoff = off % pblk_len;
|
||||||
u8* pagebuf = lbatpblk_get_buf(lv->pages[bufidx], true);
|
u8* pagebuf = lbatpblk_get_buf(lv->pages[bufidx], true);
|
||||||
memcpy(pagebuf + bufoff, buf, len);
|
memcpy(pagebuf + bufoff, buf, len);
|
||||||
lbatpblk_put_buf(lv->pages[bufidx]);
|
lbatpblk_put_buf(lv->pages[bufidx]);
|
||||||
|
|
|
@ -259,7 +259,7 @@ lbd_ctr(struct lbd* lbd,
|
||||||
struct lbatviewcache* lvc,
|
struct lbatviewcache* lvc,
|
||||||
void* percpu)
|
void* percpu)
|
||||||
{
|
{
|
||||||
u32 nr_pages = lblk_per_pblk(&kparams->params);
|
u32 nr_pages = DIV_ROUND_UP(lblk_size(&kparams->params), PAGE_SIZE);
|
||||||
|
|
||||||
memset(lbd, 0, sizeof(struct lbd));
|
memset(lbd, 0, sizeof(struct lbd));
|
||||||
INIT_LIST_HEAD(&lbd->lru_list);
|
INIT_LIST_HEAD(&lbd->lru_list);
|
||||||
|
@ -281,9 +281,14 @@ lbd_ctr(struct lbd* lbd,
|
||||||
if (!cbd_alloc_pagev(lbd->pagev, nr_pages)) {
|
if (!cbd_alloc_pagev(lbd->pagev, nr_pages)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lbd->buf = vmap(lbd->pagev, nr_pages, VM_MAP, PAGE_KERNEL);
|
if (nr_pages == 1) {
|
||||||
if (!lbd->buf) {
|
lbd->buf = page_address(lbd->pagev[0]);
|
||||||
return false;
|
}
|
||||||
|
else {
|
||||||
|
lbd->buf = vmap(lbd->pagev, nr_pages, VM_MAP, PAGE_KERNEL);
|
||||||
|
if (!lbd->buf) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lbd->c_len = 0;
|
lbd->c_len = 0;
|
||||||
|
|
||||||
|
@ -293,17 +298,30 @@ 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->kparams->params);
|
u32 nr_pages = DIV_ROUND_UP(lblk_size(&lbd->kparams->params), PAGE_SIZE);
|
||||||
|
u32 n;
|
||||||
|
|
||||||
|
if (lbd->pagev) {
|
||||||
|
for (n = 0; n < nr_pages; ++n) {
|
||||||
|
if (lbd->pagev[n]) {
|
||||||
|
lock_page(lbd->pagev[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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__);
|
||||||
}
|
}
|
||||||
lbd->c_len = 0;
|
lbd->c_len = 0;
|
||||||
vunmap(lbd->buf);
|
if (nr_pages != 1) {
|
||||||
|
vunmap(lbd->buf);
|
||||||
|
}
|
||||||
lbd->buf = NULL;
|
lbd->buf = NULL;
|
||||||
cbd_free_pagev(lbd->pagev, nr_pages);
|
if (lbd->pagev) {
|
||||||
kfree(lbd->pagev);
|
cbd_free_pagev(lbd->pagev, nr_pages);
|
||||||
lbd->pagev = NULL;
|
kfree(lbd->pagev);
|
||||||
|
lbd->pagev = NULL;
|
||||||
|
}
|
||||||
lbd->percpu = NULL;
|
lbd->percpu = NULL;
|
||||||
lbd->lv = NULL;
|
lbd->lv = NULL;
|
||||||
lbd->lvc = NULL;
|
lbd->lvc = NULL;
|
||||||
|
@ -319,12 +337,15 @@ static int
|
||||||
lbd_flush(struct lbd* lbd)
|
lbd_flush(struct lbd* lbd)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
u32 nr_pages = DIV_ROUND_UP(lblk_size(&lbd->kparams->params), PAGE_SIZE);
|
||||||
|
u32 pblk_per_page = PAGE_SIZE / pblk_size(&lbd->kparams->params);
|
||||||
int err;
|
int err;
|
||||||
|
u32 nr_pblk;
|
||||||
|
u32 pblk_idx;
|
||||||
|
u32 pg_idx;
|
||||||
|
u64 pblkv[PBLK_IOV_MAX];
|
||||||
|
u32 iov_len;
|
||||||
u32 n;
|
u32 n;
|
||||||
u64 pblk;
|
|
||||||
u32 nr_pages = lblk_per_pblk(&lbd->kparams->params);
|
|
||||||
u32 count;
|
|
||||||
struct page* iopagev[1];
|
|
||||||
|
|
||||||
mutex_lock(&lbd->lock);
|
mutex_lock(&lbd->lock);
|
||||||
if (!PageDirty(lbd->pagev[0])) {
|
if (!PageDirty(lbd->pagev[0])) {
|
||||||
|
@ -346,30 +367,30 @@ lbd_flush(struct lbd* lbd)
|
||||||
if (c_blkrem) {
|
if (c_blkrem) {
|
||||||
memset(lbd->buf + lbd->c_len, 0, c_blkrem);
|
memset(lbd->buf + lbd->c_len, 0, c_blkrem);
|
||||||
}
|
}
|
||||||
count = DIV_ROUND_UP(lbd->c_len, pblk_size(&lbd->kparams->params));
|
nr_pblk = DIV_ROUND_UP(lbd->c_len, pblk_size(&lbd->kparams->params));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lbd->c_len = CBD_UNCOMPRESSED;
|
lbd->c_len = CBD_UNCOMPRESSED;
|
||||||
count = lblk_per_pblk(&lbd->kparams->params);
|
nr_pblk = lblk_per_pblk(&lbd->kparams->params);
|
||||||
}
|
}
|
||||||
ret = lbatview_elem_realloc(lbd->lv, lbd->lblk, lbd->c_len);
|
ret = lbatview_elem_realloc(lbd->lv, lbd->lblk, lbd->c_len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
lbd->kparams->params.flags |= CBD_FLAG_ERROR;
|
lbd->kparams->params.flags |= CBD_FLAG_ERROR;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
for (n = 0; n < count; ++n) {
|
for (pblk_idx = 0, pg_idx = 0; pblk_idx < nr_pblk; ++pg_idx) {
|
||||||
pblk = lbatview_elem_pblk(lbd->lv, lbd->lblk, n);
|
iov_len = min(nr_pblk - pblk_idx, pblk_per_page);
|
||||||
BUG_ON(pblk == PBLK_NONE);
|
for (n = 0; n < iov_len; ++n) {
|
||||||
iopagev[0] = lbd->pagev[n];
|
pblkv[n] = lbatview_elem_pblk(lbd->lv, lbd->lblk, pblk_idx++);
|
||||||
pblk_write(lbd->kparams, pblk, 1, iopagev);
|
}
|
||||||
|
pblk_writev(lbd->kparams, pblkv, iov_len, lbd->pagev[pg_idx]);
|
||||||
|
}
|
||||||
|
while (pg_idx < nr_pages) {
|
||||||
|
unlock_page(lbd->pagev[pg_idx++]);
|
||||||
}
|
}
|
||||||
mutex_lock(&lbd->kstats->lock);
|
mutex_lock(&lbd->kstats->lock);
|
||||||
++lbd->kstats->lbd_w;
|
++lbd->kstats->lbd_w;
|
||||||
mutex_unlock(&lbd->kstats->lock);
|
mutex_unlock(&lbd->kstats->lock);
|
||||||
while (n < lblk_per_pblk(&lbd->kparams->params)) {
|
|
||||||
unlock_page(lbd->pagev[n]);
|
|
||||||
++n;
|
|
||||||
}
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
|
@ -392,39 +413,36 @@ static int
|
||||||
lbd_read(struct lbd* lbd)
|
lbd_read(struct lbd* lbd)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 count;
|
u32 pblk_per_page = PAGE_SIZE / pblk_size(&lbd->kparams->params);
|
||||||
|
u32 nr_pblk;
|
||||||
|
u32 pblk_idx;
|
||||||
|
u32 pg_idx;
|
||||||
|
u64 pblkv[PBLK_IOV_MAX];
|
||||||
|
u32 iov_len;
|
||||||
u32 n;
|
u32 n;
|
||||||
u64 pblk;
|
|
||||||
struct page* iopagev[1];
|
|
||||||
|
|
||||||
/* XXX: can't happen because lbdcache will not use a page with an error */
|
BUG_ON(lbd_error(lbd));
|
||||||
if (PageError(lbd->pagev[0])) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
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, lblk_size(&lbd->kparams->params));
|
memset(lbd->buf, 0, lblk_size(&lbd->kparams->params));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
count = (lbd->c_len == CBD_UNCOMPRESSED) ?
|
nr_pblk = (lbd->c_len == CBD_UNCOMPRESSED) ?
|
||||||
lblk_per_pblk(&lbd->kparams->params) :
|
lblk_per_pblk(&lbd->kparams->params) :
|
||||||
DIV_ROUND_UP(lbd->c_len, pblk_size(&lbd->kparams->params));
|
DIV_ROUND_UP(lbd->c_len, pblk_size(&lbd->kparams->params));
|
||||||
for (n = 0; n < count; ++n) {
|
for (pblk_idx = 0, pg_idx = 0; pblk_idx < nr_pblk; ++pg_idx) {
|
||||||
pblk = lbatview_elem_pblk(lbd->lv, lbd->lblk, n);
|
iov_len = min(nr_pblk - pblk_idx, pblk_per_page);
|
||||||
if (pblk == PBLK_NONE) {
|
for (n = 0; n < iov_len; ++n) {
|
||||||
ret = -EIO;
|
pblkv[n] = lbatview_elem_pblk(lbd->lv, lbd->lblk, pblk_idx++);
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
iopagev[0] = lbd->pagev[n];
|
ret = pblk_readv_wait(lbd->kparams, pblkv, iov_len, lbd->pagev[pg_idx]);
|
||||||
/* XXX: Issue non-blocking reads? */
|
|
||||||
ret = pblk_read_wait(lbd->kparams, pblk, 1, iopagev);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lbd->c_len != CBD_UNCOMPRESSED) {
|
if (lbd->c_len != CBD_UNCOMPRESSED) {
|
||||||
if (!lblk_decompress(lbd)) {
|
if (!lblk_decompress(lbd)) {
|
||||||
printk(KERN_ERR " decompress failed\n");
|
printk(KERN_ERR "%s: decompress failed\n", __func__);
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -443,7 +461,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->kparams->params);
|
u32 nr_pages = DIV_ROUND_UP(lblk_size(&lbd->kparams->params), PAGE_SIZE);
|
||||||
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__); }
|
||||||
|
@ -496,11 +514,7 @@ lbd_lblk(struct lbd* lbd)
|
||||||
void
|
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 */
|
BUG_ON(off + len > lblk_size(&lbd->kparams->params));
|
||||||
if (off + len > lblk_size(&lbd->kparams->params)) {
|
|
||||||
printk(KERN_ERR "%s: out of bounds\n", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mutex_lock(&lbd->lock);
|
mutex_lock(&lbd->lock);
|
||||||
memcpy(buf, lbd->buf + off, len);
|
memcpy(buf, lbd->buf + off, len);
|
||||||
mutex_unlock(&lbd->lock);
|
mutex_unlock(&lbd->lock);
|
||||||
|
@ -509,11 +523,7 @@ lbd_data_read(struct lbd* lbd, u32 off, u32 len, u8* buf)
|
||||||
void
|
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 */
|
BUG_ON(off + len > lblk_size(&lbd->kparams->params));
|
||||||
if (off + len > lblk_size(&lbd->kparams->params)) {
|
|
||||||
printk(KERN_ERR "%s: out of bounds\n", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mutex_lock(&lbd->lock);
|
mutex_lock(&lbd->lock);
|
||||||
memcpy(lbd->buf + off, buf, len);
|
memcpy(lbd->buf + off, buf, len);
|
||||||
SetPageDirty(lbd->pagev[0]);
|
SetPageDirty(lbd->pagev[0]);
|
||||||
|
@ -564,7 +574,7 @@ lbdcache_alloc_compress_state(void* percpu, const struct cbd_params* params, int
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#ifdef COMPRESS_HAVE_LZ4
|
#ifdef COMPRESS_HAVE_LZ4
|
||||||
workmem_len = LZ4_compressBound(lblk_size(params));
|
workmem_len = LZ4_MEM_COMPRESS;
|
||||||
state->lz4_workmem = vzalloc(workmem_len);
|
state->lz4_workmem = vzalloc(workmem_len);
|
||||||
if (!state->lz4_workmem) {
|
if (!state->lz4_workmem) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -40,7 +40,7 @@ struct pbat {
|
||||||
struct compress_stats* kstats;
|
struct compress_stats* kstats;
|
||||||
bool full;
|
bool full;
|
||||||
u32 last_alloc;
|
u32 last_alloc;
|
||||||
struct page** pagev;
|
struct page* page;
|
||||||
u8* buf;
|
u8* buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,8 +49,6 @@ pbat_ctr(struct pbat* pbat,
|
||||||
struct compress_params* kparams,
|
struct compress_params* kparams,
|
||||||
struct compress_stats* kstats)
|
struct compress_stats* kstats)
|
||||||
{
|
{
|
||||||
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);
|
||||||
pbat->zone = ZONE_NONE;
|
pbat->zone = ZONE_NONE;
|
||||||
|
@ -61,22 +59,11 @@ pbat_ctr(struct pbat* pbat,
|
||||||
pbat->kstats = kstats;
|
pbat->kstats = kstats;
|
||||||
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->page = cbd_alloc_page();
|
||||||
if (!pbat->pagev) {
|
if (!pbat->page) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!cbd_alloc_pagev(pbat->pagev, nr_pages)) {
|
pbat->buf = page_address(pbat->page);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (nr_pages == 1) {
|
|
||||||
pbat->buf = page_address(pbat->pagev[0]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pbat->buf = vmap(pbat->pagev, nr_pages, VM_MAP, PAGE_KERNEL);
|
|
||||||
if (!pbat->buf) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -84,37 +71,28 @@ 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->kparams->params);
|
if (pbat->page) {
|
||||||
u32 n;
|
lock_page(pbat->page);
|
||||||
|
|
||||||
for (n = 0; n < nr_pages; ++n) {
|
|
||||||
lock_page(pbat->pagev[n]);
|
|
||||||
}
|
|
||||||
if (nr_pages != 1) {
|
|
||||||
vunmap(pbat->buf);
|
|
||||||
}
|
}
|
||||||
pbat->buf = NULL;
|
pbat->buf = NULL;
|
||||||
cbd_free_pagev(pbat->pagev, nr_pages);
|
cbd_free_page(pbat->page);
|
||||||
kfree(pbat->pagev);
|
pbat->page = NULL;
|
||||||
pbat->pagev = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
pbat_error(struct pbat* pbat)
|
pbat_error(struct pbat* pbat)
|
||||||
{
|
{
|
||||||
return PageError(pbat->pagev[0]);
|
return PageError(pbat->page);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pbat_flush(struct pbat* pbat)
|
pbat_flush(struct pbat* pbat)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 nr_pages = pbat_len(&pbat->kparams->params);
|
|
||||||
u32 n;
|
|
||||||
u64 pblk;
|
u64 pblk;
|
||||||
|
|
||||||
mutex_lock(&pbat->lock);
|
mutex_lock(&pbat->lock);
|
||||||
if (!PageDirty(pbat->pagev[0])) {
|
if (!PageDirty(pbat->page)) {
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
if (pbat_error(pbat)) {
|
if (pbat_error(pbat)) {
|
||||||
|
@ -122,7 +100,7 @@ pbat_flush(struct pbat* pbat)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
pblk = pbat_off(&pbat->kparams->params, pbat->zone);
|
pblk = pbat_off(&pbat->kparams->params, pbat->zone);
|
||||||
pblk_write(pbat->kparams, pblk, nr_pages, pbat->pagev);
|
pblk_write(pbat->kparams, pblk, pbat_len(&pbat->kparams->params), pbat->page);
|
||||||
mutex_unlock(&pbat->lock);
|
mutex_unlock(&pbat->lock);
|
||||||
mutex_lock(&pbat->kstats->lock);
|
mutex_lock(&pbat->kstats->lock);
|
||||||
++pbat->kstats->pbat_w;
|
++pbat->kstats->pbat_w;
|
||||||
|
@ -131,9 +109,7 @@ pbat_flush(struct pbat* pbat)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
for (n = 0; n < nr_pages; ++n) {
|
unlock_page(pbat->page);
|
||||||
unlock_page(pbat->pagev[n]);
|
|
||||||
}
|
|
||||||
mutex_unlock(&pbat->lock);
|
mutex_unlock(&pbat->lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -143,15 +119,11 @@ static int
|
||||||
pbat_read(struct pbat* pbat)
|
pbat_read(struct pbat* pbat)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
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 */
|
BUG_ON(pbat_error(pbat));
|
||||||
if (PageError(pbat->pagev[0])) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
pblk = pbat_off(&pbat->kparams->params, pbat->zone);
|
pblk = pbat_off(&pbat->kparams->params, pbat->zone);
|
||||||
ret = pblk_read_wait(pbat->kparams, pblk, nr_pages, pbat->pagev);
|
ret = pblk_read_wait(pbat->kparams, pblk, pbat_len(&pbat->kparams->params), pbat->page);
|
||||||
mutex_lock(&pbat->kstats->lock);
|
mutex_lock(&pbat->kstats->lock);
|
||||||
++pbat->kstats->pbat_r;
|
++pbat->kstats->pbat_r;
|
||||||
mutex_unlock(&pbat->kstats->lock);
|
mutex_unlock(&pbat->kstats->lock);
|
||||||
|
@ -163,12 +135,8 @@ 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->kparams->params);
|
|
||||||
u32 n;
|
|
||||||
|
|
||||||
for (n = 0; n < nr_pages; ++n) {
|
lock_page(pbat->page);
|
||||||
lock_page(pbat->pagev[n]);
|
|
||||||
}
|
|
||||||
if (pbat->zone != zone) {
|
if (pbat->zone != zone) {
|
||||||
pbat->zone = zone;
|
pbat->zone = zone;
|
||||||
pbat->full = false;
|
pbat->full = false;
|
||||||
|
@ -177,9 +145,7 @@ pbat_reset(struct pbat* pbat, u32 zone)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
for (n = 0; n < nr_pages; ++n) {
|
unlock_page(pbat->page);
|
||||||
unlock_page(pbat->pagev[n]);
|
|
||||||
}
|
|
||||||
pbat->zone = ZONE_NONE;
|
pbat->zone = ZONE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +179,7 @@ pbat_alloc(struct pbat* pbat)
|
||||||
}
|
}
|
||||||
pbat->last_alloc = idx;
|
pbat->last_alloc = idx;
|
||||||
pblk = idx + zone_data_off(&pbat->kparams->params, pbat->zone);
|
pblk = idx + zone_data_off(&pbat->kparams->params, pbat->zone);
|
||||||
SetPageDirty(pbat->pagev[0]);
|
SetPageDirty(pbat->page);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&pbat->lock);
|
mutex_unlock(&pbat->lock);
|
||||||
|
@ -239,7 +205,7 @@ pbat_free(struct pbat* pbat, u64 pblk)
|
||||||
mutex_lock(&pbat->lock);
|
mutex_lock(&pbat->lock);
|
||||||
cbd_bitmap_free(pbat->buf, idx);
|
cbd_bitmap_free(pbat->buf, idx);
|
||||||
pbat->full = false;
|
pbat->full = false;
|
||||||
SetPageDirty(pbat->pagev[0]);
|
SetPageDirty(pbat->page);
|
||||||
mutex_unlock(&pbat->lock);
|
mutex_unlock(&pbat->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -99,12 +99,12 @@ cbd_free_pagev(struct page** pagev, size_t len)
|
||||||
|
|
||||||
static struct bio*
|
static struct bio*
|
||||||
pblk_io_prepare(struct block_device* bdev, unsigned int op,
|
pblk_io_prepare(struct block_device* bdev, unsigned int op,
|
||||||
u32 pblk_size, u64 pblk, u32 count, struct page** pagev)
|
u32 pblk_len, u64 pblk, u32 count, struct page* page, u32 page_off)
|
||||||
{
|
{
|
||||||
struct bio* bio;
|
struct bio* bio;
|
||||||
u32 n;
|
|
||||||
|
|
||||||
bio = bio_alloc(GFP_KERNEL, count);
|
BUG_ON(page_off + pblk_len * count > PAGE_SIZE);
|
||||||
|
bio = bio_alloc(GFP_KERNEL, 1);
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
printk(KERN_ERR "%s: out of memory\n", __func__);
|
printk(KERN_ERR "%s: out of memory\n", __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -112,11 +112,9 @@ pblk_io_prepare(struct block_device* bdev, unsigned int op,
|
||||||
bio_set_dev(bio, bdev);
|
bio_set_dev(bio, bdev);
|
||||||
bio->bi_opf = op;
|
bio->bi_opf = op;
|
||||||
|
|
||||||
bio->bi_iter.bi_sector = pblk * (pblk_size / SECTOR_SIZE);
|
bio->bi_iter.bi_sector = pblk * (pblk_len / SECTOR_SIZE);
|
||||||
for (n = 0; n < count; ++n) {
|
if (bio_add_page(bio, page, pblk_len * count, page_off) == 0) {
|
||||||
if (bio_add_page(bio, pagev[n], pblk_size, 0) != pblk_size) {
|
BUG();
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bio;
|
return bio;
|
||||||
|
@ -124,13 +122,13 @@ pblk_io_prepare(struct block_device* bdev, unsigned int op,
|
||||||
|
|
||||||
int
|
int
|
||||||
pblk_read_wait(struct compress_params* kparams,
|
pblk_read_wait(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev)
|
u64 pblk, u32 count, struct page* page)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct bio* bio;
|
struct bio* bio;
|
||||||
|
|
||||||
bio = pblk_io_prepare(kparams->dev, REQ_OP_READ,
|
bio = pblk_io_prepare(kparams->dev, REQ_OP_READ,
|
||||||
pblk_size(&kparams->params), pblk, count, pagev);
|
pblk_size(&kparams->params), pblk, count, page, 0);
|
||||||
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,15 +142,44 @@ pblk_read_wait(struct compress_params* kparams,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pblk_readv_wait(struct compress_params* kparams,
|
||||||
|
u64* pblkv, u32 count, struct page* page)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
u32 pblk_len = pblk_size(&kparams->params);
|
||||||
|
u32 n;
|
||||||
|
u32 page_off;
|
||||||
|
struct bio* bio;
|
||||||
|
|
||||||
|
/* XXX: Issue no-blocking reads for parallelism? */
|
||||||
|
for (n = 0, page_off = 0; n < count; ++n, page_off += pblk_len) {
|
||||||
|
bio = pblk_io_prepare(kparams->dev, REQ_OP_READ,
|
||||||
|
pblk_len, pblkv[n], 1, page, page_off);
|
||||||
|
if (!bio) {
|
||||||
|
printk(KERN_ERR "%s: out of memory\n", __func__);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
ret = submit_bio_wait(bio);
|
||||||
|
if (ret) {
|
||||||
|
printk(KERN_ERR "%s: submit_bio_wait failed: %d\n", __func__, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
bio_put(bio);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
pblk_write_wait(struct compress_params* kparams,
|
pblk_write_wait(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev)
|
u64 pblk, u32 count, struct page* page)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct bio* bio;
|
struct bio* bio;
|
||||||
|
|
||||||
bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE,
|
bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE,
|
||||||
pblk_size(&kparams->params), pblk, count, pagev);
|
pblk_size(&kparams->params), pblk, count, page, 0);
|
||||||
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;
|
||||||
|
@ -171,45 +198,120 @@ void
|
||||||
pblk_write_endio(struct bio* bio)
|
pblk_write_endio(struct bio* bio)
|
||||||
{
|
{
|
||||||
struct compress_params* kparams = bio->bi_private;
|
struct compress_params* kparams = bio->bi_private;
|
||||||
u32 n;
|
struct page* page = bio->bi_io_vec[0].bv_page;
|
||||||
struct page* page;
|
|
||||||
|
|
||||||
BUG_ON(!bio);
|
|
||||||
if (bio->bi_status != BLK_STS_OK) {
|
if (bio->bi_status != BLK_STS_OK) {
|
||||||
|
printk(KERN_ERR "%s: I/O error\n", __func__);
|
||||||
kparams->params.flags |= CBD_FLAG_ERROR;
|
kparams->params.flags |= CBD_FLAG_ERROR;
|
||||||
for (n = 0; n < bio->bi_max_vecs; ++n) {
|
SetPageError(page);
|
||||||
page = bio->bi_io_vec[n].bv_page;
|
|
||||||
SetPageError(page);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (n = 0; n < bio->bi_max_vecs; ++n) {
|
|
||||||
page = bio->bi_io_vec[n].bv_page;
|
|
||||||
ClearPageDirty(page);
|
|
||||||
unlock_page(page);
|
|
||||||
}
|
}
|
||||||
|
ClearPageDirty(page);
|
||||||
|
unlock_page(page);
|
||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pblk_write(struct compress_params* kparams,
|
pblk_write(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev)
|
u64 pblk, u32 count, struct page* page)
|
||||||
{
|
{
|
||||||
struct bio* bio;
|
struct bio* bio;
|
||||||
u32 n;
|
|
||||||
|
|
||||||
bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE,
|
bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE,
|
||||||
pblk_size(&kparams->params), pblk, count, pagev);
|
pblk_size(&kparams->params), pblk, count, page, 0);
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
printk(KERN_ERR "%s: out of memory\n", __func__);
|
printk(KERN_ERR "%s: out of memory\n", __func__);
|
||||||
kparams->params.flags |= CBD_FLAG_ERROR;
|
kparams->params.flags |= CBD_FLAG_ERROR;
|
||||||
for (n = 0; n < count; ++n) {
|
SetPageError(page);
|
||||||
SetPageError(pagev[n]);
|
unlock_page(page);
|
||||||
unlock_page(pagev[n]);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bio->bi_end_io = pblk_write_endio;
|
bio->bi_end_io = pblk_write_endio;
|
||||||
bio->bi_private = kparams;
|
bio->bi_private = kparams;
|
||||||
|
|
||||||
submit_bio(bio);
|
submit_bio(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct pblk_iov
|
||||||
|
{
|
||||||
|
struct compress_params* kparams;
|
||||||
|
atomic_t remain;
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
pblk_writev_endio(struct bio* bio)
|
||||||
|
{
|
||||||
|
struct pblk_iov* iov = bio->bi_private;
|
||||||
|
struct compress_params* kparams = iov->kparams;
|
||||||
|
struct page* page = bio->bi_io_vec[0].bv_page;
|
||||||
|
|
||||||
|
if (bio->bi_status != BLK_STS_OK) {
|
||||||
|
printk(KERN_ERR "%s: I/O error\n", __func__);
|
||||||
|
kparams->params.flags |= CBD_FLAG_ERROR;
|
||||||
|
SetPageError(page);
|
||||||
|
}
|
||||||
|
if (atomic_dec_and_test(&iov->remain)) {
|
||||||
|
ClearPageDirty(page);
|
||||||
|
unlock_page(page);
|
||||||
|
kfree(iov);
|
||||||
|
}
|
||||||
|
bio_put(bio);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pblk_writev(struct compress_params* kparams,
|
||||||
|
u64* pblkv, u32 count, struct page* page)
|
||||||
|
{
|
||||||
|
u32 pblk_len = pblk_size(&kparams->params);
|
||||||
|
struct pblk_iov* iov;
|
||||||
|
u32 idx;
|
||||||
|
u32 page_off;
|
||||||
|
u32 nr_bio;
|
||||||
|
u64 pblk;
|
||||||
|
u32 iov_nr_pblk;
|
||||||
|
struct bio* bio;
|
||||||
|
|
||||||
|
BUG_ON(pblk_len * count > PAGE_SIZE);
|
||||||
|
iov = kmalloc(sizeof(struct pblk_iov), GFP_KERNEL);
|
||||||
|
if (!iov) {
|
||||||
|
printk(KERN_ERR "%s: out of memory\n", __func__);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
iov->kparams = kparams;
|
||||||
|
atomic_set(&iov->remain, count);
|
||||||
|
idx = 0;
|
||||||
|
page_off = 0;
|
||||||
|
nr_bio = 0;
|
||||||
|
while (idx < count) {
|
||||||
|
pblk = pblkv[idx];
|
||||||
|
iov_nr_pblk = 1;
|
||||||
|
++idx;
|
||||||
|
while (idx < count && pblkv[idx] == pblk + iov_nr_pblk) {
|
||||||
|
++iov_nr_pblk;
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
bio = pblk_io_prepare(kparams->dev, REQ_OP_WRITE,
|
||||||
|
pblk_len, pblk, iov_nr_pblk, page, page_off);
|
||||||
|
if (!bio) {
|
||||||
|
printk(KERN_ERR "%s: out of memory\n", __func__);
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
++nr_bio;
|
||||||
|
bio->bi_end_io = pblk_writev_endio;
|
||||||
|
bio->bi_private = iov;
|
||||||
|
submit_bio(bio);
|
||||||
|
page_off += pblk_len * iov_nr_pblk;
|
||||||
|
}
|
||||||
|
if (atomic_sub_and_test(count - nr_bio, &iov->remain)) {
|
||||||
|
ClearPageDirty(page);
|
||||||
|
unlock_page(page);
|
||||||
|
kfree(iov);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
kfree(iov);
|
||||||
|
err:
|
||||||
|
kparams->params.flags |= CBD_FLAG_ERROR;
|
||||||
|
SetPageError(page);
|
||||||
|
unlock_page(page);
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,6 @@ void __attribute__((noreturn))
|
||||||
error(const char* fmt, ...);
|
error(const char* fmt, ...);
|
||||||
int verbose(uint level, const char* fmt, ...);
|
int verbose(uint level, const char* fmt, ...);
|
||||||
|
|
||||||
bool ask_user_bool(const char* fmt, ...);
|
bool ask_user_bool(tristate_t auto_response, const char* fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -66,9 +66,9 @@ typedef enum {
|
||||||
} tristate_t;
|
} tristate_t;
|
||||||
|
|
||||||
int cbd_format(const char* dev,
|
int cbd_format(const char* dev,
|
||||||
uint8_t pshift, uint8_t lshift,
|
|
||||||
uint16_t pbatlen,
|
|
||||||
enum cbd_alg alg, uint level,
|
enum cbd_alg alg, uint level,
|
||||||
|
uint8_t pshift, uint8_t lshift,
|
||||||
|
uint8_t pbatshift,
|
||||||
uint64_t psize, uint64_t lsize);
|
uint64_t psize, uint64_t lsize);
|
||||||
int cbd_open(const char* dev,
|
int cbd_open(const char* dev,
|
||||||
const char* name);
|
const char* name);
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#define PBLK_SHIFT_MAX 3
|
#define PBLK_SHIFT_MAX 3
|
||||||
#define LBLK_SHIFT_MIN 1
|
#define LBLK_SHIFT_MIN 1
|
||||||
#define LBLK_SHIFT_MAX 10
|
#define LBLK_SHIFT_MAX 10
|
||||||
|
#define PBAT_SHIFT_MIN 0
|
||||||
|
#define PBAT_SHIFT_MAX 3
|
||||||
|
|
||||||
#define ZONE_NONE (u32)(~0)
|
#define ZONE_NONE (u32)(~0)
|
||||||
#define PBLK_NONE (u64)(~0)
|
#define PBLK_NONE (u64)(~0)
|
||||||
|
@ -35,7 +37,8 @@ struct cbd_params {
|
||||||
u8 pblk_shift;
|
u8 pblk_shift;
|
||||||
u8 lblk_shift;
|
u8 lblk_shift;
|
||||||
u8 lba_elem_pblk_bytes;
|
u8 lba_elem_pblk_bytes;
|
||||||
u16 pbat_len;
|
u8 pbat_shift;
|
||||||
|
/* u8 pad */
|
||||||
u32 nr_zones;
|
u32 nr_zones;
|
||||||
u32 lblk_per_zone;
|
u32 lblk_per_zone;
|
||||||
};
|
};
|
||||||
|
@ -253,7 +256,7 @@ lblk_size(const struct cbd_params* params)
|
||||||
static inline u32
|
static inline u32
|
||||||
pbat_len(const struct cbd_params* params)
|
pbat_len(const struct cbd_params* params)
|
||||||
{
|
{
|
||||||
return params->pbat_len;
|
return (1 << params->pbat_shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32
|
static inline u32
|
||||||
|
@ -356,7 +359,8 @@ cbd_header_get(const u8* buf, struct cbd_header* header)
|
||||||
header->params.pblk_shift = get_byte(&p);
|
header->params.pblk_shift = get_byte(&p);
|
||||||
header->params.lblk_shift = get_byte(&p);
|
header->params.lblk_shift = get_byte(&p);
|
||||||
header->params.lba_elem_pblk_bytes = get_byte(&p);
|
header->params.lba_elem_pblk_bytes = get_byte(&p);
|
||||||
header->params.pbat_len = get16_le(&p);
|
header->params.pbat_shift = get_byte(&p);
|
||||||
|
p += 1; /* pad */
|
||||||
header->params.nr_zones = get32_le(&p);
|
header->params.nr_zones = get32_le(&p);
|
||||||
header->params.lblk_per_zone = get32_le(&p);
|
header->params.lblk_per_zone = get32_le(&p);
|
||||||
p = buf + 64;
|
p = buf + 64;
|
||||||
|
@ -377,7 +381,8 @@ cbd_header_put(u8* buf, const struct cbd_header* header)
|
||||||
put_byte(&p, header->params.pblk_shift);
|
put_byte(&p, header->params.pblk_shift);
|
||||||
put_byte(&p, header->params.lblk_shift);
|
put_byte(&p, header->params.lblk_shift);
|
||||||
put_byte(&p, header->params.lba_elem_pblk_bytes);
|
put_byte(&p, header->params.lba_elem_pblk_bytes);
|
||||||
put16_le(&p, header->params.pbat_len);
|
put_byte(&p, header->params.pbat_shift);
|
||||||
|
put_byte(&p, 0); /* pad */
|
||||||
put32_le(&p, header->params.nr_zones);
|
put32_le(&p, header->params.nr_zones);
|
||||||
put32_le(&p, header->params.lblk_per_zone);
|
put32_le(&p, header->params.lblk_per_zone);
|
||||||
p = buf + 64;
|
p = buf + 64;
|
||||||
|
@ -577,12 +582,17 @@ 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 */
|
||||||
|
#define PBLK_IOV_MAX (PAGE_SIZE / SECTOR_SIZE)
|
||||||
int pblk_read_wait(struct compress_params* kparams,
|
int pblk_read_wait(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev);
|
u64 pblk, u32 count, struct page* page);
|
||||||
|
int pblk_readv_wait(struct compress_params* kparams,
|
||||||
|
u64* pblkv, u32 count, struct page* page);
|
||||||
int pblk_write_wait(struct compress_params* kparams,
|
int pblk_write_wait(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev);
|
u64 pblk, u32 count, struct page* page);
|
||||||
void pblk_write(struct compress_params* kparams,
|
void pblk_write(struct compress_params* kparams,
|
||||||
u64 pblk, u32 count, struct page** pagev);
|
u64 pblk, u32 count, struct page* page);
|
||||||
|
void pblk_writev(struct compress_params* kparams,
|
||||||
|
u64* pblkv, u32 count, struct page* page);
|
||||||
|
|
||||||
struct pbat;
|
struct pbat;
|
||||||
u32 pbat_zone(struct pbat* pbat);
|
u32 pbat_zone(struct pbat* pbat);
|
||||||
|
|
|
@ -10,6 +10,7 @@ typedef off_t off64_t;
|
||||||
struct check_state
|
struct check_state
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
tristate_t auto_response;
|
||||||
bool check_lblk_data;
|
bool check_lblk_data;
|
||||||
bool clean;
|
bool clean;
|
||||||
u64 pblk_used;
|
u64 pblk_used;
|
||||||
|
@ -17,7 +18,6 @@ struct check_state
|
||||||
u8** pbatv;
|
u8** pbatv;
|
||||||
|
|
||||||
u8* compress_buf;
|
u8* compress_buf;
|
||||||
u8* lz4_workmem;
|
|
||||||
z_stream zlib_dstream;
|
z_stream zlib_dstream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -206,7 +206,8 @@ check_lblk_data(struct check_state* state,
|
||||||
ret = check_decompress(state, params, data, len);
|
ret = check_decompress(state, params, data, len);
|
||||||
free(data);
|
free(data);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
if (ask_user_bool("lblk %u: failed to decompress. Clear?", lblk)) {
|
if (ask_user_bool(state->auto_response,
|
||||||
|
"lblk %u: failed to decompress. Clear?", lblk)) {
|
||||||
memset(lba, 0, lba_len(params));
|
memset(lba, 0, lba_len(params));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +242,8 @@ check_lblk_alloc(struct check_state* state,
|
||||||
verbose(2, " lblk[%u]: len=%u\n", lblk, len);
|
verbose(2, " lblk[%u]: len=%u\n", lblk, len);
|
||||||
}
|
}
|
||||||
if (len > lblk_size(params)) {
|
if (len > lblk_size(params)) {
|
||||||
if (ask_user_bool("lblk %u: length %u out of bounds. Clear?", lblk, len)) {
|
if (ask_user_bool(state->auto_response,
|
||||||
|
"lblk %u: length %u out of bounds. Clear?", lblk, len)) {
|
||||||
memset(lba, 0, lba_len(params));
|
memset(lba, 0, lba_len(params));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -255,7 +257,8 @@ check_lblk_alloc(struct check_state* state,
|
||||||
pblk = lba_pblk_get(params, buf, n);
|
pblk = lba_pblk_get(params, buf, n);
|
||||||
if (pblk < CBD_HEADER_BLOCKS) {
|
if (pblk < CBD_HEADER_BLOCKS) {
|
||||||
verbose(2, " [%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)) {
|
if (ask_user_bool(state->auto_response,
|
||||||
|
"lblk %u: alloc %u in header. Clear?", lblk, n)) {
|
||||||
memset(lba, 0, lba_len(params));
|
memset(lba, 0, lba_len(params));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -265,7 +268,8 @@ check_lblk_alloc(struct check_state* state,
|
||||||
pblk_zone = zone_for_pblk(params, pblk);
|
pblk_zone = zone_for_pblk(params, pblk);
|
||||||
if (pblk_zone == ZONE_NONE || pblk_zone >= params->nr_zones) {
|
if (pblk_zone == ZONE_NONE || pblk_zone >= params->nr_zones) {
|
||||||
verbose(2, " [%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)) {
|
if (ask_user_bool(state->auto_response,
|
||||||
|
"lblk %u: alloc %u beyond end. Clear?", lblk, n)) {
|
||||||
memset(lba, 0, lba_len(params));
|
memset(lba, 0, lba_len(params));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -274,7 +278,8 @@ check_lblk_alloc(struct check_state* state,
|
||||||
}
|
}
|
||||||
if (pblk < zone_data_off(params, pblk_zone)) {
|
if (pblk < zone_data_off(params, pblk_zone)) {
|
||||||
verbose(2, " [%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)) {
|
if (ask_user_bool(state->auto_response,
|
||||||
|
"lblk %u alloc in medatada. Clear?", lblk)) {
|
||||||
memset(lba, 0, lba_len(params));
|
memset(lba, 0, lba_len(params));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -285,7 +290,8 @@ check_lblk_alloc(struct check_state* state,
|
||||||
verbose(3, " [%u] pblk=%lu\n", n, (unsigned long)pblk);
|
verbose(3, " [%u] pblk=%lu\n", n, (unsigned long)pblk);
|
||||||
if (cbd_bitmap_isset(state->pbatv[pblk_zone], pblk_off)) {
|
if (cbd_bitmap_isset(state->pbatv[pblk_zone], pblk_off)) {
|
||||||
verbose(2, " [%u] :E: Duplicate allocation for pblk %lu\n", n, (unsigned long)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)) {
|
if (ask_user_bool(state->auto_response,
|
||||||
|
"lblk %u duplicate alloc for pblk %lu. Clear?", lblk, pblk)) {
|
||||||
memset(lba, 0, lba_len(params));
|
memset(lba, 0, lba_len(params));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -294,6 +300,8 @@ check_lblk_alloc(struct check_state* state,
|
||||||
}
|
}
|
||||||
cbd_bitmap_set(state->pbatv[pblk_zone], pblk_off);
|
cbd_bitmap_set(state->pbatv[pblk_zone], pblk_off);
|
||||||
}
|
}
|
||||||
|
++state->lblk_used;
|
||||||
|
state->pblk_used += n_alloc;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -316,7 +324,7 @@ check_lbat(struct check_state* state, const struct cbd_params* params)
|
||||||
(unsigned long)zone_off(params, zone),
|
(unsigned long)zone_off(params, zone),
|
||||||
(unsigned long)(zone_data_off(params, zone) - 1),
|
(unsigned long)(zone_data_off(params, zone) - 1),
|
||||||
(unsigned long)zone_data_off(params, zone),
|
(unsigned long)zone_data_off(params, zone),
|
||||||
(unsigned long)zone_off(params, zone + 1));
|
(unsigned long)(zone_off(params, zone + 1) - 1));
|
||||||
for (n = 0; n < params->lblk_per_zone; ++n) {
|
for (n = 0; n < params->lblk_per_zone; ++n) {
|
||||||
u8* buf = lbat + n * lba_len(params);
|
u8* buf = lbat + n * lba_len(params);
|
||||||
if (lba_len_get(params, buf) != 0) {
|
if (lba_len_get(params, buf) != 0) {
|
||||||
|
@ -331,7 +339,6 @@ check_lbat(struct check_state* state, const struct cbd_params* params)
|
||||||
for (n = 0; n < params->lblk_per_zone; ++n) {
|
for (n = 0; n < params->lblk_per_zone; ++n) {
|
||||||
u64 lblk = zone * params->lblk_per_zone + n;
|
u64 lblk = zone * params->lblk_per_zone + n;
|
||||||
u8* buf = lbat + n * lba_len(params);
|
u8* buf = lbat + n * lba_len(params);
|
||||||
u32 len;
|
|
||||||
if (check_lblk_alloc(state, params, lblk, buf)) {
|
if (check_lblk_alloc(state, params, lblk, buf)) {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
@ -340,11 +347,6 @@ check_lbat(struct check_state* state, const struct cbd_params* params)
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
len = lba_len_get(params, buf);
|
|
||||||
if (len != 0) {
|
|
||||||
++state->lblk_used;
|
|
||||||
state->pblk_used += DIV_ROUND_UP(len, pblk_size(params));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
lbat_write(state->fd, params, zone, lbat);
|
lbat_write(state->fd, params, zone, lbat);
|
||||||
|
@ -364,7 +366,8 @@ check_pbat(struct check_state* state, const struct cbd_params* params)
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
pbat_read(state->fd, params, zone, pbat);
|
pbat_read(state->fd, params, zone, pbat);
|
||||||
if (memcmp(pbat, state->pbatv[zone], pblk_size(params) * pbat_len(params)) != 0) {
|
if (memcmp(pbat, state->pbatv[zone], pblk_size(params) * pbat_len(params)) != 0) {
|
||||||
if (ask_user_bool("zone %u has incorrect pbat. Fix?", zone)) {
|
if (ask_user_bool(state->auto_response,
|
||||||
|
"zone %u has incorrect pbat. Fix?", zone)) {
|
||||||
memcpy(pbat, state->pbatv[zone], pblk_size(params) * pbat_len(params));
|
memcpy(pbat, state->pbatv[zone], pblk_size(params) * pbat_len(params));
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
@ -395,8 +398,6 @@ cbd_check(const char* dev,
|
||||||
if (state.fd < 0) {
|
if (state.fd < 0) {
|
||||||
error("Cannot open device\n");
|
error("Cannot open device\n");
|
||||||
}
|
}
|
||||||
state.check_lblk_data = full_check;
|
|
||||||
state.clean = true;
|
|
||||||
|
|
||||||
verbose(1, "Reading header\n");
|
verbose(1, "Reading header\n");
|
||||||
pblk_read(state.fd, SECTOR_SIZE, 0, 1, buf);
|
pblk_read(state.fd, SECTOR_SIZE, 0, 1, buf);
|
||||||
|
@ -409,16 +410,26 @@ cbd_check(const char* dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.auto_response = auto_response;
|
||||||
|
state.check_lblk_data = full_check;
|
||||||
|
state.clean = true;
|
||||||
state.pbatv = calloc(header.params.nr_zones, sizeof(u8*));
|
state.pbatv = calloc(header.params.nr_zones, sizeof(u8*));
|
||||||
for (n = 0; n < header.params.nr_zones; ++n) {
|
for (n = 0; n < header.params.nr_zones; ++n) {
|
||||||
state.pbatv[n] = calloc(pblk_size(&header.params), pbat_len(&header.params));
|
state.pbatv[n] = calloc(pblk_size(&header.params), pbat_len(&header.params));
|
||||||
}
|
}
|
||||||
|
if (full_check) {
|
||||||
|
state.compress_buf = malloc(lblk_size(&header.params));
|
||||||
|
memset(state.compress_buf, 0, lblk_size(&header.params));
|
||||||
|
memset(&state.zlib_dstream, 0, sizeof(z_stream));
|
||||||
|
inflateInit2(&state.zlib_dstream, MAX_WBITS);
|
||||||
|
}
|
||||||
|
|
||||||
verbose(1, "Checking lbat\n");
|
verbose(1, "Checking lbat\n");
|
||||||
check_lbat(&state, &header.params);
|
check_lbat(&state, &header.params);
|
||||||
verbose(1, "Checking pbat\n");
|
verbose(1, "Checking pbat\n");
|
||||||
check_pbat(&state, &header.params);
|
check_pbat(&state, &header.params);
|
||||||
|
|
||||||
|
free(state.compress_buf);
|
||||||
for (n = 0; n < header.params.nr_zones; ++n) {
|
for (n = 0; n < header.params.nr_zones; ++n) {
|
||||||
free(state.pbatv[n]);
|
free(state.pbatv[n]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,9 @@ pblk_write(int fd, u32 pblk_size, u64 pblk, u32 count, const u8* data)
|
||||||
|
|
||||||
int
|
int
|
||||||
cbd_format(const char* dev,
|
cbd_format(const char* dev,
|
||||||
uint8_t pshift, uint8_t lshift,
|
|
||||||
uint16_t pbatlen,
|
|
||||||
enum cbd_alg alg, uint level,
|
enum cbd_alg alg, uint level,
|
||||||
|
uint8_t pshift, uint8_t lshift,
|
||||||
|
uint8_t pbatshift,
|
||||||
uint64_t psize, uint64_t lsize)
|
uint64_t psize, uint64_t lsize)
|
||||||
{
|
{
|
||||||
int devfd;
|
int devfd;
|
||||||
|
@ -45,6 +45,12 @@ cbd_format(const char* dev,
|
||||||
error("Cannot open device\n");
|
error("Cannot open device\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (alg <= CBD_ALG_NONE || alg >= CBD_ALG_MAX) {
|
||||||
|
error("Compression algorithm %d unknown\n", (int)alg);
|
||||||
|
}
|
||||||
|
if (level < 1 || level > 9) {
|
||||||
|
error("Compression level %u out of bounds\n", level);
|
||||||
|
}
|
||||||
if (!pshift) {
|
if (!pshift) {
|
||||||
pshift = CBD_DEFAULT_PHYSICAL_BLOCK_SHIFT;
|
pshift = CBD_DEFAULT_PHYSICAL_BLOCK_SHIFT;
|
||||||
}
|
}
|
||||||
|
@ -61,14 +67,9 @@ cbd_format(const char* dev,
|
||||||
(uint)lshift, (uint)LBLK_SHIFT_MIN, (uint)LBLK_SHIFT_MAX);
|
(uint)lshift, (uint)LBLK_SHIFT_MIN, (uint)LBLK_SHIFT_MAX);
|
||||||
}
|
}
|
||||||
lblk_size = pblk_size * (1 << lshift);
|
lblk_size = pblk_size * (1 << lshift);
|
||||||
if (!pbatlen) {
|
if (pbatshift < PBAT_SHIFT_MIN || pbatshift > PBAT_SHIFT_MAX) {
|
||||||
pbatlen = 1;
|
error("Physical block allocation table shift %u is not in [%u,%u]\n",
|
||||||
}
|
(uint)pbatshift, (uint)PBAT_SHIFT_MIN, (uint)PBAT_SHIFT_MAX);
|
||||||
if (alg <= CBD_ALG_NONE || alg >= CBD_ALG_MAX) {
|
|
||||||
error("Compression algorithm %d unknown\n", (int)alg);
|
|
||||||
}
|
|
||||||
if (level < 1 || level > 9) {
|
|
||||||
error("Compression level %u out of bounds\n", level);
|
|
||||||
}
|
}
|
||||||
if (!psize) {
|
if (!psize) {
|
||||||
off_t pos;
|
off_t pos;
|
||||||
|
@ -92,7 +93,7 @@ cbd_format(const char* dev,
|
||||||
printf("%s: parameters...\n", __func__);
|
printf("%s: parameters...\n", __func__);
|
||||||
printf(" pshift=%u\n", (unsigned int)pshift);
|
printf(" pshift=%u\n", (unsigned int)pshift);
|
||||||
printf(" lshift=%u\n", (unsigned int)lshift);
|
printf(" lshift=%u\n", (unsigned int)lshift);
|
||||||
printf(" pbatlen=%hu\n", (unsigned short)pbatlen);
|
printf(" pbatshift=%u\n", (unsigned int)pbatshift);
|
||||||
printf(" alg=%d\n", (int)alg);
|
printf(" alg=%d\n", (int)alg);
|
||||||
printf(" level=%u\n", level);
|
printf(" level=%u\n", level);
|
||||||
printf(" psize=%lu\n", (unsigned long)psize);
|
printf(" psize=%lu\n", (unsigned long)psize);
|
||||||
|
@ -110,7 +111,13 @@ cbd_format(const char* dev,
|
||||||
header.params.lba_elem_pblk_bytes =
|
header.params.lba_elem_pblk_bytes =
|
||||||
((psize / pblk_size) <= 0xffff ? 2 :
|
((psize / pblk_size) <= 0xffff ? 2 :
|
||||||
((psize / pblk_size) <= 0xffffffff ? 4 : 6));
|
((psize / pblk_size) <= 0xffffffff ? 4 : 6));
|
||||||
header.params.pbat_len = pbatlen;
|
header.params.pbat_shift = pbatshift;
|
||||||
|
if (pbat_len(&header.params) * pblk_size > PAGE_SIZE) {
|
||||||
|
error("Physical block allocation table too large\n");
|
||||||
|
}
|
||||||
|
if (lba_len(&header.params) > pblk_size) {
|
||||||
|
error("lba element size too large\n");
|
||||||
|
}
|
||||||
/* XXX: Initial estimate */
|
/* XXX: Initial estimate */
|
||||||
header.params.lblk_per_zone = zone_data_len(&header.params) * (lsize / lblk_size) / (psize / pblk_size);
|
header.params.lblk_per_zone = zone_data_len(&header.params) * (lsize / lblk_size) / (psize / pblk_size);
|
||||||
printf(" initial estimate for lblk_per_zone: %lu\n", (unsigned long)header.params.lblk_per_zone);
|
printf(" initial estimate for lblk_per_zone: %lu\n", (unsigned long)header.params.lblk_per_zone);
|
||||||
|
@ -121,7 +128,7 @@ cbd_format(const char* dev,
|
||||||
printf(" pblk_shift=%hu\n", (unsigned short)header.params.pblk_shift);
|
printf(" pblk_shift=%hu\n", (unsigned short)header.params.pblk_shift);
|
||||||
printf(" lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift);
|
printf(" lblk_shift=%hu\n", (unsigned short)header.params.lblk_shift);
|
||||||
printf(" lba_elem_pblk_bytes=%hu\n", (unsigned short)header.params.lba_elem_pblk_bytes);
|
printf(" lba_elem_pblk_bytes=%hu\n", (unsigned short)header.params.lba_elem_pblk_bytes);
|
||||||
printf(" pbat_len=%hu\n", (unsigned short)header.params.pbat_len);
|
printf(" pbat_shift=%hu\n", (unsigned short)header.params.pbat_shift);
|
||||||
printf(" nr_zones=%lu\n", (unsigned long)header.params.nr_zones);
|
printf(" nr_zones=%lu\n", (unsigned long)header.params.nr_zones);
|
||||||
printf(" lblk_per_zone=%lu\n", (unsigned long)header.params.lblk_per_zone);
|
printf(" lblk_per_zone=%lu\n", (unsigned long)header.params.lblk_per_zone);
|
||||||
|
|
||||||
|
|
|
@ -29,18 +29,27 @@ verbose(uint level, const char* fmt, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ask_user_bool(const char* fmt, ...)
|
ask_user_bool(tristate_t auto_response, const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char* line = NULL;
|
char prompt[256];
|
||||||
size_t len = 0;
|
char* line;
|
||||||
|
size_t len;
|
||||||
int ret;
|
int ret;
|
||||||
bool answer;
|
bool answer;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
vsnprintf(prompt, sizeof(prompt), fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
again:
|
again:
|
||||||
vprintf(fmt, ap);
|
printf("%s [y/n]? ", prompt);
|
||||||
printf(" [y/n]? ");
|
if (auto_response != t_none) {
|
||||||
|
answer = (auto_response == t_true);
|
||||||
|
printf("%s\n", (answer ? "y" : "n"));
|
||||||
|
return answer;
|
||||||
|
}
|
||||||
|
line = NULL;
|
||||||
|
len = 0;
|
||||||
getline(&line, &len, stdin);
|
getline(&line, &len, stdin);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
switch (line[0]) {
|
switch (line[0]) {
|
||||||
|
|
Loading…
Reference in New Issue