device-mapper 块级重删(d
五、代码结构(3) I/O写流程
上一篇我们来介绍了dm dedup的空间管理
这一篇我们介绍核心流程I/O写流程
要看的特别清楚这部分的内容,需要结合我之前写过的《device-mapper 块级重删(dm dedup) <2>设计》请添加链接描述一起学习。
在块级重删 设计那一篇已经描述了这一系列的过程。
上一篇代码结构已经对kvs_hash和kvs_lbn的lookup和insert有了分析。
接下来我们来看看lookup和insert在写流程中的使用。
首先我们先看一下alloc_pbn_block给lbn的函数,后面都会用用到。
【
static int alloc_pbnblk_and_insert_lbn_pbn(struct dedup_config *dc,
u64 *pbn_new,
struct bio *bio, uint64_t lbn)
{
int r = 0;
struct lbn_pbn_value lbnpbn_value;
r = allocate_block(dc, pbn_new);
lbnpbn_value.pbn = *pbn_new;
do_io(dc, bio, *pbn_new);
r = dc->kvs_lbn_pbn->kvs_insert(dc->kvs_lbn_pbn, (void *)&lbn,
sizeof(lbn), (void *)&lbnpbn_value,
sizeof(lbnpbn_value));
return r;
}
】
1、no hash && no lbn
即:① compute_hash_bio(dc->desc_table, bio, hash); //对bio的data进行hash,获得到hash_pbn
-> ② dc->kvs_hash_pbn->kvs_lookup; //通过hash值,查找对应的hash_pbn_value,也就是pbn。
没有找到pbn ->③ handle_write_no_hash.[dc->kvs_lbn_pbn->kvs_lookup] //寻找bio的lbn是否存在
没有找到lbn -> ④ handle_write_no_hash.[__handle_no_lbn_pbn] //这里到了最终处理函数
这里为了减少篇章,去掉了资源申请错误处理和资源访问错误处理
static int __handle_no_lbn_pbn(struct dedup_config *dc,
struct bio *bio, uint64_t lbn, u8 *hash)
{
int r, ret;
u64 pbn_new;
struct hash_pbn_value hashpbn_value;
r = alloc_pbnblk_and_insert_lbn_pbn(dc, &pbn_new, bio, lbn);
hashpbn_value.pbn = pbn_new;
r = dc->kvs_hash_pbn->kvs_insert(dc->kvs_hash_pbn, (void *)hash,
dc->crypto_key_size,
(void *)&hashpbn_value,
sizeof(hashpbn_value));
r = dc->mdops->inc_refcount(dc->bmd, pbn_new);
dc->newwrites++;
Goto out;
inc_refcount_err:
ret = dc->kvs_hash_pbn->kvs_delete(dc->kvs_hash_pbn,
(void *)hash, dc->crypto_key_size);
kvs_insert_err:
ret = dc->kvs_lbn_pbn->kvs_delete(dc->kvs_lbn_pbn,
(void *)&lbn, sizeof(lbn));
ret = dc->mdops->dec_refcount(dc->bmd, pbn_new);
out:
return r;
}
2、no hash && has lbn
即:① compute_hash_bio(dc->desc_table, bio, hash); //对bio的data进行hash,获得到hash_pbn
-> ② dc->kvs_hash_pbn->kvs_lookup; //通过hash值,查找对应的hash_pbn_value,也就是pbn。
没有找到pbn ->③ handle_write_no_hash.[dc->kvs_lbn_pbn->kvs_lookup] //寻找bio的lbn是否存在
找到lbn -> ④ handle_write_no_hash.[__handle_has_lbn_pbn] //这里到了最终处理函数
static int __handle_has_lbn_pbn(struct dedup_config *dc,
struct bio *bio, uint64_t lbn, u8 *hash,
u64 pbn_old)
{
int r, ret;
u64 pbn_new;
struct hash_pbn_value hashpbn_value;
r = alloc_pbnblk_and_insert_lbn_pbn(dc, &pbn_new, bio, lbn);
hashpbn_value.pbn = pbn_new;
r = dc->kvs_hash_pbn->kvs_insert(dc->kvs_hash_pbn, (void *)hash,
dc->crypto_key_size,
(void *)&hashpbn_value,
sizeof(hashpbn_value));
r = dc->mdops->inc_refcount(dc->bmd, pbn_new);
r = dc->mdops->dec_refcount(dc->bmd, pbn_old);
dc->logical_block_counter--;
dc->overwrites++;
goto out;
dec_refcount_err:
ret = dc->mdops->dec_refcount(dc->bmd, pbn_new);
inc_refcount_err:
ret = dc->kvs_hash_pbn->kvs_delete(dc->kvs_hash_pbn, (void *)hash,
dc->crypto_key_size);
kvs_insert_err:
ret = dc->kvs_lbn_pbn->kvs_delete(dc->kvs_lbn_pbn, (void *)&lbn,
sizeof(lbn));
ret = dc->mdops->dec_refcount(dc->bmd, pbn_new);
out:
return r;
}
3、hash && no lbn
即:① compute_hash_bio(dc->desc_table, bio, hash); //对bio的data进行hash,获得到hash_pbn
-> ② dc->kvs_hash_pbn->kvs_lookup; //通过hash值,查找对应的hash_pbn_value,也就是pbn。
找到pbn ->③ handle_write_with_hash.[dc->kvs_lbn_pbn->kvs_lookup] //寻找bio的lbn是否存在
没有找到lbn -> ④ handle_write_no_hash.[__handle_no_lbn_pbn_with_hash] //这里到了最终处理函数
既然找到了hash_pbn,就是pbn可以复用的,直接将lbn将pbn关联就行
static int __handle_no_lbn_pbn_with_hash(struct dedup_config *dc,
struct bio *bio, uint64_t lbn,
u64 pbn_this,
struct lbn_pbn_value lbnpbn_value)
{
int r = 0, ret;
r = dc->mdops->inc_refcount(dc->bmd, pbn_this);
if (r < 0)
goto out;
lbnpbn_value.pbn = pbn_this;
r = dc->kvs_lbn_pbn->kvs_insert(dc->kvs_lbn_pbn, (void *)&lbn,
sizeof(lbn), (void *)&lbnpbn_value,
sizeof(lbnpbn_value));
if (r < 0)
goto kvs_insert_error;
dc->logical_block_counter++;
bio->bi_status = BLK_STS_OK;
bio_endio(bio);
dc->newwrites++;
goto out;
kvs_insert_error:
ret = dc->mdops->dec_refcount(dc->bmd, pbn_this);
out:
return r;
}
4、hash && lbn
即:① compute_hash_bio(dc->desc_table, bio, hash); //对bio的data进行hash,获得到hash_pbn
-> ② dc->kvs_hash_pbn->kvs_lookup; //通过hash值,查找对应的hash_pbn_value,也就是pbn。
找到pbn ->③ handle_write_with_hash.[dc->kvs_lbn_pbn->kvs_lookup] //寻找bio的lbn是否存在
找到lbn -> ④ handle_write_no_hash.[__handle_has_lbn_pbn_with_hash] //这里到了最终处理函数
既然找到了hash_pbn和lbn_pbn,这里存在了两种情况:
一、overwrite,也就是hash_pbn的pbn和lbn_pbn是一个。
二、No relationship,也就是这是将一个pbn的内容写到一个新的lbn位置
static int __handle_has_lbn_pbn_with_hash(struct dedup_config *dc,
struct bio *bio, uint64_t lbn,
u64 pbn_this,
struct lbn_pbn_value lbnpbn_value)
{
int r = 0, ret;
struct lbn_pbn_value this_lbnpbn_value;
u64 pbn_old;
pbn_old = lbnpbn_value.pbn;
if (pbn_this == pbn_old)
goto out;
r = dc->mdops->inc_refcount(dc->bmd, pbn_this);
if (r < 0)
goto out;
this_lbnpbn_value.pbn = pbn_this;
r = dc->kvs_lbn_pbn->kvs_insert(dc->kvs_lbn_pbn, (void *)&lbn,
sizeof(lbn),
(void *)&this_lbnpbn_value,
sizeof(this_lbnpbn_value));
if (r < 0)
goto kvs_insert_err;
r = dc->mdops->dec_refcount(dc->bmd, pbn_old);
if (r < 0)
goto dec_refcount_err;
goto out;
dec_refcount_err:
ret = dc->kvs_lbn_pbn->kvs_insert(dc->kvs_lbn_pbn, (void *)&lbn,
sizeof(lbn), (void *)&lbnpbn_value,
sizeof(lbnpbn_value));
if (ret < 0)
DMERR("Error in overwriting lbn->pbn_this [%llu] with"
" lbn-pbn_old entry [%llu].", this_lbnpbn_value.pbn,
lbnpbn_value.pbn);
kvs_insert_err:
ret = dc->mdops->dec_refcount(dc->bmd, pbn_this);
if (ret < 0)
DMERR("Error in decrementing previously incremented refcount.");
out:
if (r == 0) {
bio->bi_status = BLK_STS_OK;
bio_endio(bio);
dc->overwrites++;
}
return r;
}
这一篇介绍了,写流程的四种情况,更加清晰了解释了dm dedup设计一文中的流程图。
希望读者看完后,能够对dm dedup这种简单逻辑的方式所吸引,从而喜欢上块重删这个技术。
--------------未完待续--------------
【本文只在51cto博客作者 “底层存储技术” https://blog.51cto.com/12580077 个人发布,公众号发布:存储之谷】,如需转载,请于本人联系,谢谢。
相关文章