我們都知道,對一個linux塊裝置來說,都有一個對應的請求隊列。註冊在這個請求隊列上的請求就是該塊裝置的請求入口。對於raid來說,分配struct mddev時就已經設定好了,在函數md_alloc中有這樣的代碼:
4846 blk_queue_make_request(mddev->queue, md_make_request); 4847 blk_set_stacking_limits(&mddev->queue->limits);
雖然全國的PM一直保持著穩健的增長,但絲毫也阻擋不了我們看代碼的慧眼,在成千上萬行的代碼裡我們依然能夠迅速地找出raid讀寫入口就是md_make_request。
328/* Rather than calling directly into the personality make_request function, 329 * IO requests come here first so that we can check if the device is 330 * being suspended pending a reconfiguration. 331 * We hold a refcount over the call to ->make_request. By the time that 332 * call has finished, the bio has been linked into some internal structure 333 * and so is visible to ->quiesce(), so we don't need the refcount any more. 334 */
我們在調用make_request函數之前,先檢查裝置是否因為重配置而掛起。在調用make_request函數之前,我們增加裝置的引用計數,在make_request調用完成時再遞減。增加裝置引用計數主要是為調用->quiesce()之前保證下發到裝置的IO已經完成。
335static void md_make_request(struct request_queue *q, struct bio *bio) 336{ 337 const int rw = bio_data_dir(bio); 338 struct mddev *mddev = q->queuedata; 339 int cpu; 340 unsigned int sectors; 341 342 if (mddev == NULL || mddev->pers == NULL 343 || !mddev->ready) { 344 bio_io_error(bio); 345 return; 346 } 347 smp_rmb(); /* Ensure implications of 'active' are visible */348 rcu_read_lock(); 349 if (mddev->suspended) { 350 DEFINE_WAIT(__wait); 351 for (;;) { 352 prepare_to_wait(&mddev->sb_wait, &__wait, 353 TASK_UNINTERRUPTIBLE); 354 if (!mddev->suspended) 355 break; 356 rcu_read_unlock(); 357 schedule(); 358 rcu_read_lock(); 359 } 360 finish_wait(&mddev->sb_wait, &__wait); 361 } 362 atomic_inc(&mddev->active_io); 363 rcu_read_unlock(); 364 365 /* 366 * save the sectors now since our bio can 367 * go away inside make_request 368 */369 sectors = bio_sectors(bio); 370 mddev->pers->make_request(mddev, bio); 371 372 cpu = part_stat_lock(); 373 part_stat_inc(cpu, &mddev->gendisk->part0, ios[rw]); 374 part_stat_add(cpu, &mddev->gendisk->part0, sectors[rw], sectors); 375 part_stat_unlock(); 376 377 if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended) 378 wake_up(&mddev->sb_wait); 379}
337行,擷取IO方向,用於裝置資訊統計
338行,擷取陣列指標,該指標是在md_alloc中賦值的
342行,基本檢查
348行,訪問struct mddev資訊加rcu讀鎖
349行,陣列suspend
350行,如果陣列suspend,即前面注釋中講的正在重配置,則加入sb_wait等待隊列
360行,陣列完成suspend,從等待隊列中移除
362行,遞增陣列引用計數,在前面注釋裡有原因說明
370行,下發bio到陣列
372行,這個開始是資訊統計
377行,遞減陣列引用計數,如果正在重配置,則喚醒該進程
真正的資料通道命令也就370行這一句,其他的都是控制通道的。
對於raid5陣列,這個請求函數對應的是raid5.c中的make_request函數: