From 7a743a7e65400e32526eaaf98f249f5f414a01f2 Mon Sep 17 00:00:00 2001 From: Tom Marshall Date: Sat, 2 Nov 2019 09:35:49 -0700 Subject: [PATCH] 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. --- dm-compress/lbatview.c | 80 +++++++++++++++++++++++------------------- libcbd/check.c | 69 +++++++++++++++++------------------- 2 files changed, 76 insertions(+), 73 deletions(-) diff --git a/dm-compress/lbatview.c b/dm-compress/lbatview.c index 98a9910..34a448d 100644 --- a/dm-compress/lbatview.c +++ b/dm-compress/lbatview.c @@ -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)) { + 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; + 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; + } +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_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; - } - 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 */ - } - elem_lepblk = __cpu_to_le64(pblk); - lbatview_wmem(lv, off, lba_elem_pblk_bytes(lv->params), &elem_lepblk); - } - else { - if (n >= req_nalloc) { - elem_lepblk = 0; - lbatview_wmem(lv, off, lba_elem_pblk_bytes(lv->params), &elem_lepblk); - ret = lbatview_free_pblk(lv, pblk); - if (ret) { - printk(KERN_ERR "%s: lbatview_free_pblk failed\n", __func__); - goto out; /* XXX: undo */ - } - } + err = lbatview_free_pblk(lv, pblk); + if (err) { + printk(KERN_ERR "%s: lbatview_free_pblk failed\n", __func__); + 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; } diff --git a/libcbd/check.c b/libcbd/check.c index 3f54443..e2cd1b2 100644 --- a/libcbd/check.c +++ b/libcbd/check.c @@ -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,45 +87,40 @@ 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) { + 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 (c_len > PBLK_SIZE * n) { - u32 pblk_zone; - u32 rel_pblk; - if (pblk < CBD_HEADER_BLOCKS) { - printf(" [%u] :E: Alloc in header: %lu\n", n, pblk); - continue; - } - pblk_zone = (pblk - CBD_HEADER_BLOCKS) / zone_len(params); - if (pblk_zone >= params->nr_zones) { - printf(" [%u] :E: Alloc beyond end: %lu\n", n, pblk); - continue; - } - if (pblk < zone_data_off(params, pblk_zone)) { - printf(" [%u] :E: Alloc in metadata: %lu\n", n, pblk); - continue; - } - rel_pblk = pblk - zone_data_off(params, pblk_zone); - /* XXX: Cannot happen? */ - if (rel_pblk >= pbat_len(params) * PBLK_SIZE_BITS) { - printf(" [%u] :E: Alloc out of zone: %lu\n", n, pblk); - continue; - } - printf(" [%u] pblk=%lu pblk_zone=%u rel_pblk=%u\n", n, - (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)); + if (pblk < CBD_HEADER_BLOCKS) { + printf(" [%u] :E: Alloc in header: %lu\n", n, pblk); + continue; } - else { - if (pblk) { - printf(" [%u] :E: Unexpected pblk alloc: %lu\n", n, pblk); - } + pblk_zone = (pblk - CBD_HEADER_BLOCKS) / zone_len(params); + if (pblk_zone >= params->nr_zones) { + printf(" [%u] :E: Alloc beyond end: %lu\n", n, pblk); + continue; } + if (pblk < zone_data_off(params, pblk_zone)) { + printf(" [%u] :E: Alloc in metadata: %lu\n", n, pblk); + continue; + } + rel_pblk = pblk - zone_data_off(params, pblk_zone); + /* XXX: Cannot happen? */ + if (rel_pblk >= pbat_len(params) * PBLK_SIZE_BITS) { + printf(" [%u] :E: Alloc out of zone: %lu\n", n, pblk); + continue; + } + printf(" [%u] pblk=%lu pblk_zone=%u rel_pblk=%u\n", n, + (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);