Raid5.h注释翻译
Linux內(nèi)核2.6.32中的Raid5.h一上來(lái)就是150多行的注釋!看起來(lái)好辛苦,簡(jiǎn)單翻譯一份留在這里,翻譯不對(duì)的地方希望大家指出~
?
每個(gè)條紋都包含一個(gè)buffer,每個(gè)buffer和每個(gè)磁盤對(duì)應(yīng)。每個(gè)buffer都包括一些列的狀態(tài),存儲(chǔ)在flags字段中。這些狀態(tài)之間的切換“幾乎”都是異步的,并且在一個(gè)“每條紋”的自旋鎖中進(jìn)行。一些非常特殊的標(biāo)志位改變可以在bi_end_io中進(jìn)行,這些改變不會(huì)由自旋鎖保護(hù)。
兩個(gè)標(biāo)志位R5_UPTODATE和R5_LOCKED指出四種不同的狀態(tài):
State Empty == !UPTODATE, !LOCK
?????? 內(nèi)存(buffer)中沒(méi)有數(shù)據(jù),而且也沒(méi)有活躍的請(qǐng)求
State Want == !UPTODATE, LOCK
?????? 這個(gè)塊上提交有讀請(qǐng)求
State Dirty == UPTODATE, LOCK
?????? 內(nèi)存中有數(shù)據(jù),正在被寫入磁盤
State Clean == UPTODATE, !LOCK
?????? 內(nèi)存中有數(shù)據(jù),并且和磁盤上的數(shù)據(jù)是同步的
狀態(tài)轉(zhuǎn)換可能:
?*? Empty -> Want?? - 讀或者寫(寫操作需要讀舊數(shù)據(jù)用于更新校驗(yàn))
?*? Empty -> Dirty? - 計(jì)算校驗(yàn)數(shù)據(jù)(sync或者重構(gòu)寫)
?*? Empty -> Clean? - 一個(gè)失效的設(shè)備上恢復(fù)出來(lái)的數(shù)據(jù)
?*? Want? -> Empty? - 讀失敗
?*? Want? -> Clean? - 讀請(qǐng)求成功完成
?*? Dirty -> Clean? - 寫請(qǐng)求成功完成
?*? Dirty -> Clean? - 寫失敗
?*? Clean -> Dirty? - 計(jì)算校驗(yàn)數(shù)據(jù)(sync或者重構(gòu)、讀改寫)
Want->Empty, Want->Clean, Dirty->Clean的過(guò)程都發(fā)生在b_end_io的中斷中。每次都要在釋放鎖標(biāo)記位之前設(shè)置Uptodate位。
只剩下一種多狀態(tài)轉(zhuǎn)換可能:Want->Dirty->Clean。這種轉(zhuǎn)換是安全的,因?yàn)?#xff0c;試想一個(gè)標(biāo)記為Clean的buffer如果實(shí)際上是dirty的,最壞情況便是推遲了一些動(dòng)作,條紋會(huì)在轉(zhuǎn)換完成的時(shí)候注意到并且被重新調(diào)度。
上述狀態(tài)并未包括一種可能性,即如果一個(gè)設(shè)備失效,同時(shí)有一個(gè)spare的設(shè)備正在重構(gòu)。我們無(wú)法區(qū)分一個(gè)由計(jì)算校驗(yàn)而產(chǎn)生的clean的塊還是一個(gè)成功寫入spare設(shè)備的塊(或者是resync進(jìn)行中的校驗(yàn))。為了區(qū)分這兩種情況,條紋中的STRIPE_INSYNC為用以指明。當(dāng)一個(gè)寫操作是面向spare設(shè)備,或者沒(méi)有spare設(shè)備的時(shí)候面向校驗(yàn)盤,該位將被置位。一個(gè)sync請(qǐng)求將復(fù)位該位,當(dāng)我們發(fā)現(xiàn)(置位并且)沒(méi)有任何buffer鎖住的時(shí)候,就知道sync完成了。
md設(shè)備的buffer通過(guò)make_request是依附在合適的條紋中,這些條紋在兩個(gè)b_reqnext鏈表之一。bh_read是讀請(qǐng)求鏈表,bh_write是寫請(qǐng)求鏈表。一個(gè)buffer應(yīng)該是不可能同時(shí)存在于兩個(gè)鏈表中,但是我們無(wú)法保證這一點(diǎn),因此需要做更多的許可。
如果一個(gè)buffer對(duì)應(yīng)的cache buffer標(biāo)記為Uptodate的并且在讀鏈表中,數(shù)據(jù)將拷貝到讀緩沖區(qū),并且調(diào)用自己的b_end_io例程。這種情況僅僅發(fā)生在buffer剛剛成功讀取時(shí)候的end_request例程中。end_request需要將buffer從列表中移除,然后設(shè)置buffer的Uptodate位。其他線程僅僅在他們第一次檢測(cè)Uptodate被設(shè)置的時(shí)候這么做,一旦檢測(cè)完成,就將buffer從讀隊(duì)列中移除。
當(dāng)一個(gè)寫鏈表中的buffer進(jìn)行寫提交時(shí)候,將被拷貝到cache buffer中,這時(shí)將標(biāo)記為dirty,并且移至第三個(gè)列表,written列表(bh_written)。一旦校驗(yàn)快和cache buffer都被成功寫入磁盤,written列表中的buffer們將隨b_end_io返回。
寫列表和讀列表都以fifo的方式工作。讀列表由device_lock保護(hù)。write和written列表由條紋鎖保護(hù)。device_lock將在條紋塊持有的時(shí)候聲明,僅僅用于人工修改列表,并且持有很短的時(shí)間。可以從中斷中聲明。
stripe cache中的條紋可以在兩個(gè)列表中的一個(gè)里(也可以一個(gè)都不在)?!胺腔顒?dòng)列表”包括了當(dāng)前沒(méi)有被任何請(qǐng)求使用的列表,可以自由的由其他條紋使用?!疤幚砹斜怼卑诵枰茨撤N方法處理的條紋。這些列表都是fifo的隊(duì)列。每個(gè)條紋也都(可能的)連接到一個(gè)哈希桶中,因此可以由扇區(qū)號(hào)索引到。條紋沒(méi)有被哈希的,一定是在非活動(dòng)列表中,并且一般都是在前頭。所有的條紋都是以這種方式開(kāi)始自己的生存期。
非活動(dòng)列表、處理列表和哈希桶列表都由device_lock保護(hù)
---非活動(dòng)列表中的條紋永遠(yuǎn)不會(huì)獲得其條紋鎖
---條紋都有引用計(jì)數(shù),如果count==0,則必定在某個(gè)列表中
---如果一個(gè)條紋必須需要處理,STRIPE_HANDLE置位
---當(dāng)引用計(jì)數(shù)到達(dá)0,如果STRIPE_HANDLE沒(méi)有置位,該條紋放在非活動(dòng)列表中,否則放在處理列表中
結(jié)合STRIPE_HANDLE僅僅當(dāng)條紋具有一個(gè)非0的引用計(jì)數(shù)的情況下才能被復(fù)位,這意味著如果引用計(jì)數(shù)到達(dá)0并且STRIPE_HANDLE被置位,該條紋一定在處理列表中,如果STRIPE_HANDLE復(fù)位,該條紋一定在非活動(dòng)列表中。
可能的轉(zhuǎn)換包括:
---沒(méi)有哈希/非活躍條紋---->激活(get_active_stripe())
?? ++設(shè)備上鎖--檢驗(yàn)哈希--unlink條紋--cnt++--clean條紋--哈希條紋--設(shè)備解鎖
---哈希(很可能是活躍)的條紋--->激活(get_active_stripe())
?? ++設(shè)備上鎖--檢驗(yàn)哈希--if(!cnt++)unlink條紋--設(shè)備解鎖
---將一個(gè)請(qǐng)求加到一個(gè)活躍條紋頭上(add_stripe_bh())
?? ++設(shè)備上鎖--附加buffer--設(shè)備解鎖
---處理一個(gè)條紋(handle_stripe())
?? ++條文上鎖--清STRIPE_HANDLE位--(設(shè)備上鎖--檢測(cè)buffers--設(shè)備解鎖--)--改變狀態(tài)--記錄需要的io/ops--條紋解鎖--調(diào)度io/ops
---釋放一個(gè)活躍的條紋(release_stripe())
?? ++設(shè)備上鎖--if(!--cnt){根據(jù)STRIPE_HANDLE將條紋放回處理列表或者非活躍列表}--設(shè)備解鎖
引用計(jì)數(shù)記錄了激活了這個(gè)條紋的線程數(shù)+正在處理這個(gè)條紋的raid5d+cache buffer上的活躍請(qǐng)求數(shù)目,如果條紋正在進(jìn)行條紋操作,那么再加1.
對(duì)條紋的操作在條紋鎖的外面進(jìn)行,主要包括:
---在stripe cache和用戶應(yīng)用緩沖之間拷貝數(shù)據(jù)
---為了減少一次磁盤訪問(wèn)進(jìn)行的塊(重構(gòu))計(jì)算,或者恢復(fù)一個(gè)丟失的塊
---寫操作中的更新校驗(yàn)
---檢測(cè)校驗(yàn)是否正確
---運(yùn)行到磁盤的I/O操作
這些操作都由raid5_run_ops進(jìn)行,這個(gè)函數(shù)使用了async_tx相關(guān)api,使用專用的硬件以(可選的)減少操作負(fù)載。當(dāng)請(qǐng)求一個(gè)操作時(shí)候,handle_stripe設(shè)置操作的pending位并且計(jì)數(shù)加一。每當(dāng)計(jì)數(shù)為非0的時(shí)候,raid5_run_ops運(yùn)行。
為了避免一些操作被請(qǐng)求而另一些操作正在進(jìn)行的情況,操作之間要服從一些嚴(yán)格的依賴:
(1)因?yàn)樾r?yàn)檢查操作破壞了校驗(yàn)塊的緩存中版本,所以必須防止檢查進(jìn)程進(jìn)行中的依賴校驗(yàn)的操作,比如寫操作和計(jì)算塊(即恢復(fù)塊)操作。一些dma機(jī)器可以在不破壞校驗(yàn)塊的前提下進(jìn)行檢查操作,這時(shí)校驗(yàn)塊將被重新標(biāo)記為實(shí)時(shí)(假設(shè)檢查操作成功)并且不從磁盤中重新讀取。
(2)當(dāng)一個(gè)寫請(qǐng)求到來(lái)時(shí),要立即鎖住相關(guān)的塊,標(biāo)記這些塊為過(guò)期。這造成了新的讀請(qǐng)求被攔截,并且?guī)?lái)了校驗(yàn)檢查和塊的計(jì)算操作。
(3)一旦有塊計(jì)算請(qǐng)求,handle_stripe將這些塊視作已經(jīng)實(shí)時(shí)有效。raid5_run_ops保證任何獨(dú)立于塊計(jì)算結(jié)果的操作都在塊計(jì)算完成之后被初始化。
操作狀態(tài) - sh->lock之外能看到的內(nèi)部狀態(tài)
一般的,_idle表示什么都沒(méi)有進(jìn)行中,_run表示一個(gè)數(shù)據(jù)操作正在進(jìn)行,_result表示數(shù)據(jù)操作的結(jié)果是穩(wěn)定的(即運(yùn)算完了),并且可以受到(別的操作影響)。對(duì)于像biofill這樣的簡(jiǎn)單操作和只有一個(gè)_idle和_run狀態(tài)的計(jì)算,都用sh->state標(biāo)志位表示(STRIPE_BIOFILL_RUN和STRIPE_COMPUTE_RUN)。
?
轉(zhuǎn)載于:https://blog.51cto.com/luckybins/666430
與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的Raid5.h注释翻译的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: winform dategridview
- 下一篇: netapp学习(五)---创建volu