linux内核的冒险md来源释义# 14raid5非条块读
生活随笔
收集整理的這篇文章主要介紹了
linux内核的冒险md来源释义# 14raid5非条块读
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
linux內核的冒險md來源釋義# 14raid5非條塊讀 轉載請注明出處:http://blog.csdn.net/liumangxiong
假設是非條塊內讀。那么就至少涉及到兩個條塊的讀,這就須要分別從這兩個條塊內讀出數據。然后再湊成整個結果返回給上層。接下來我們將看到怎樣將一個完整的bio讀請求拆分成多個子請求下發到磁盤,從磁盤返回之后再又一次組合成請求結果返回給上層的。 4097 logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); 4098 last_sector = bi->bi_sector + (bi->bi_size>>9); 4099 bi->bi_next = NULL; 4100 bi->bi_phys_segments = 1; /* over-loaded to count active stripes */
首先計算請求起始位置,由于md下發到磁盤數據請求的最小單位為STRIPE_SECTORS,所以這里要將請求對齊。計算出請求起始位置為logical_sector?,結束位置為last_sector。4100行復用bi_phys_segments?用于計數下發條帶數,這里防止意外釋放先設置為1。
在這個循環中將請求拆分個多個條帶,分別下發命令。
在第一次看這段代碼的時候。因為太匆忙全然沒有找到重點在哪里。就像一個人在喧囂的城市里長大,因為被城市的外表所迷惑全然不知道內心真正想追求的生活。當真正靜下心來看的時候。最終發現最重要的一句在4187行,即add_stripe_bio函數,從此開始stripe不再孤單,因為有了bio的附體。它已經準備好要增加了條帶處理流程,一場轟轟烈烈的條帶人生路由此展開。 在4198行和4203行release_stripe_plug之后一個新的條帶正式增加了處理隊列(conf->handle_list)。 人的上半生在不斷地找入口。下半生在不斷地找出口。在這里,讀stripe找到了入口,那么出口在哪里呢?讀過LDD的同學一定知道答案,對于不使用默認請求隊列的塊設備驅動來說。相應的make_request函數為入口。出口就是bio_endio。接下來我們就一步步邁向這個出口。 release_stripe_plug之后首先進入的是handle_stripe,handle_stripe調用analyse_stripe,在這個函數中設置了to_read: 3245 if (test_bit(R5_Wantfill, &dev->flags)) 3246 s->to_fill++; 3247 else if (dev->toread) 3248 s->to_read++;
回到handle_stripe函數中: 3472 if (s.to_read || s.non_overwrite 3473 || (conf->level == 6 && s.to_write && s.failed) 3474 || (s.syncing && (s.uptodate + s.compute < disks)) 3475 || s.replacing 3476 || s.expanding) 3477 handle_stripe_fill(sh, &s, disks);
to_read觸發了handle_stripe_fill,這個函數的作用就是設置須要讀取的標志: 2696 set_bit(R5_LOCKED, &dev->flags); 2697 set_bit(R5_Wantread, &dev->flags); 2698 s->locked++;
接著又來到了ops_run_io,將讀請求下發到磁盤。讀請求的回調函數為raid5_end_read_request: 1745 if (uptodate) { 1746 set_bit(R5_UPTODATE, &sh->dev[i].flags); ... 1824 rdev_dec_pending(rdev, conf->mddev); 1825 clear_bit(R5_LOCKED, &sh->dev[i].flags); 1826 set_bit(STRIPE_HANDLE, &sh->state); 1827 release_stripe(sh);
這個函數做了兩件事情。一是設置了R5_UPTODATE標志,還有一是調用了release_stripe又一次將條帶送回了handle_stripe處理。 帶著R5_UPTODATE標志進入了analyse_stripe函數: 3231 if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread && 3232 !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) 3233 set_bit(R5_Wantfill, &dev->flags); 3234 3235 /* now count some things */ 3236 if (test_bit(R5_LOCKED, &dev->flags)) 3237 s->locked++; 3238 if (test_bit(R5_UPTODATE, &dev->flags)) 3239 s->uptodate++; 3240 if (test_bit(R5_Wantcompute, &dev->flags)) { 3241 s->compute++; 3242 BUG_ON(s->compute > 2); 3243 } 3244 3245 if (test_bit(R5_Wantfill, &dev->flags)) 3246 s->to_fill++;
在3255行設置了R5_Wantfill標志。在3246行設置了to_fill,再次回來handle_stripe: 3426 if (s.to_fill && !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) { 3427 set_bit(STRIPE_OP_BIOFILL, &s.ops_request); 3428 set_bit(STRIPE_BIOFILL_RUN, &sh->state); 3429 }
條帶狀態設置了STRIPE_OP_BIOFILL,僅僅要設置了s.ops_request。就必須立即知道這個域相應的處理函數為raid_run_ops,實際操作在__raid_run_ops: 1378 if (test_bit(STRIPE_OP_BIOFILL, &ops_request)) { 1379 ops_run_biofill(sh); 1380 overlap_clear++; 1381 }
相應的處理函數是ops_run_biofill: 812static void ops_run_biofill(struct stripe_head *sh) 813{ 814 struct dma_async_tx_descriptor *tx = NULL; 815 struct async_submit_ctl submit; 816 int i; 817 818 pr_debug("%s: stripe %llu\n", __func__, 819 (unsigned long long)sh->sector); 820 821 for (i = sh->disks; i--; ) { 822 struct r5dev *dev = &sh->dev[i]; 823 if (test_bit(R5_Wantfill, &dev->flags)) { 824 struct bio *rbi; 825 spin_lock_irq(&sh->stripe_lock); 826 dev->read = rbi = dev->toread; 827 dev->toread = NULL; 828 spin_unlock_irq(&sh->stripe_lock); 829 while (rbi && rbi->bi_sector < 830 dev->sector + STRIPE_SECTORS) { 831 tx = async_copy_data(0, rbi, dev->page, 832 dev->sector, tx); 833 rbi = r5_next_bio(rbi, dev->sector); 834 } 835 } 836 } 837 838 atomic_inc(&sh->count); 839 init_async_submit(&submit, ASYNC_TX_ACK, tx, ops_complete_biofill, sh, NULL); 840 async_trigger_callback(&submit); 841}
最終見到廬山真面目了,不禁感慨一下代碼就是這樣裹著一層又一層,就好像神奇的生日禮物一樣要拆開一層又一層的包裝,又像老胡同巷子走過一道又一道才干找到那個賣酒的店子。但無論怎么樣,代碼都對你毫無保留的。真誠的。
假設你已經練就了一目十行的火眼睛睛的話,你一定看到了806行的return_io,沒錯。這就是我之前提到的出口了: 177static void return_io(struct bio *return_bi) 178{ 179 struct bio *bi = return_bi; 180 while (bi) { 181 182 return_bi = bi->bi_next; 183 bi->bi_next = NULL; 184 bi->bi_size = 0; 185 bio_endio(bi, 0); 186 bi = return_bi; 187 } 188}
最終看到bio_endio了吧,happy吧去慶祝喝一杯吧。 狂歡夠了嗎?接下來有兩個思考題: 1)return_bi為什么不是一個bio。而有bi_next? 2)既然return_io結束了。808/809行為什么又要又一次增加到處理鏈表? 轉載請注明出處:http://blog.csdn.net/liumangxiong
假設是非條塊內讀。那么就至少涉及到兩個條塊的讀,這就須要分別從這兩個條塊內讀出數據。然后再湊成整個結果返回給上層。接下來我們將看到怎樣將一個完整的bio讀請求拆分成多個子請求下發到磁盤,從磁盤返回之后再又一次組合成請求結果返回給上層的。 4097 logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); 4098 last_sector = bi->bi_sector + (bi->bi_size>>9); 4099 bi->bi_next = NULL; 4100 bi->bi_phys_segments = 1; /* over-loaded to count active stripes */
首先計算請求起始位置,由于md下發到磁盤數據請求的最小單位為STRIPE_SECTORS,所以這里要將請求對齊。計算出請求起始位置為logical_sector?,結束位置為last_sector。4100行復用bi_phys_segments?用于計數下發條帶數,這里防止意外釋放先設置為1。
4102 for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { 4103 DEFINE_WAIT(w); 4104 int previous; 4105 4106 retry: 4107 previous = 0; 4108 prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); ... 4134 4135 new_sector = raid5_compute_sector(conf, logical_sector, 4136 previous, 4137 &dd_idx, NULL); 4138 pr_debug("raid456: make_request, sector %llu logical %llu\n", 4139 (unsigned long long)new_sector, 4140 (unsigned long long)logical_sector); 4141 4142 sh = get_active_stripe(conf, new_sector, previous, 4143 (bi->bi_rw&RWA_MASK), 0);
在這個循環中將請求拆分個多個條帶,分別下發命令。
在處理條帶的時候還須要做到相互排斥。不能有兩個線程在同一時候操作同一個條帶。
比方說同步線程在同步這個條帶,raid5d在寫這個條帶,那么就會產生非預期的結果。
4103行。等待隊列用于條帶訪問相互排斥 4108行,增加等待隊列 4135行。依據陣列邏輯扇區計算出磁盤物理偏移扇區,并計算相應的數據盤號和校驗盤號 4142行,依據磁盤物理偏移扇區獲取一個條帶 4144 if (sh) { .... 4186 if (test_bit(STRIPE_EXPANDING, &sh->state) || 4187 !add_stripe_bio(sh, bi, dd_idx, rw)) { 4188 /* Stripe is busy expanding or 4189 * add failed due to overlap. Flush everything 4190 * and wait a while 4191 */ 4192 md_wakeup_thread(mddev->thread); 4193 release_stripe(sh); 4194 schedule(); 4195 goto retry; 4196 } 4197 finish_wait(&conf->wait_for_overlap, &w); 4198 set_bit(STRIPE_HANDLE, &sh->state); 4199 clear_bit(STRIPE_DELAYED, &sh->state); 4200 if ((bi->bi_rw & REQ_SYNC) && 4201 !test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) 4202 atomic_inc(&conf->preread_active_stripes); 4203 release_stripe_plug(mddev, sh); 4204 } else { 4205 /* cannot get stripe for read-ahead, just give-up */ 4206 clear_bit(BIO_UPTODATE, &bi->bi_flags); 4207 finish_wait(&conf->wait_for_overlap, &w); 4208 break; 4209 } 4210 }在第一次看這段代碼的時候。因為太匆忙全然沒有找到重點在哪里。就像一個人在喧囂的城市里長大,因為被城市的外表所迷惑全然不知道內心真正想追求的生活。當真正靜下心來看的時候。最終發現最重要的一句在4187行,即add_stripe_bio函數,從此開始stripe不再孤單,因為有了bio的附體。它已經準備好要增加了條帶處理流程,一場轟轟烈烈的條帶人生路由此展開。 在4198行和4203行release_stripe_plug之后一個新的條帶正式增加了處理隊列(conf->handle_list)。 人的上半生在不斷地找入口。下半生在不斷地找出口。在這里,讀stripe找到了入口,那么出口在哪里呢?讀過LDD的同學一定知道答案,對于不使用默認請求隊列的塊設備驅動來說。相應的make_request函數為入口。出口就是bio_endio。接下來我們就一步步邁向這個出口。 release_stripe_plug之后首先進入的是handle_stripe,handle_stripe調用analyse_stripe,在這個函數中設置了to_read: 3245 if (test_bit(R5_Wantfill, &dev->flags)) 3246 s->to_fill++; 3247 else if (dev->toread) 3248 s->to_read++;
回到handle_stripe函數中: 3472 if (s.to_read || s.non_overwrite 3473 || (conf->level == 6 && s.to_write && s.failed) 3474 || (s.syncing && (s.uptodate + s.compute < disks)) 3475 || s.replacing 3476 || s.expanding) 3477 handle_stripe_fill(sh, &s, disks);
to_read觸發了handle_stripe_fill,這個函數的作用就是設置須要讀取的標志: 2696 set_bit(R5_LOCKED, &dev->flags); 2697 set_bit(R5_Wantread, &dev->flags); 2698 s->locked++;
接著又來到了ops_run_io,將讀請求下發到磁盤。讀請求的回調函數為raid5_end_read_request: 1745 if (uptodate) { 1746 set_bit(R5_UPTODATE, &sh->dev[i].flags); ... 1824 rdev_dec_pending(rdev, conf->mddev); 1825 clear_bit(R5_LOCKED, &sh->dev[i].flags); 1826 set_bit(STRIPE_HANDLE, &sh->state); 1827 release_stripe(sh);
這個函數做了兩件事情。一是設置了R5_UPTODATE標志,還有一是調用了release_stripe又一次將條帶送回了handle_stripe處理。 帶著R5_UPTODATE標志進入了analyse_stripe函數: 3231 if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread && 3232 !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) 3233 set_bit(R5_Wantfill, &dev->flags); 3234 3235 /* now count some things */ 3236 if (test_bit(R5_LOCKED, &dev->flags)) 3237 s->locked++; 3238 if (test_bit(R5_UPTODATE, &dev->flags)) 3239 s->uptodate++; 3240 if (test_bit(R5_Wantcompute, &dev->flags)) { 3241 s->compute++; 3242 BUG_ON(s->compute > 2); 3243 } 3244 3245 if (test_bit(R5_Wantfill, &dev->flags)) 3246 s->to_fill++;
在3255行設置了R5_Wantfill標志。在3246行設置了to_fill,再次回來handle_stripe: 3426 if (s.to_fill && !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) { 3427 set_bit(STRIPE_OP_BIOFILL, &s.ops_request); 3428 set_bit(STRIPE_BIOFILL_RUN, &sh->state); 3429 }
條帶狀態設置了STRIPE_OP_BIOFILL,僅僅要設置了s.ops_request。就必須立即知道這個域相應的處理函數為raid_run_ops,實際操作在__raid_run_ops: 1378 if (test_bit(STRIPE_OP_BIOFILL, &ops_request)) { 1379 ops_run_biofill(sh); 1380 overlap_clear++; 1381 }
相應的處理函數是ops_run_biofill: 812static void ops_run_biofill(struct stripe_head *sh) 813{ 814 struct dma_async_tx_descriptor *tx = NULL; 815 struct async_submit_ctl submit; 816 int i; 817 818 pr_debug("%s: stripe %llu\n", __func__, 819 (unsigned long long)sh->sector); 820 821 for (i = sh->disks; i--; ) { 822 struct r5dev *dev = &sh->dev[i]; 823 if (test_bit(R5_Wantfill, &dev->flags)) { 824 struct bio *rbi; 825 spin_lock_irq(&sh->stripe_lock); 826 dev->read = rbi = dev->toread; 827 dev->toread = NULL; 828 spin_unlock_irq(&sh->stripe_lock); 829 while (rbi && rbi->bi_sector < 830 dev->sector + STRIPE_SECTORS) { 831 tx = async_copy_data(0, rbi, dev->page, 832 dev->sector, tx); 833 rbi = r5_next_bio(rbi, dev->sector); 834 } 835 } 836 } 837 838 atomic_inc(&sh->count); 839 init_async_submit(&submit, ASYNC_TX_ACK, tx, ops_complete_biofill, sh, NULL); 840 async_trigger_callback(&submit); 841}
最終見到廬山真面目了,不禁感慨一下代碼就是這樣裹著一層又一層,就好像神奇的生日禮物一樣要拆開一層又一層的包裝,又像老胡同巷子走過一道又一道才干找到那個賣酒的店子。但無論怎么樣,代碼都對你毫無保留的。真誠的。
并且越是復雜的代碼就越是風情萬種、婀娜多姿,前提是你要懂得怎樣走入她的內心里才干體會得到。等真正體會到的時候你就會拍案叫絕,從而獲得征服的快感久久不能忘懷。在征服了這樣一個又一個風情萬種的代碼之后。你的追求就不再局限于肉體之上,轉而追求精神上的高度,像歐洲建筑師一樣去設計大教堂,然后花個600多年把哥特式的科隆大教堂建好,這才叫藝術。
好吧,那個時候你我都已經不在了,但那種精神始終是你我要追求的境地。
823行,我們剛剛完畢了對磁盤的讀取,這下將讀取的數據從緩存區中復制到dev->page上,而此時dev->toread也轉移到了dev->read。這里先構造了dma的描寫敘述符,839和840將請求提交給DMA,在請求完畢之后會回調到839傳入的參數ops_complete_biofill: 769static void ops_complete_biofill(void *stripe_head_ref) 770{ 771 struct stripe_head *sh = stripe_head_ref; 772 struct bio *return_bi = NULL; 773 int i; 774 775 pr_debug("%s: stripe %llu\n", __func__, 776 (unsigned long long)sh->sector); 777 778 /* clear completed biofills */ 779 for (i = sh->disks; i--; ) { 780 struct r5dev *dev = &sh->dev[i]; 781 782 /* acknowledge completion of a biofill operation */ 783 /* and check if we need to reply to a read request, 784 * new R5_Wantfill requests are held off until 785 * !STRIPE_BIOFILL_RUN 786 */ 787 if (test_and_clear_bit(R5_Wantfill, &dev->flags)) { 788 struct bio *rbi, *rbi2; 789 790 BUG_ON(!dev->read); 791 rbi = dev->read; 792 dev->read = NULL; 793 while (rbi && rbi->bi_sector < 794 dev->sector + STRIPE_SECTORS) { 795 rbi2 = r5_next_bio(rbi, dev->sector); 796 if (!raid5_dec_bi_active_stripes(rbi)) { 797 rbi->bi_next = return_bi; 798 return_bi = rbi; 799 } 800 rbi = rbi2; 801 } 802 } 803 } 804 clear_bit(STRIPE_BIOFILL_RUN, &sh->state); 805 806 return_io(return_bi); 807 808 set_bit(STRIPE_HANDLE, &sh->state); 809 release_stripe(sh); 810}假設你已經練就了一目十行的火眼睛睛的話,你一定看到了806行的return_io,沒錯。這就是我之前提到的出口了: 177static void return_io(struct bio *return_bi) 178{ 179 struct bio *bi = return_bi; 180 while (bi) { 181 182 return_bi = bi->bi_next; 183 bi->bi_next = NULL; 184 bi->bi_size = 0; 185 bio_endio(bi, 0); 186 bi = return_bi; 187 } 188}
最終看到bio_endio了吧,happy吧去慶祝喝一杯吧。 狂歡夠了嗎?接下來有兩個思考題: 1)return_bi為什么不是一個bio。而有bi_next? 2)既然return_io結束了。808/809行為什么又要又一次增加到處理鏈表? 轉載請注明出處:http://blog.csdn.net/liumangxiong
版權聲明:本文博客原創文章。博客,未經同意,不得轉載。
轉載于:https://www.cnblogs.com/mengfanrong/p/4713262.html
總結
以上是生活随笔為你收集整理的linux内核的冒险md来源释义# 14raid5非条块读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开发文档收集
- 下一篇: Ant—使用Ant构建一个简单的Java