RAID5 IO處理之寫請求代碼詳解( 四 )

以上,讀改寫處理結束 。
3 重構寫重構寫整體邏輯與讀改寫相差不大,我們只將不相同的部分說明如下,整體邏輯大家可自行串聯 。
第一輪讀數據:
static void handle_stripe_dirtying(struct r5conf *conf,struct stripe_head *sh,struct stripe_head_state *s,int disks){ int rmw = 0, rcw = 0, i; sector_t recovery_cp = conf->mddev->recovery_cp; /** 以下幾種情況不能進行讀改寫只能使用重構寫* 1.RAID級別為6,因為讀改寫利用的是異或運算的特性,因此RAID6不適用* 2.IO起始范圍超過了同步的進度 。因為讀改寫需要用舊的數據和舊的校驗,*如果舊數據見不是一致的,那么再進行異或運算數據也是不一致的,*/ if (conf->max_degraded == 2 ||(recovery_cp < MaxSector && sh->sector >= recovery_cp)) {/* Calculate the real rcw later - for now make it* look like rcw is cheaper*/rcw = 1; rmw = 2;pr_debug("force RCW max_degraded=%u, recovery_cp=%llu sh->sector=%llu\n",conf->max_degraded, (unsigned long long)recovery_cp,(unsigned long long)sh->sector); } else for (i = disks; i--; ) {/* 如果dev有寫請求或保存的是校驗值那么該dev在讀改寫邏輯中是需要讀的 */struct r5dev *dev = &sh->dev[i];if ((dev->towrite || i == sh->pd_idx) &&!test_bit(R5_LOCKED, &dev->flags) &&!(test_bit(R5_UPTODATE, &dev->flags) ||test_bit(R5_Wantcompute, &dev->flags))) {if (test_bit(R5_Insync, &dev->flags))rmw++;elsermw += 2*disks;/* cannot read it */}/* 如果dev非滿寫(為寫滿4K或無IO)并且不是校驗那么該dev在重構寫邏輯中是需要讀的 */if (!test_bit(R5_OVERWRITE, &dev->flags) && i != sh->pd_idx &&!test_bit(R5_LOCKED, &dev->flags) &&!(test_bit(R5_UPTODATE, &dev->flags) ||test_bit(R5_Wantcompute, &dev->flags))) {if (test_bit(R5_Insync, &dev->flags)) rcw++;elsercw += 2*disks;} } /* 進行重構寫需要讀的次數少 */ if (rcw <= rmw && rcw > 0) {/* want reconstruct write, but need to get some data */int qread =0;rcw = 0;for (i = disks; i--; ) {struct r5dev *dev = &sh->dev[i];/** 滿足以下條件下發讀請求*1. 非滿寫*2. 不是校驗*3. 尚未下發請求*4. 當前page中不是最新數據且不需要計算*/if (!test_bit(R5_OVERWRITE, &dev->flags) &&i != sh->pd_idx && i != sh->qd_idx &&!test_bit(R5_LOCKED, &dev->flags) &&!(test_bit(R5_UPTODATE, &dev->flags) ||test_bit(R5_Wantcompute, &dev->flags))) {rcw++;if (!test_bit(R5_Insync, &dev->flags))continue; /* it's a failed drive *//* 給條帶/設備上鎖表明正在進行IO */set_bit(R5_LOCKED, &dev->flags);/* 表明該條帶/設備要調度讀請求 */set_bit(R5_Wantread, &dev->flags);s->locked++;/* locked增加計數 */qread++;}} } /* locked不等于0本輪不調度schedule_reconstruction */ if ((s->req_compute || !test_bit(STRIPE_COMPUTE_RUN, &sh->state)) &&(s->locked == 0 && (rcw == 0 || rmw == 0) &&!test_bit(STRIPE_BIT_DELAY, &sh->state)))schedule_reconstruction(sh, s, rcw == 0, 0);}在第二輪計算校驗的條帶處理中,因為直接使用數據段計算校驗段 , 因此不需要做 ops_run_prexor,后續下發寫請求和向上返回與讀改寫相同 。
滿寫是重構寫的一種特殊情況 , 即所有數據段都是滿寫,此時不需要讀舊數據,直接根據新數據計算校驗然后一起寫入 , 此時性能最好,我們在實際使用中,可以根據業務寫IO的buffer大小調整數據盤個數和chunk大小 , 以達到滿寫的狀態 。

推薦閱讀