storage manager

上一篇寫了些關於SD Driver的東西,在卡被系統識別到之後最後會加載文件系統。這部分工作是由CE下的Storage Manager來完成的,在系統啓動時會加載Filesys.exe,這個會提供Storager Manager的功能。在Storage Manager的初始化階段會創建一個Pnp的線程來監測有無Pnp的設備插入或移出。當SD卡插入後,系統監測到之後會發送一個Msg出來,這個Msg包括設備的名稱和GUID。那麼Pnp的線程等到這個Msg後開始爲剛插入的Block設備加載文件系統。函數MountStore用來加載。

  在這裏CE設計了一個類CStore來表述這個塊設備,在創建一個實例的時候會執行構造函數來完成部分成員的初始化。Storage Manager作爲一個管理器的角色自然要對系統中各個存儲設備進行管理,StorageManager會構造一個鏈表,然後將前面創建的Store的指針插入這個鏈表。由於之前塊設備的Block Driver已經由Device.exe也就是設備管理器加載過了,因此已經存在設備文件,那麼存儲管理器就在OpenDisk函數內使用CreateFileW來獲取設備句柄,這個句柄也是CStore的一個成員變量。之後利用該句柄調用DeviceIoControl來獲取Block驅動的部分信息,這裏比較重要的是Profile對應的字串。有了這個就在接下來的GetStorageMessage(函數名忘記是不是這個了)中獲取註冊表中關於該塊設備的信息。包括Partition Driver和該設備需要加載的文件系統等。

  在獲取了Partition Driver之後(一般都是使用MS的mspart.dll)接着就涉及到Partition部分了,在這個部分會創建Partition的類,該類的成員中包括一系列的函數指針,接着調用LoadPartitionDriver函數,該函數是把mspart.dll中的函數地址賦給Partition類中的函數指針。有了這些函數的具體實現就可以加載分區驅動了。分區驅動的入口應該是PD_OpenStore函數,在這個函數中利用設備句柄和DeviceIoControl來讀取MBR,通過這部分信息來創建Partition的結構(這裏不是Partition的類),有幾個分區就有幾個對應的結構,並用鏈表相連,表頭賦給CStore的一個成員(沒有記錯的話應該是dwStoreId吧),而Partition類的指針也賦給CStoer的成員,好像叫做m_pPartitionList,有了這些之後再調用Partition驅動中LoadPartition的函數來加載分區,分區加載上之後就要加載該分區上的文件系統了,我們使用FAT文件系統。

  在分區加載之後加載文件系統,在這裏涉及到一個函數InitEx,在這個函數中來完成對於文件系統的加載。該函數中會去創建兩個結構:FSD和DSK。同時該函數的返回值m_pDsk是類Partition的成員。DSK結構中有指向FSD的指針,也有指向_DSK的指針,同時_DSK有指向Volume的結構。

  由以上可以看出,實際存儲管理維護了幾個類和結構:CStore,CPartition,FSD,DSK和Volume等。文件系統加載會調用一個RegisterVolume函數,在註冊成功後就可以看到在設備上顯示SD的卷標了。

  在這個部分涉及到一個斷點續傳的問題,比如在向SD卡寫入數據的過程中如果Suspend設備,之後再Wakeup。那麼之前的寫入操作會從剛纔的斷點開始。在這裏有一個Pnp設備Unmount的Delay時間,這個時間一般通過註冊表來設定。在設備WakeUp之後,實際會執行一次Unmount的動作,之後又會去執行一次Mount操作。在Unmount之後,系統把要Unmount的設備標記一下,之後等待這個Delay時間,Delay時間過了之後,存儲管理纔會把標記過的設備Unmount掉,如果在時間還沒有到的時候重新Mount,系統會重複之前介紹過的動作,但是在這裏會去比較這個新Mount進來的設備和之前CStore鏈表上的是否有一致的,這個比較是非常嚴格的,比如說設備的ID,修改的時間等等。這樣纔不會在中途換卡而系統仍認爲是前一張卡的錯誤出現。如果確認是同一張卡並且卡上內容沒有變動過,就把新的CStore中的部分信息賦給原來鏈表上的那個CStore,但是大部分內容不變,之後刪除新的這個CStore實例。在刪除過程中,需要把部分成員設爲NULL,這樣這些空間就不會在Delete Store的時候也被刪除,因爲這些還要在老的CStore上使用,由於大部分內容沒有變化,特別是CPartition中的m_pDsk沒有變,它所指向的Volume的內容也沒有變化,這樣才能夠做到斷點的續傳。

  最後還有在Unmount的時候系統會做些什麼操作呢。在Unmount的時候,由於要保證該Store上的操作都必須完成。判斷Vol的成員c_Thread的值是否爲0,如果爲0說明沒有線程在操作該Store,那麼就正常Unmount。如果不爲0說明還有線程沒有退出,這時創建一個線程去判斷是否操作都完成,同時將Vol設爲不可用,這樣之後對該Store的操作將不被允許。那麼這些未完成的線程操作會在退出時將c_Thread減1,如果該變量爲0,那麼就會SetEvent告訴剛纔創建的判斷線程,這樣Unmount纔會去執行接下來的Unmount操作


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/gooogleman/archive/2008/11/20/3339247.aspx

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章