溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

device-mapper 塊級重刪(dm dedup) <3>代碼結(jié)構(gòu)(3)

發(fā)布時間:2020-04-08 17:52:38 來源:網(wǎng)絡(luò) 閱讀:542 作者:慢慢存儲路 欄目:建站服務(wù)器

五、代碼結(jié)構(gòu)(3) I/O寫流程

上一篇我們來介紹了dm dedup的空間管理
這一篇我們介紹核心流程I/O寫流程

device-mapper 塊級重刪(dm dedup) <3>代碼結(jié)構(gòu)(3)

要看的特別清楚這部分的內(nèi)容,需要結(jié)合我之前寫過的《device-mapper 塊級重刪(dm dedup) <2>設(shè)計》請?zhí)砑渔溄用枋鲆黄饘W(xué)習(xí)。

在塊級重刪 設(shè)計那一篇已經(jīng)描述了這一系列的過程。
上一篇代碼結(jié)構(gòu)已經(jīng)對kvs_hash和kvs_lbn的lookup和insert有了分析。
接下來我們來看看lookup和insert在寫流程中的使用。

首先我們先看一下alloc_pbn_block給lbn的函數(shù),后面都會用用到。


            【
                            /*因為現(xiàn)在還沒有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的數(shù)據(jù)放置到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的關(guān)系記錄到kvs_lbn_pbn中*/
                            return r;
                    }
             】

1、no hash && no lbn
即:① compute_hash_bio(dc->desc_table, bio, hash); //對bio的data進(jìn)行hash,獲得到hash_pbn
-> ② dc->kvs_hash_pbn->kvs_lookup; //通過hash值,查找對應(yīng)的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] //這里到了最終處理函數(shù)
這里為了減少篇章,去掉了資源申請錯誤處理和資源訪問錯誤處理

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已經(jīng)將bio數(shù)據(jù)放置到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增加,為了更好的統(tǒng)計和分析行為*/
    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進(jìn)行hash,獲得到hash_pbn
-> ② dc->kvs_hash_pbn->kvs_lookup; //通過hash值,查找對應(yīng)的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] //這里到了最終處理函數(shù)

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進(jìn)行hash,獲得到hash_pbn
-> ② dc->kvs_hash_pbn->kvs_lookup; //通過hash值,查找對應(yīng)的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] //這里到了最終處理函數(shù)
既然找到了hash_pbn,就是pbn可以復(fù)用的,直接將lbn將pbn關(guān)聯(lián)就行

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進(jìn)行hash,獲得到hash_pbn
-> ② dc->kvs_hash_pbn->kvs_lookup; //通過hash值,查找對應(yīng)的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] //這里到了最終處理函數(shù)
既然找到了hash_pbn和lbn_pbn,這里存在了兩種情況:
一、overwrite,也就是hash_pbn的pbn和lbn_pbn是一個。
二、No relationship,也就是這是將一個pbn的內(nèi)容寫到一個新的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關(guān)聯(lián)*/
    /* 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設(shè)計一文中的流程圖。
希望讀者看完后,能夠?qū)m dedup這種簡單邏輯的方式所吸引,從而喜歡上塊重刪這個技術(shù)。

--------------未完待續(xù)--------------

【本文只在51cto博客作者 “底層存儲技術(shù)” https://blog.51cto.com/12580077 個人發(fā)布,公眾號發(fā)布:存儲之谷】,如需轉(zhuǎn)載,請于本人聯(lián)系,謝謝。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI