Rewrite lbatview_elem_realloc

* Only touch the data we need to touch.
 * Handle failure gracefully by reverting to old data.
 * Adjust libcbd check_one_lblk to ignore unused allocs.
This commit is contained in:
Tom Marshall 2019-11-02 09:35:49 -07:00
parent 5be74b3346
commit 7a743a7e65
2 changed files with 76 additions and 73 deletions

View File

@ -315,56 +315,64 @@ int
lbatview_elem_realloc(struct lbatview* lv, u64 lblk, u32 len)
{
int ret = 0;
u32 req_nalloc;
int err;
u32 elem_off;
u32 elem_len;
u32 req_nalloc;
u32 cur_nalloc;
u32 old_nalloc;
u32 off;
u32 n;
u64 pblk;
u32 elem_lelen;
u64 elem_lepblk;
if (len == CBD_UNCOMPRESSED) {
req_nalloc = lblk_per_pblk(lv->params);
}
else {
req_nalloc = DIV_ROUND_UP(len, PBLK_SIZE);
}
mutex_lock(&lv->lock);
elem_off = lbatview_elem_off(lv, lblk);
elem_lelen = __cpu_to_le32(len);
lbatview_wmem(lv, elem_off, lba_elem_len_bytes(lv->params), &elem_lelen);
off = elem_off + lba_elem_len_bytes(lv->params);
for (n = 0; n < lblk_per_pblk(lv->params); ++n, off += lba_elem_pblk_bytes(lv->params)) {
elem_lepblk = 0;
lbatview_rmem(lv, off, lba_elem_pblk_bytes(lv->params), &elem_lepblk);
pblk = __le64_to_cpu(elem_lepblk);
if (pblk == 0) {
if (n >= req_nalloc) {
break;
}
req_nalloc = (len == CBD_UNCOMPRESSED) ?
lblk_per_pblk(lv->params) :
DIV_ROUND_UP(len, PBLK_SIZE);
elem_lelen = 0;
lbatview_rmem(lv, elem_off, lba_elem_len_bytes(lv->params), &elem_lelen);
elem_len = __le32_to_cpu(elem_lelen);
cur_nalloc = (elem_len == CBD_UNCOMPRESSED) ?
lblk_per_pblk(lv->params) :
DIV_ROUND_UP(elem_len, PBLK_SIZE);
old_nalloc = cur_nalloc;
while (cur_nalloc < req_nalloc) {
off = elem_off + lba_elem_len_bytes(lv->params) +
cur_nalloc * lba_elem_pblk_bytes(lv->params);
pblk = lbatview_alloc_pblk(lv);
if (pblk == PBLK_NONE) {
printk(KERN_ERR "%s: lbatview_alloc_pblk failed\n", __func__);
ret = -ENOSPC;
goto out; /* XXX: undo */
req_nalloc = old_nalloc;
goto do_free;
}
elem_lepblk = __cpu_to_le64(pblk);
lbatview_wmem(lv, off, lba_elem_pblk_bytes(lv->params), &elem_lepblk);
++cur_nalloc;
}
else {
if (n >= req_nalloc) {
do_free:
while (cur_nalloc > req_nalloc) {
--cur_nalloc;
off = elem_off + lba_elem_len_bytes(lv->params) +
cur_nalloc * lba_elem_pblk_bytes(lv->params);
elem_lepblk = 0;
lbatview_wmem(lv, off, lba_elem_pblk_bytes(lv->params), &elem_lepblk);
ret = lbatview_free_pblk(lv, pblk);
if (ret) {
lbatview_rmem(lv, off, lba_elem_pblk_bytes(lv->params), &elem_lepblk);
pblk = __le64_to_cpu(elem_lepblk);
err = lbatview_free_pblk(lv, pblk);
if (err) {
printk(KERN_ERR "%s: lbatview_free_pblk failed\n", __func__);
goto out; /* XXX: undo */
}
}
ret = err;
}
}
out:
if (!ret) {
elem_lelen = __cpu_to_le32(len);
lbatview_wmem(lv, elem_off, lba_elem_len_bytes(lv->params), &elem_lelen);
}
mutex_unlock(&lv->lock);
return ret;
}

View File

@ -65,7 +65,7 @@ check_one_lblk(const struct cbd_params* params,
{
struct lba* lba;
u8* lba_buf;
u32 c_len;
u32 n_alloc;
u32 n;
u64 pblk;
@ -87,12 +87,13 @@ check_one_lblk(const struct cbd_params* params,
printf(" :E: Length out of bounds\n");
return;
}
c_len = (lba->len == CBD_UNCOMPRESSED) ? PBLK_SIZE * lblk_per_pblk(params) : lba->len;
for (n = 0; n < lblk_per_pblk(params); ++n) {
pblk = lba->pblk[n];
if (c_len > PBLK_SIZE * n) {
n_alloc = (lba->len == CBD_UNCOMPRESSED) ?
lblk_per_pblk(params) :
DIV_ROUND_UP(lba->len, PBLK_SIZE);
for (n = 0; n < n_alloc; ++n) {
u32 pblk_zone;
u32 rel_pblk;
pblk = lba->pblk[n];
if (pblk < CBD_HEADER_BLOCKS) {
printf(" [%u] :E: Alloc in header: %lu\n", n, pblk);
continue;
@ -121,12 +122,6 @@ check_one_lblk(const struct cbd_params* params,
}
pblk_used[pblk_zone][rel_pblk/8] |= (1 << (rel_pblk % 8));
}
else {
if (pblk) {
printf(" [%u] :E: Unexpected pblk alloc: %lu\n", n, pblk);
}
}
}
free(lba);
}