SMP 行為和互動
內建方法和管理基礎結構 API
記憶體管理提供者 (SMP) 開發人員會使用:
- Convert-MofToProvider.exe所產生的內建方法。
- 來自 mi.h 檔案的管理基礎結構 (MI) API,以提供其 SMP 的實作。
下列項目符號會記下一些重要的內建和MI方法。
EnumerateInstances 和 GetInstance
當特定類別的實例有查詢時,會呼叫 EnumerateInstances。 例如:PowerShell Cmdlet Get-Object<> 會對應至對應的 WMI 物件的 EnumerateInstances 方法。 這個方法應該會透過 <Object>_Post 方法傳回 類別的所有實例。 由於 WMI 經常呼叫 EnumerateInstances,因此應該會快速執行。 若要這樣做,請使用良好的快取管理。
需要特定類別實例時,會呼叫 GetInstance,例如(但不限於):
- 當 WMI 基礎結構叫用此類別的任何方法時
- 當 WMI 型應用程式直接呼叫此方法時
- 透過 Association 類別要求 類別的實例時
GetInstance 方法應該只傳回透過 <Object>_Post 方法指定的物件。 所查詢之實例的標識碼,也就是MOF中所定義的「金鑰」,通常是 ObjectId,是透過 InstanceName 參數擷取。 WMI 經常呼叫這個方法,而且應該會快速完成。
EnumerateInstances 和 GetInstance 是一般類別的必要專案,例如 StorageProvider、StorageSubsystem、PhysicalDisk 等等。
對於 Association 類別,EnumerateInstances、AssociatorInstances 和 ReferenceInstances 是必要專案,而 GetInstance 則不是。
<物件>_Post 和 MI_PostResult
若要瞭解 MI API 方法 <物件>之間的差異_Post和MI_PostResult:
- <請將 Object>_Post視為傳回輸出參數的指標。
- 請將MI_PostResult視為函式傳回值,指出函式的執行狀態。
每個 WMI 方法「內容」只能呼叫MI_PostResult一次,這可以在每個 WMI 方法的輸入參數中找到。 “Context” 是 WMI 回呼的指標。 呼叫 MI_PostResult將會終結此指標。 因此,不應該在另一個 WMI 方法的主體中呼叫 WMI 方法。
<另一方面,物件>_Post每個 WMI 方法內容可以多次呼叫。 這個方法通常用於 EnumerateInstances,以傳回多個物件。
設定<屬性> 和 ModifyInstance
Windows 記憶體管理 API 不支持內部方法 ModifyInstance。 若要修改對象的屬性,則會使用 extrinsic 方法 Set<Property> 。
如需內部方法和 MI API 的詳細資訊,請參閱 Windows SDK 中的 MI API 範例。
對象識別
SMP 介面會使用下列兩組屬性來識別物件:
針對腳本和程序設計: ObjectId 和 UniqueId
ObjectId 是建立和維護的不透明標識符,以使用SMP及其用戶端來追蹤對象的實例。 這是全域唯一的必要屬性。 也就是說,兩個物件都不應該有相同的 ObjectId,即使它們是由個別的 SMP 管理,或位於不同的儲存子系統上也一樣。
如果對像是透過兩個不同的路徑可見的(例如:有兩個不同的SMP指向相同的儲存子系統),則相同的物件可以與兩個不同的 ObjectId 一起出現。 若要判斷兩個物件實例是否相同物件,請使用 UniqueId 屬性。
UniqueId 是強制屬性,用來唯一識別全域範圍內類別的實例。 此值應該在不同的管理伺服器上執行的兩個 SMP 實例之間相同。 不同於 ObjectId,UniqueId 應該是儲存子系統保存的值,而不是記憶體管理提供者進程。
UniqueId 可以是任何不透明的值,除非另有註明(例如:MSFT_VirtualDisk)。
針對顯示: FriendlyName 和 Name
終端使用者會使用這兩個屬性來識別物件。 如果 SMP 支援這類作業,FriendlyName 是使用者易記的字串,可由終端用戶設定。 FriendlyName 不一定是唯一的。 單一儲存子系統中的兩個物件可以共用相同的FriendlyName,但不建議這種做法。
SMP 會設定 Name 屬性,用戶無法修改它。 SMP 會提供此屬性中的其他資訊,以協助使用者識別物件。 這類資訊可能涵蓋對象的技術層面。 例如,記憶體子系統的名稱可以是子系統的IP或WN。 名稱通常在特定範圍中是唯一的。 例如,存放集區的名稱在擁有的儲存子系統中必須是唯一的。
錯誤處理
SMP 介面中有三種類型的錯誤: Windows 記憶體管理 API (SM API ) 傳回碼、「軟錯誤」和「硬式錯誤」。
SM API 傳回碼是指每個 SMP 外部方法所列出的錯誤碼作為傳回值。 例如,「5」 代表「無效的參數」。 這些錯誤碼會透過Convert-MofToProvider.exe所產生之方法結構中所定義的MIReturn輸出參數傳回。 MIReturn 的值可以透過 <Object> _<Method> 設定_Set_MIReturn在對應物件的頭文件中定義。
可能的話,Extrinsic 方法應該一律預設為使用 SM API 錯誤碼。 需要其他資訊時,SMP 可以使用 MSFT_ExtendedStatus 類別來提供外部方法調用的額外狀態資訊。 這個方法最好是使用外部方法的軟式錯誤。
軟式錯誤是指透過 MSFT_SoftError 類別傳回的錯誤訊息。 這些錯誤是針對內部方法(EnumerateInstances、GetInstance 等)所設計,無法傳回 SM API 錯誤碼。 若要傳回軟式錯誤,衍生自 MSFT_SoftError 之軟式錯誤類別的實例,應該透過mi.h中定義的MI_WriteCimError方法中的 「MI_Instance error」 參數來建構和傳回。 例如,若要在記憶體陣列登入期間指出「需要正確的認證」,您可以在 StorageSubsystem 物件的 EnumerateInstances 呼叫期間傳回 “MSFT_SoftError_NotAuthenticated”。 針對軟錯誤,仍應透過MI_PostResult張貼MI_RESULT_OK的結果。
硬式錯誤是指mi.h 檔案中MI_Result結構中定義的錯誤。 MI API 會傳回這些錯誤。 除非絕對必要,否則 SMP 應該避免將這些錯誤直接呈現至記憶體管理應用程式。 例如,對於「無效的參數」,SMP 應該使用 MIReturn 來呈現 SM API 錯誤碼 「5」 – “Invalid Parameter”,而不是依賴記憶體管理應用程式來取用MI_RESULT_INVALID_PARAMETER。
原始集區
原始集區,也稱為「可用的存放區」,是在建立和刪除具體存放集區時繪製和傳回儲存容量的位置。 無法建立、刪除或修改原始集區。
SMP 必須至少提供一個原始集區。 將實體磁碟新增至具體存放集區時,實體磁碟仍應視為原始集區的一部分。
大小報告
儲存集區對象的各種大小欄位有兩個特殊案例:來自熱備援磁碟驅動器的容量,以及狀況不良磁碟驅動器的容量。
一旦磁碟驅動器被指定為熱備援磁碟驅動器,其容量應該包含在對應的原始集區的 AllocatedSize 中。 不過,磁碟驅動器的容量不應包含在任何混凝土集區的大小中,即使儲存數位支援將熱備援磁碟驅動器用於特定混凝土集區也一樣。 在熱備援磁碟驅動器專用於特定混凝土集區之後,磁碟驅動器的容量不應包含在混凝土集區的 AllocatedSize 中,直到實際取代已使用的磁碟驅動器為止。 新增至混凝土集區時,CanPooled 對於這個熱備援磁碟驅動器的實體磁碟對象應該是 FALSE。 這個實體磁碟對象與具體集區的存放集區對象之間應該建立關聯。
來自健康狀態為「狀況不良」的磁碟驅動器容量不應包含在原始集區或混凝土集區的任何大小字段中。
關聯
SM API 包含定義記憶體對象之間關聯性的關聯類別。 透過這些關聯類別,可以輕鬆地周遊記憶體物件階層,以取得指定對象的相關物件。 針對記憶體 PowerShell 模組,Cmdlet 管線是透過關聯類別來達成。 例如,假設有虛擬磁碟物件,用戶可以透過下列 Cmdlet 取得擁有虛擬磁碟物件的存放集區:
PS> Get-VirtualDisk –FriendlyName MyVirtualDisk | Get-StoragePool
本節的其餘部分說明關聯類別的實作。 筆記中的方法是由每個關聯類別的Convert-MofToProvider.exe所產生。 附註使用 XToY 作為範例關聯類別;虛擬程式代碼使用 StoragePoolToVirtualDisk 作為範例。
- EnumerateInstances 和 GetInstance
- XToY\_EnumerateInstances returns association objects (XToY objects) for ALL X objects
<!-- end list -->
void MI_CALL SAMPLE_StoragePoolToVirtualDisk_EnumerateInstances( ... )
{
...
/** This method should return association objects for ALL Storage Pools. **/
// for each storage pool
// for each virtual disk that's associated with this storage pool
// create the StoragePoolToVirtualDisk association object
// set the storage pool object and virtual disk object to this association object
// post the association object
// end for
// end for
...
}
- AssociatorInstances
- AssociatorInstances method returns regular objects instead of association objects
- XToY\_AssociatorInstancesX should return all associated Y object(s) for the X specified
- XToY\_AssociatorInstancesY should return all associated X object(s) for the Y specified
<!-- end list -->
void MI_CALL SAMPLE_StoragePoolToVirtualDisk_AssociatorInstancesStoragePool(...)
{
...
/** This method should return VIRTUAL DISK object(s) for the
STORAGE POOL specified. **/
// for each virtual disk that's associated with this storage pool
// create the virtual disk object
// post the virtual disk object
// end for
...
}
void MI_CALL SAMPLE_StoragePoolToVirtualDisk_AssociatorInstancesVirtualDisk(...)
{
...
/** This method should return STORAGE POOL object(s) for the
VIRTUAL DISK specified. **/
// for each storage pool that's associated with this virtual disk
// create the storage pool object
// post the storage pool object
// end for
...
}
- ReferenceInstances
- ReferenceInstances is similar to AssociatorInstances except that these methods return association (XToY) objects instead of regular objects
- XToY\_ReferenceInstancesX should return XToY object(s) for X specified
- XToY\_ReferenceInstancesY should return YToX object(s) for Y specified
<!-- end list -->
void MI_CALL SAMPLE_StoragePoolToVirtualDisk_ReferenceInstancesStoragePool(...)
{
...
/** This method should return StoragePoolToVirtualDisk
ASSOCIATION object(s) for the STORAGE POOL specified. **/
// for each virtual disk that's associated with this storage pool
// create the StoragePoolToVirtualDisk association object
// set the storage pool and virtual disk to this association object
// post the association object
// end for
...
}
void MI_CALL SAMPLE_StoragePoolToVirtualDisk_ReferenceInstancesVirtualDisk(...)
{
...
/** This method should return StoragePoolToVirtualDisk
ASSOCIATION object(s) for the VIRTUAL DISK specified. **/
// for each storage pool that's associated with this virtual disk
// create the StoragePoolToVirtualDisk association object
// set the storage pool and virtual disk to this association object
// post the association object
// end for
...
}
快取管理
載入 SMP 時,它應該初始化記憶體物件的快取。 此初始化可確保服務 API 呼叫時的快速回應時間,因為物件可以直接從 SMP 的快取擷取。 此快取應該與頻內物件變更和頻外物件變更保持同步。
頻內物件變更包含透過目前 SMP 實例所做的變更。 例如,如果虛擬磁碟是透過目前的 SMP 實例建立:
- 新的虛擬磁碟物件應該新增至快取。
- 也應該更新相關聯的物件,例如擁有存放集區和相關聯的目標埠物件。
頻外變更包括透過廠商專屬工具和裝載於其他電腦上之SMP進行的變更。 例如,如果虛擬磁碟是透過廠商專屬工具建立的,則事件應該從記憶體子系統傳送至 SMP(s)以觸發快取更新。
呼叫 Storage Provider 類別的 Discover 方法時,SMP 也應該更新快取。 儲存體管理應用程式會呼叫此方法,以重設並重建事件上的快取,例如服務重新啟動或系統重新啟動。
如果 SMP 無法在啟動時初始化整個快取(因為物件太多,或因為無法快速完成),則應該只將記憶體提供者和記憶體子系統物件載入快取中。 應用程式會查看 Storage Subsystem 物件上的 CurrentCacheLevel 屬性,以瞭解快取已填入深度。 終端使用者或應用程式會透過 Discover 方法明確載入其餘的快取。
非同步作業
任何需要超過 30 秒才能完成的作業都必須傳回 Storage Job 物件。 包含 CreatedStorageJob 輸出參數的方法很可能屬於這種類型的作業。 SMP 應該實作所有這些方法做為異步操作,並傳回它們的 Storage Job 物件。 記憶體作業對象必須在 30 秒內傳回給呼叫端;否則,如果呼叫端等候的時間太長,而且仍然未收到 Storage Job 物件,則呼叫端可能會逾時。
應用程式(或 “WMI Client”) 可以選擇指定方法是否應為 “RunAsJob”。 應用程式使用的 SM API 包含這個額外的布爾 RunAsJob 參數和 CreatedStorageJob 輸出參數。 同時,SMP 介面中的對應方法只有 CreatedStorageJob 參數。 不過,不論 「RunAsJob」 的值為何,SMP 應該一律傳回這些方法的 Storage Job 物件。
下列案例說明異步操作的呼叫順序。 CreateVirtualDisk 會作為範例使用:
如果 「RunAsJob」 設定為 TRUE
叫用 CreateVirtualDisk 時,SMP 應該對 方法進行初始化、在記憶體子系統中啟動作業,並在 30 秒內將 Storage Job 物件傳回給呼叫端。 不過,儲存子系統可能需要任何時間才能完成作業。 呼叫端將在這段期間輪詢作業的狀態。
背景工作線程應該用來執行作業。 基於效率目的,SMP 只有在呼叫端輪詢該作業的狀態時,才能更新作業狀態相關屬性(例如 PercentComplete)。
如果 「RunAsJob」 設定為 FALSE
呼叫端會在 CreateVirtualDisk 方法上封鎖,直到方法傳回為止。 SM API 會自動執行封鎖和輪詢本身。 這種類型的呼叫者通常是偏好封鎖機制的非使用者互動式用戶端(例如腳本工具)。
由於取得新建立對象資訊的唯一方法是透過這個對象與對應的 Storage Job 對象之間的關聯,所以 SMP 應該保留記憶體作業物件至少 24 小時,再從快取中移除它。 若為未傳回新建立之物件的其他作業(例如DeleteObject作業),則不需要關聯,且 Storage Job 物件只需要保持運作 15 分鐘。
針對管理控制臺上的非預期系統重新啟動,SMP 應該在實體位置維護 StorageJob 物件的快取,例如在記憶體陣列中,並在系統重新啟動時重載快取。
提供者生命週期控制
SMP 可以實作為結合或分離提供者。 如需這兩種提供者類型之間的差異,請參閱 WMI MSDN 檔。
分離的提供者會載入並裝載於廠商的特定程式中。 此程式通常是一律執行的服務。
啟動提供者相當耗時,因為它牽涉到重載快取。 如果您的 SMP 啟動需要超過一秒以上的負載,建議您實作分離提供者,以透過永續性快取管理記憶體物件。 此方法可協助提升使用 Windows SM API 來管理 SMP 之應用程式的整體效能和回應性。
Windows SDK 的 DecoupledHost 範例提供有關分離提供者的更多詳細數據。
跡象
應用程式開發人員通常會想要知道物件的狀態在變更時何時變更。 他們可以訂閱 WMI 指示來執行此動作。 指示是不同類型的類別;它們會以異步方式公開,有時超出任何管理作業的頻外,而且不會保存。 有一些必須支援的新方法,而不是實作熟悉的內建方法(也就是 EnumerateInstances / GetInstance)。
有四種類型的指示:
- 抵達 – 當裝置或物件實例新增至子系統時,會使用此指示。 例如:將新的實體磁碟新增至子系統,或建立虛擬磁碟。
- 離開 – 從子系統移除裝置或對象實例時,會使用此指示。 例如:從子系統移除實體磁碟,或刪除存放集區。
- Modify – 當現有物件上的重要屬性變更時,會使用此指示。 HealthStatus 和 OperationalStatus 變更至少必須觸發Modify指示。 強烈建議您指出與物件作業狀態相關的任何其他屬性變更。
- 警示 – 此指示可用來向應用程式發出潛在問題的警示。 目前,唯一定義的警示是在達到精簡布建閾值時通知。
若要實作指示,每個指示類別都必須實作兩個新的內建方法:
- EnableIndication – 已提出訂閱指示類別的要求。 指示Context 應該儲存下來,以便稍後的時間點張貼在指示中。
- DisableIndication – 指示類別不再有訂閱者。 應該進行清除,而且不應該再張貼此類別的指示。 指示Context 目前已終結。
部署
SMP 會安裝在選取的「管理伺服器」上。 這些伺服器可以叢集以提供備援。 其他伺服器會透過 iSCSI 或 Fiber 通道存取配置給他們的記憶體。 所有這些機器都可以由從 伺服器管理員 執行檔伺服器使用者介面的伺服器管理。
不過,歡迎使用記憶體廠商選擇最適合其需求的部署模型。
安全性模型
SMP 介面支援使用 Windows 安全性認證的單一登錄 (SSO) 模型。
在 SSO 模型中,使用者一次使用其 Windows 認證登入「管理計算機」,並自動取得他們具有訪問許可權之所有記憶體資產的存取權。 不需要有更多記憶體子系統登入的認證。
介面也可讓記憶體系統管理員管理個別記憶體資產的訪問控制。 對於每個記憶體資產,記憶體系統管理員可以透過 GetSecurityDescriptor 和 SetSecurityDescriptor 方法,將不同的訪問許可權授與任何 Windows 使用者。 因此,與 VDS 模型不同的 SMP 現在可以從任何類型的用戶帳戶接收要求。
若要實作 SSO 模型,SMP 必須向記憶體子系統驗證 Windows 用戶端。 記憶體子系統必須保存每個記憶體資產的安全性描述項資訊。 若要實作驗證,記憶體廠商有兩個選項:
- 在子系統中驗證 (建議)
- 在每個 SMP 實例中驗證。
這兩個選項都需要在 SMP 與儲存子系統之間建立信任關係,以便安全地傳遞安全性描述元和使用者身分識別資訊。
若要在儲存子系統上實作無縫驗證和授權,建議您在SMP與儲存子系統之間實作 Kerberos、NTLM 或 SPNego 之間的連結。 如果存儲設備子系統已備妥網頁伺服器,“NTLM over HTTP” 通訊協定 [MS-NLMP] 可能會更實用。 記憶體廠商可以選擇保留其專屬通訊協議來實作 SSO 模型。 不過,不建議使用此方法,因為它可能會導致比實作其中一個 Windows 支援的驗證通訊協定更正常或設定。
為了支援 Windows 安全策略,記憶體子系統必須取得使用者的「令牌資訊」,其中包括使用者的安全性識別碼 (SID) 和使用者所屬任何群組的 SID。 如果實作 Kerberos、NTLM 或 SPNego 通訊協定,記憶體子系統會取得使用者的令牌資訊,做為通訊協定的一部分。 如果在 SMP 和儲存子系統之間使用廠商的專屬通訊協定,則儲存子系統可以透過輕量型目錄存取通訊協定 (LDAP) 查詢 Active Directory 的令牌資訊,並查看使用者帳戶物件的 tokenGroupsGlobalAndUniversal 屬性或 Object-Sid 屬性。
使用使用者的令牌資訊,若要強制執行 Windows 安全策略,記憶體子系統必須實作 [MS-DTYP] 中所述的存取檢查演算法。
如果記憶體廠商選擇不支援此 SSO 模型,則我們建議 SMP 遵循 VDS 的安全性模型, 只允許從系統管理員帳戶起始的作業。 不過,這項檢查現在必須由SMP本身執行。