正是有了上一篇的讀寫基礎,我們才開始看raid5d的代碼。raid5d不是讀寫的入口,也不是讀寫處理的地方,只是簡簡單單的中轉站或者叫做交通樞紐。這個樞紐具有制高點的作用,就像美國在新加坡的基地,直接就控制了太平洋和印度洋的交通樞紐。
4626 /* 4627 * This is our raid5 kernel thread. 4628 * 4629 * We scan the hash table for stripes which can be handled now. 4630 * During the scan, completed stripes are saved for us by the interrupt 4631 * handler, so that they will not have to wait for our next wakeup. 4632 */4633 static void raid5d(struct mddev *mddev) 4634 { 4635 struct r5conf *conf = mddev->private; 4636 int handled; 4637 struct blk_plug plug; 4638 4639 pr_debug("+++ raid5d active\n"); 4640 4641 md_check_recovery(mddev); 4642 4643 blk_start_plug(&plug); 4644 handled = 0; 4645 spin_lock_irq(&conf->device_lock); 4646 while (1) { 4647 struct bio *bio; 4648 int batch_size; 4649 4650 if ( 4651 !list_empty(&conf->bitmap_list)) { 4652 /* Now is a good time to flush some bitmap updates */4653 conf->seq_flush++; 4654 spin_unlock_irq(&conf->device_lock); 4655 bitmap_unplug(mddev->bitmap); 4656 spin_lock_irq(&conf->device_lock); 4657 conf->seq_write = conf->seq_flush; 4658 activate_bit_delay(conf); 4659 }
4641行,md_check_recovery這個函數前面看過了,用來檢查觸發同步
4643行,blk_start_plug和4688行blk_finish_plug是一對,用於合并請求。
4646行,這裡為什麼要來個大迴圈呢?剛開始看4629行注釋可能有點迷糊,可是看到這個迴圈就知道原來講的是這裡,4629行注釋說我們不必等到下次喚醒raid5線程,可以繼續處理stripes,因為可能有stripes已經在中斷處理函數裡處理完成返回了。
4651行,判斷陣列對應的bitmap_list是否為空白,如果這個鏈表不為空白則進入分支。bitmap跟條帶處理有什麼關係呢?這個問題就比較有曆史性了。對於raid5陣列來說,最可怕的事情莫過於在寫的過程中異常掉電,這就意味陣列不知道哪些資料是一致的,哪些是不一致的?這就是safemode乾的事情,用來記錄陣列資料是否一致。然而資料不一致導致的代碼是全盤同步,這個是raid5最頭疼的問題。好了,現在有bitmap了可以解決這個問題啦,太happy啦。那bitmap是如何解決這個問題的呢?bitmap說你寫每個條帶的時候我都記錄一下,寫完成就清除一下。如果異常掉電就只要同步掉電時未寫完成的條帶就可以啦。娃哈哈太happy了!!!但是請別高興的太早,bitmap也不是一個好侍候的爺,bitmap必須要在寫條帶之前寫完成,這裡的寫完成就是要Write Through即同步寫。這下悲催了,bitmap的寫過程太慢了,完全拖垮了raid5的效能。於是有了這個的bitmap_list,raid5說,bitmap老弟你批量寫吧,有點類似bio的合并請求。但是這也只能部分彌補bitmap帶來的負面效能作用。
4655行,下發bitmap批量寫請求。
4657行,更新bitmap批量寫請求的序號。
4658行,將等待bitmap寫的條帶下發。
4660 raid5_activate_delayed(conf);
4660行,看函數名就是啟用延遲條帶的意思。那麼為什麼要延遲條帶的處理呢?按照塊裝置常用的手段,延遲處理是為了合并請求,這裡也是同樣的道理。那麼條帶什麼時候做延遲處理呢?我們跟進raid5_activate_delayed函數:
3691static void raid5_activate_delayed(struct r5conf *conf) 3692{ 3693 if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) { 3694 while (!list_empty(&conf->delayed_list)) { 3695 struct list_head *l = conf->delayed_list.next; 3696 struct stripe_head *sh; 3697 sh = list_entry(l, struct stripe_head, lru); 3698 list_del_init(l); 3699 clear_bit(STRIPE_DELAYED, &sh->state); 3700 if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) 3701 atomic_inc(&conf->preread_active_stripes); 3702 list_add_tail(&sh->lru, &conf->hold_list); 3703 } 3704 } 3705}
3693行,這裡控制預讀數量。
3694行,遍曆陣列延遲處理鏈表
3695行,擷取陣列延遲處理鏈表表頭
3697行,擷取陣列延遲處理鏈表第一個條帶
3698行,從陣列延遲處理鏈表取出一個條帶
3700行,設定預讀標誌
3702行,添加到預讀鏈表中