本文共 8698 字,大约阅读时间需要 28 分钟。
五、代码结构(3) I/O写流程
上一篇我们来介绍了dm dedup的空间管理
这一篇我们介绍核心流程I/O写流程要看的特别清楚这部分的内容,需要结合我之前写过的一起学习。
在块级重删 设计那一篇已经描述了这一系列的过程。
上一篇代码结构已经对kvs_hash和kvs_lbn的lookup和insert有了分析。接下来我们来看看lookup和insert在写流程中的使用。首先我们先看一下alloc_pbn_block给lbn的函数,后面都会用用到。
【 /*因为现在还没有pbn来放置lbn,所以先申请一个pbn_new*/ 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);/*找到一个新的pbn*/ lbnpbn_value.pbn = *pbn_new; do_io(dc, bio, *pbn_new); /*将bio的数据放置到pbn_new的位置*/ r = dc->kvs_lbn_pbn->kvs_insert(dc->kvs_lbn_pbn, (void *)&lbn, sizeof(lbn), (void *)&lbnpbn_value, sizeof(lbnpbn_value)); /*将新的lbn_pbn的关系记录到kvs_lbn_pbn中*/ 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; /* Create a new lbn-pbn mapping for given lbn,注意这里是pbn_new */ r = alloc_pbnblk_and_insert_lbn_pbn(dc, &pbn_new, bio, lbn); /* Inserts new hash-pbn mapping for given hash. 由于dm_io已经将bio数据放置到pbn中,然后hash_pbn记录*/ 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)); /* Increments refcount for new pbn entry created. 增加一个引用*/ r = dc->mdops->inc_refcount(dc->bmd, pbn_new); /* On all successful steps increment new write count. */ dc->newwrites++;/* 在dc中记录下newwrites增加,为了更好的统计和分析行为*/ goto out;/* Error handling code path */inc_refcount_err: /* Undo actions taken in hash-pbn kvs insert. */ ret = dc->kvs_hash_pbn->kvs_delete(dc->kvs_hash_pbn, (void *)hash, dc->crypto_key_size);kvs_insert_err: /* Undo actions taken in alloc_pbnblk_and_insert_lbn_pbn. */ 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; /* Allocates a new block for new pbn and inserts lbn-pbn lapping.注意这是覆盖 */ r = alloc_pbnblk_and_insert_lbn_pbn(dc, &pbn_new, bio, lbn); /* Inserts new hash-pbn entry for given hash. */ 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)); /* Increments refcount of new pbn. */ r = dc->mdops->inc_refcount(dc->bmd, pbn_new); /*注意这里需要将pbn_new+,pbn_old-,这样有可能pbn_old减到可回收的可能*/ /* Decrements refcount for old pbn and decrement logical block cnt. */ r = dc->mdops->dec_refcount(dc->bmd, pbn_old); dc->logical_block_counter--; /* On all successful steps increment overwrite count. */ dc->overwrites++; /*这里是overwrites++,和上面的newwrites不一样*/ goto out;/* Error handling code path. */dec_refcount_err: /* Undo actions taken while incrementing refcount of new pbn. */ 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: /* Undo actions taken in alloc_pbnblk_and_insert_lbn_pbn. */ 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; /* Increments refcount of this passed pbn */ r = dc->mdops->inc_refcount(dc->bmd, pbn_this); if (r < 0) goto out; lbnpbn_value.pbn = pbn_this; /* Insert lbn->pbn_this entry */ 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); /*bio完成*/ dc->newwrites++; goto out;kvs_insert_error: /* Undo actions taken while incrementing refcount of this pbn. */ 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; /* special case, overwrite same LBN/PBN with same data */ if (pbn_this == pbn_old) goto out; /*如果hash_pbn和lbn_pbn不相等,1、增加pbn引用和新lbn和pbn关联*/ /* Increments refcount of this passed pbn */ r = dc->mdops->inc_refcount(dc->bmd, pbn_this); if (r < 0) goto out; this_lbnpbn_value.pbn = pbn_this; /* Insert lbn->pbn_this entry */ 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; /*减小lbn之前记住的pbn_old的引用,这个pbn_old将可能被回收*/ /* Decrement refcount of old pbn */ r = dc->mdops->dec_refcount(dc->bmd, pbn_old); if (r < 0) goto dec_refcount_err; goto out; /* all OK */dec_refcount_err: /* Undo actions taken while decrementing refcount of old pbn */ /* Overwrite lbn->pbn_this entry with lbn->pbn_old entry */ 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/2311649