這節我們來分析神奇而又nb的handle_stripe,2.6.21版本的處理raid5和raid6分別用handle_stripe5和handle_stripe6這兩個函式,我們這裡主要說handle_stripe5,handle_stripe6和handle_stripe5其實差不多,只要你理解raid6的原理並理解了handle_stripe5,那麼handle_stripe6自然便明白了。
前一節中已經把請求的bio插入到了合適的條帶中,那麼接下來就是要處理這個條帶了。。這個任務就由handle_stripe函式來完成。這一節先講講它是如何處理正常的讀寫,其它部分會在以後涉及到。由於讀比較簡單,所以先說說讀的情況。
對於讀來說,在make_request函式中已把要請求的bio加入到了條帶中某個裝置的toread鍊錶中。然後呼叫handle_stripe處理這個條帶。步驟如下:(這裡假設條帶中裝置緩衝區均為empty)
a、開始會統計這個條帶中有多少個r5dev上有需要處理的讀請求,找到乙個,to_read++,還會統計緩衝區的狀態以及失效盤的個數等。
b、這時,to_read值不為0,滿足中條件,可見,進入這個判定條件還是蠻多的:讀請求,非滿塊寫,同步,擴容等,確實,這些操作是需要先讀出資料。之後對於每個裝置緩衝區,如果有讀請求(dev->to_read)並且緩衝區狀態為empty(!test_bit(r5_locked, &dev->flags) && !test_bit(r5_uptodate, &dev->flags)),就會把緩衝區標誌位置為 want(set_bit(r5_locked, &dev->flags);set_bit(r5_wantread, &dev->flags);)表明要從底層讀取資料。
c、在handle_stripe5的末尾,統計那些裝置有讀請求。如果有讀請求的話,初始化r5dev中req,包括設定**函式bi_end_io=raid5_end_read_request,req的起始扇區及長度等,最後使用generic_make_request下發這個req。
d、請求處理完畢,raid5_end_read_request被呼叫,如果讀取資料成功的話,會把裝置緩衝區的r5_uptodate置為有效,並清除掉r5_locked位,表明緩衝區狀態為clean。到現在為止,我們已經把資料從磁碟上讀取到了條帶的裝置緩衝區中,但這僅僅讀到了緩衝區中,並沒有把資料填充到原始請求bio中。所以需要對這個條帶在進行一次處理,設定條帶stripe_handle為有效,呼叫release_stripe把條帶放到handle_list中在進行處理,並喚醒守護執行緒raid5d。
e、raid5d從handle_list中取出條帶,再次呼叫handle_stripe對條帶進行處理。這次我們發現緩衝區狀態為r5_uptodate即(test_bit(r5_uptodate, &dev->flags) && dev->toread條件滿足),呼叫copy_data函式將緩衝區的資料拷貝到bio相應的段中。如果bi_phys_segments等於0的話,那麼說明這個bio已經處理完畢,可以返回給上層了,則加入到return _bi的鍊錶中。
f、最後執行
通知上層處理完畢。
對於寫請求
的情況,比較複雜,涉及到了延遲寫,下面來一步一步分析:
a、與處理讀請求一樣,開始也統計條帶中有多少r5dev要處理的寫請求,如果有的話,to_write++,還會統計非滿塊寫的數量,如果該r5dev是非滿塊寫,則non_overwrite++;
b、如果條帶中有個裝置被標記為非滿塊寫,即r5_overwrite位有效,則需要先讀出這塊的資料(為什麼要讀出來下面再說)裝置緩衝區為want,表明需要從磁碟讀取資料。
c、接下來就判斷使用何種寫方式進行寫操作。我們知道raid5的寫資料的同時還是寫新校驗,這就決定要了寫資料首先要限度資料。這裡有兩種寫方式,說白了就是兩種計算校驗的方法,一種是rmw(read-modify-write),一種是rcw(reconstruct-write).第一種方式先讀出有寫請求的裝置和校驗盤上的資料,然後將這些讀出來的資料和要寫的資料做xor,求得新的校驗值。第2種方式是要讀出非滿塊寫和沒有寫請求裝置上的資料,這裡我們就看到了為何要標記非滿塊寫,由於使用rcw,那麼僅僅讀出來沒有寫請求上裝置的資料是不夠的。因為有非滿塊寫的存在,還要把非滿塊寫的裝置上資料讀出來,然後把copy其中一部分資料,這樣這個非滿塊寫裝置上的資料才可以用來計算新校驗。rcw就用這個新構造的資料和讀出來的資料以及要寫的資料(除去非滿塊寫)來計算新校驗。
d、以rmw為例,我們要先讀出有寫請求和校驗盤上的資料(如果緩衝區狀態為empty),這時我們可以看到有個對條帶狀態的判斷,即test_bit(stripe_preread_active, &sh->state) 。如果stripe_preread_active有效,則表明預讀啟用了,這時便可以傳送讀請求。如果無效的話,則set_bit(stripe_delayed, &sh->state);表明要延遲處理這個條帶。我們這裡以延遲處理條帶來繼續分析。安我的理解,延遲處理乙個條帶,其本質上就是處理條帶時盡可能地少讀取資料。
e、條帶被置為stripe_delayed,這一輪handle_stripe結束,在release_stripe函式中,會把這個條帶加入到delayed_list中,然後啟用塊裝置驅動blk_plug_device(conf->mddev->queue);當定時器到期時(預設3ms),核心通過一些類函式呼叫最終會呼叫md對列的q->unplug_fn方法,該方法有raid5_unplug_device實現,該方法會呼叫raid5_activate_delayed函式,從delayed_list中取出條帶,去掉stripe_delayed標記,設定stripe_preread_active有效,並將條帶加入到handle_list中,喚醒raid5d執行緒,處理該條帶。
f、handle_stripe函式再被呼叫,這時發現stripe_preread_active位有效,則將裝置緩衝區狀態為want,下發讀請求到下層。讀請求處理完畢,緩衝區狀態為clean,然後把條帶加入到handle_list中繼續進行處理。
g、handle_stripe函式再一次被呼叫,這時要讀的資料已經都讀出來,那麼便呼叫compute_parity5函式來計算新校驗值,此時緩衝區狀態為dirty,表明要有新資料寫到磁碟中,將to_writen鍊錶置空,並連線到written鍊錶。設定set_bit(r5_wantwrite, &sh->dev[i].flags),並且清楚掉stripe_preread_active,喚醒其他等待預讀的條帶。
i、raid5_end_write_request**函式被呼叫,資料寫成功,緩衝區狀態為clean,此時資料已經寫到磁碟上,但請求並沒有處理結束,所以還要吧條帶加入到handle_list中在進行處理。
j、handle_stripe有一次被呼叫,這事發現written鍊錶不為空並且緩衝區為clean了,便可以將請求返回了。
MD模組之處理讀寫過程分析 2
這一節講述raid5模組中處理讀寫流程。這個過程很複雜,最關鍵的函式就是handle stripe,處理一次讀或寫都會多次呼叫這個函式才能完成。當然,這個函式也是raid5模組的乙個核心函式,他還負責同步,重建,以及擴充套件的實現。在分析之前,我們需要準備一些預備知識 一 條帶 我們知道,raid5...
HDFS讀寫過程
讀過程 1 初始化filesystem,然後客戶端 client 用filesystem的open 函式開啟檔案 2 filesystem用rpc呼叫元資料節點,得到檔案的資料塊資訊,對於每乙個資料塊,元資料節點返回儲存資料塊的資料節點的位址。3 filesystem返回fsdatainputstr...
Hbase讀寫過程
補充 布隆過濾器引數型別有2種 row row col 細節描述 hbase使用memstore和storefile儲存對錶的更新。資料在更新時首先寫入log wal log 和記憶體 memstore 中,memstore中的資料是排序的,當memstore累計到一定閾值時,就會建立乙個新的mem...