Friday, April 01, 2011

load storage adapter driver 遇到的問題

今天成功的將 CentOS 5.5 機器的 kernel更新成了 Fedora Core 14 x86 64 bits 的 kernel,

因為CentOS 5.5 的 kernel實在太老舊了,

不過在開機過程 load SAS adapter driver, 發現 driver load 完, init 仍然繼續往前執行,

如果這時有設定 LVM/MD之類的東西就會發生錯誤,

後來拜Google大神找到一個類似的問題
rc.sysinit does not wait for udev loaded scsi adapters to finish scanning their busses

應該跟 rc.sysinit 有關係, 因為筆者使用 Fedora Core 14時並沒有這個現象,
索性就直接去比較 CentOS 5.5 和 Fedora Core 14 rc.sysinit 的差別
結果發現了, Fedora Core 14 裡面有一段

# Sync waiting for storage.
{ rmmod scsi_wait_scan ; modprobe scsi_wait_scan ; rmmod scsi_wait_scan ; } >/dev/null 2>&1

加到 CentOS 5.5 rc.sysinit 後, 一切 OK, 果然如 module name scsi_wait_scan 一樣
至於為什麼要先 rmmod -> modprobe -> rmmod 就再研究了

SCSI adapter driver initial 完會call scsi_scan_host 來 scan device
為了 async scan device 會 create 一個名為 "scsi_scan_x" 的 kernel thread 來執行 do_scan_async
詳細看 void scsi_scan_host(struct Scsi_Host *shost) source code

do_scan_async() 呼叫 do_scsi_scan_host() 開始啟動 scan,
呼叫 scsi_finish_async_scan() 來通知系統 scan 完成

從source code 可以得知如果是 async scan的話, scan到一個lun的時候並不會馬上註冊device name
device name的註冊是在scsi_finish_async_scan()裡面完成的

基本上這次遇到的問題是 async scan 造成的...

scsi_wait_scan module source code 很短, 主要應該是 scsi_complete_async_scans(void)
基本上作法就是 create 一個假的 "async_scan_data" insert 到
scanning_hosts list 的尾巴, 然後就等 wait_for_completion(&data->prev_finished);

int scsi_complete_async_scans(void)
{
struct async_scan_data *data;
...
...
data = kmalloc(sizeof(*data), GFP_KERNEL);
...
init_completion(&data->prev_finished);
...
...
list_add_tail(&data->list, &scanning_hosts);
...
printk(KERN_INFO "scsi: waiting for bus probes to complete ...\n");
wait_for_completion(&data->prev_finished);
...
return 0;
}


如果沒理解錯誤的話, 應該是會在
void scsi_finish_async_scan(struct async_scan_data *data) 中
被 complete(&next->prev_finished);

也因此 scsi_wait_scan module return 時只保證在它之前就啟動的scan

已經結束, 若是在它之後才啟動的scan 則有可能已經結束或未結束

No comments: