ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

WSL C SDK 存储 API 深度解析:WslcCreateSessionVhdVolume 与 WslcDeleteSessionVhdVolume 的用法、校验逻辑与源码实现

2026/9/10 11:00:41 拓冰建站 浏览量
WSL C SDK 存储 API 深度解析:WslcCreateSessionVhdVolume 与 WslcDeleteSessionVhdVolume 的用法、校验逻辑与源码实现 WSL C SDK 存储 API 深度解析WslcCreateSessionVhdVolume 与 WslcDeleteSessionVhdVolume 的用法、校验逻辑与源码实现【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL本篇围绕 WSLWindows Subsystem for Linux仓库中的 C API Storage APIs 参考页 展开完整覆盖其中登记的两个成员函数WslcCreateSessionVhdVolume与WslcDeleteSessionVhdVolume的签名、参数、取值约束与调用示例并深入 wslcsdk.cpp 的校验与底层CreateVolume调用链、wslcsdk.h 中的WslcVhdRequirements结构定义以及 WslcSdkTests.cpp 中的端到端测试用例帮助读者掌握在 WSLCWindows Subsystem for Linux Containers会话中创建、挂载并删除命名 VHD 卷的完整实战方案。1. 存储 API 的定位会话级命名 VHD 卷管理Storage APIs是 C API 参考目录 下的一个子章节当前登记了两个成员函数WslcCreateSessionVhdVolume在已运行的 WSLC 会话中创建一个以 VHDX 为后端的命名卷WslcDeleteSessionVhdVolume按名称删除该会话中的命名卷。这两个函数管理的对象是会话内的命名卷named session volumes区别于会话自身的根文件系统 VHD后者由WslcSetSessionSettingsVhd在建会话前配置。命名卷创建后可通过容器配置中的WslcSetContainerSettingsNamedVolumes挂载进容器实现跨容器的持久化数据共享。2. WslcCreateSessionVhdVolume签名、参数与官方示例2.1 函数签名与参数表STDAPI WslcCreateSessionVhdVolume( _In_ WslcSession session, _In_ const WslcVhdRequirements* options, _Outptr_opt_result_z_ PWSTR* errorMessage);ParameterTypeDirectionsessionWslcSessioninoptionsconst WslcVhdRequirements*inerrorMessagePWSTR*out, optional返回值HRESULT成功时返回S_OK失败时返回对应的错误码如E_INVALIDARG、E_POINTER。2.2 WslcVhdRequirements 结构字段语义与生效条件入参结构体WslcVhdRequirements的完整定义见 wslcsdk.htypedef enum WslcVhdType { WSLC_VHD_TYPE_DYNAMIC 0, // Expanding VHDX (default) WSLC_VHD_TYPE_FIXED 1 // Fixed-allocation VHDX (only honored by WslcCreateSessionVhdVolume) } WslcVhdType; typedef enum WslcVhdRequirementsFlags { WSLC_VHD_REQ_FLAG_NONE 0x00000000, // When set, WslcVhdRequirements::uid and gid are honored. When clear, // those fields are ignored and the volume is left owned by root:root. WSLC_VHD_REQ_FLAG_OWNER 0x00000001, } WslcVhdRequirementsFlags; typedef struct WslcVhdRequirements { // Ignored by WslcSetSessionSettingsVhd _In_z_ PCSTR name; _In_ uint64_t sizeBytes; // Desired size (for create/expand) _In_ WslcVhdType type; // The remaining fields are only honored by WslcCreateSessionVhdVolume. // WslcSetSessionSettingsVhd rejects non-NONE flags with E_INVALIDARG. _In_ WslcVhdRequirementsFlags flags; _In_ uint32_t uid; // honored iff (flags WSLC_VHD_REQ_FLAG_OWNER) _In_ uint32_t gid; // honored iff (flags WSLC_VHD_REQ_FLAG_OWNER) } WslcVhdRequirements;各字段在WslcCreateSessionVhdVolume中的约束如下字段类型约束与语义namePCSTR卷名不能为NULL否则返回E_INVALIDARG对应后端文件会话存储目录/volumes/name.vhdxsizeBytesuint64_t期望容量字节必须大于 0否则返回E_INVALIDARGtypeWslcVhdType仅接受WSLC_VHD_TYPE_DYNAMIC0动态扩展 VHDX默认或WSLC_VHD_TYPE_FIXED1固定分配 VHDX其它取值返回E_INVALIDARG。WSLC_VHD_TYPE_FIXED是仅被本函数认可的取值flagsWslcVhdRequirementsFlags目前已知标志位仅有WSLC_VHD_REQ_FLAG_OWNER出现任何未知标志位会返回E_INVALIDARG防未来标志位被静默忽略uid/giduint32_t仅当flags WSLC_VHD_REQ_FLAG_OWNER时生效指定卷根 inode 的所有者未设置该标志时字段被忽略卷保持root:root属主2.3 官方示例可直接复现参考文档给出的最小示例WslcVhdRequirements options { 0 }; options.name cache; options.sizeBytes (uint64_t)8 * 1024 * 1024 * 1024; // 8 GiB options.type WSLC_VHD_TYPE_DYNAMIC; options.flags WSLC_VHD_REQ_FLAG_OWNER; options.uid (uint32_t)1000; options.gid (uint32_t)1000; HRESULT hr WslcCreateSessionVhdVolume(session, options, NULL);errorMessage为可选出参传入非空指针时失败路径会返回一条以CoTaskMemAlloc分配的、调用方需自行释放CoTaskMemFree的宽字符错误消息不需要消息时可传NULL测试代码中大量使用NULL。3. 源码级实现剖析从参数校验到底层 CreateVolume3.1 参数校验顺序与错误码实现位于 wslcsdk.cpp#L482-L533校验顺序非常明确可直接映射为一张错误码表auto internalType CheckAndGetInternalType(session); RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), internalType-session); RETURN_HR_IF_NULL(E_POINTER, options); RETURN_HR_IF_NULL(E_INVALIDARG, options-name); RETURN_HR_IF(E_INVALIDARG, options-sizeBytes 0); // Reject unknown flag bits so future additions cant be silently ignored. constexpr WslcVhdRequirementsFlags c_knownFlags WSLC_VHD_REQ_FLAG_OWNER; RETURN_HR_IF(E_INVALIDARG, (options-flags ~c_knownFlags) ! WSLC_VHD_REQ_FLAG_NONE);触发条件返回码会话句柄内部状态无效非活动会话HRESULT_FROM_WIN32(ERROR_INVALID_STATE)options NULLE_POINTERoptions-name NULLE_INVALIDARGoptions-sizeBytes 0E_INVALIDARGflags含未知标志位如0x80000000E_INVALIDARGtype既不是DYNAMIC也不是FIXED如强转值 42E_INVALIDARG上述每一个错误分支都在 WslcSdkTests.cpp#L2184-L2212 与 L2269-L2277 中有对应的负向用例逐一验证。3.2 驱动选项组装SizeBytes / Fixed / Uid / Gid校验通过后SDK 把WslcVhdRequirements翻译为一组WSLCCompatDriverOption键值对传给底层卷创建接口const auto sizeStr std::to_string(options-sizeBytes); std::vectorWSLCCompatDriverOption driverOpts; driverOpts.push_back({SizeBytes, sizeStr.c_str()}); if (options-type WSLC_VHD_TYPE_FIXED) { driverOpts.push_back({Fixed, true}); } if (WI_IsFlagSet(options-flags, WSLC_VHD_REQ_FLAG_OWNER)) { driverOpts.push_back({Uid, uidStr.c_str()}); driverOpts.push_back({Gid, gidStr.c_str()}); } WSLCCompatVolumeOptions volumeOptions{}; volumeOptions.Name options-name; volumeOptions.Driver vhd; volumeOptions.DriverOpts driverOpts.data(); ... return errorInfoWrapper.CaptureResult(internalType-session-CreateVolume(volumeOptions, volumeInfo));由此可以得到几个实现层面的事实卷的后端驱动固定为vhd即每个命名卷对应一个 VHDX 文件从测试代码断言的路径看文件落在会话存储目录/volumes/name.vhdx见 WslcSdkTests.cpp#L2128-L2129WSLC_VHD_TYPE_FIXED通过追加Fixedtrue驱动选项实现固定预分配单元测试进一步验证固定卷落盘后的文件尺寸不小于sizeBytesL2214-L2231而动态卷则按需扩展OWNER标志转换为Uid/Gid两个驱动选项。测试中的注释表明其作用时机uid/gid 在mkfs时写入卷的根 inode随后容器内执行stat -c %u %g /data得到65534 65534nobody:nogroup作为验证L2233-L2267源码中特意把uidStr/gidStr提升到函数作用域注释解释了原因驱动选项数组中保存的是c_str()指针必须保持到CreateVolume调用结束都有效L498-L502。3.3 与 WslcSetSessionSettingsVhd 的边界差异WslcVhdRequirements同时被WslcSetSessionSettingsVhd配置会话根文件系统 VHD复用但两者对字段的认可范围不同这一点从 wslcsdk.cpp#L548-L572 可见WslcSetSessionSettingsVhd忽略name根文件系统卷不需要名字只接受WSLC_VHD_TYPE_DYNAMICFIXED会返回E_NOTIMPL—— 这也正是头文件中“WSLC_VHD_TYPE_FIXEDis only honored byWslcCreateSessionVhdVolume”备注的由来要求flags必须为WSLC_VHD_REQ_FLAG_NONE否则E_INVALIDARG防止调用者误以为 owner 设置作用在了根文件系统 VHD 上传NULL时重置为默认值sizeBytes s_DefaultStorageSize。换言之WslcCreateSessionVhdVolume才是该结构体全部字段含name、typeFIXED、OWNER标志的“全量消费者”这是文档头注两条 Header notes 的完整背景。4. WslcDeleteSessionVhdVolume签名与实现4.1 签名与参数STDAPI WslcDeleteSessionVhdVolume( _In_ WslcSession session, _In_z_ PCSTR name, _Outptr_opt_result_z_ PWSTR* errorMessage);ParameterTypeDirectionsessionWslcSessioninnamePCSTRin_In_z_指向以空字符终止的卷名errorMessagePWSTR*out, optional返回值HRESULT。参考文档示例HRESULT hr WslcDeleteSessionVhdVolume(session, cache, NULL);4.2 实现与语义实现非常短位于 wslcsdk.cpp#L535-L546校验会话处于有效状态否则ERROR_INVALID_STATE、name非空否则E_POINTER然后直接转发到底层session-DeleteVolume(name)。从单元测试WslcSdkTests.cpp#L2174-L2182可确认其完整语义删除成功后对应的会话存储目录/volumes/name.vhdx文件必须已从磁盘移除。因此删除是不可逆的——卷内数据随之丢失生产环境中应在删除前把关键数据拷出或先停止挂载该卷的容器。5. 端到端实战创建卷并用容器读写测试用例WslcSdkTests.cpp#L2100-L2182提供了一条完整可参考的调用链展示了命名卷的典型生命周期建会话WslcInitSessionSettingsWslcCreateSession测试刻意使用独立会话目录避免影响共享默认会话建卷WslcCreateSessionVhdVolume创建名为c_volumeName的动态卷并断言后端 VHDX 文件存在挂载写入通过WslcSetContainerSettingsNamedVolumes把命名卷挂进容器的/dataWslcContainerNamedVolume namedVol{}; namedVol.name c_volumeName; // 与 WslcVhdRequirements.name 一致 namedVol.containerPath /data; // 容器内绝对路径 namedVol.readOnly FALSE; WslcSetContainerSettingsNamedVolumes(containerSettings, namedVol, 1);容器执行echo wslc-vhd-test /data/marker.txt写入标记文件WslcContainerNamedVolume定义见 wslcsdk.h#L205-L210 4.跨容器读取第二个容器以readOnly TRUE只读挂载同一卷cat /data/marker.txt读回wslc-vhd-test\n验证了命名卷在会话内多个容器之间的数据共享 5.删卷WslcDeleteSessionVhdVolume后断言 VHDX 文件不再存在。6. WinRT 封装对照VhdOptions 与 Session 接口同一组 API 在 WinRT 侧有面向托管/WinRT 调用者的封装。VhdOptions的构造函数接收name、size、VhdType其中size 0会在构造/赋值阶段即抛出E_INVALIDARGVHD size cannot be zero见 VhdOptions.cpp#L21-L28当设置了Owner含Uid/Gid的可选引用时ToStructPointer()会把它们填入WslcVhdRequirements并自动置位WSLC_VHD_REQ_FLAG_OWNERVhdOptions.cpp#L95-L114。会话接口CreateVhdVolume/DeleteVhdVolume则直接桥接到本文讲解的两个 C 函数Session.cpp#L322-L336。WinRT 单元测试WslcSdkWinRTTests.cpp#L1523-L1591覆盖了动态卷、固定卷与 owner 卷三条路径行为与 C API 一致。7. 要点小结WslcCreateSessionVhdVolume接受WslcVhdRequirements的全部字段name卷名、sizeBytes必须 0、typeDYNAMIC或仅本函数认可的FIXED、OWNER标志控制uid/gid是否生效作用于卷根 inode 属主任何未知标志位或非法type都以E_INVALIDARG拒绝。卷以会话存储目录/volumes/name.vhdx落盘驱动选项为SizeBytes/Fixedtrue/Uid/Gid创建动作最终转发到底层CreateVolumewslcsdk.cpp#L524-L531。创建出的命名卷通过WslcSetContainerSettingsNamedVolumes挂载进容器可读写或只读实现会话内多容器共享持久化数据。WslcDeleteSessionVhdVolume按名删除卷并移除后端 VHDX 文件操作不可逆其参数校验E_POINTER/ERROR_INVALID_STATE与创建函数一致。与WslcSetSessionSettingsVhd根文件系统 VHD 配置相比会话命名卷 API 是唯一支持固定分配 VHD 与属主设置的入口这是本组存储 API 最核心的差异化能力。【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考