ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

3. blob 的三维输入模型:blob_mem × blob_flags × blob_id

3. blob 的三维输入模型:blob_mem × blob_flags × blob_id 前两篇我们回答了“为什么要有 blob”和“它在整栈的哪个位置”。从这一篇起我们正式进入规范层。guest 想要一块 blob 时它到底告诉了 host 哪些信息答案浓缩成三个参数blob_mem、blob_flags、blob_id。这三者相互正交共同构成整个 blob机制的“语义骨架”。理解了它们你就理解了后端为什么会产出四种截然不同的存储形态。1、先看命令长什么样guest 内核发出的命令是VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB它携带的关键字段可以简化为structvirtio_gpu_resource_create_blob{uint32_tresource_id;/* 资源身份证res_id */uint32_tblob_mem;/* 维度一存储在哪 */uint32_tblob_flags;/* 维度二可见性 / 共享语义 */uint64_tblob_id;/* 维度三引用哪块已有 host 内存 */uint64_tsize;/* 存储大小 *//* 后随 guest 页的 iovec 数组可选详见第 6 篇 */};在 host 侧virglrenderer 把它接成virgl_renderer_resource_create_blob_args然后进入 virglrenderer.c 的校验与分发。本篇文章我们就围绕中间那三个字段展开。2、维度一blob_mem —— 存储在哪blob_mem回答最根本的问题这块内存的“真身”存在哪一侧它有三个取值。取值含义谁提供存储VIRTIO_GPU_BLOB_MEM_GUEST存储就是 guest 的物理页guestiovec 描述第 6 篇详解VIRTIO_GPU_BLOB_MEM_HOST3D存储由 host 分配host 后端GPU 显存 / Vulkan memoryVIRTIO_GPU_BLOB_MEM_HOST3D_GUEST两者都有host 分配 guest 镜像在 virglrenderer 里这个三选一直接被翻译成两个布尔量见 virglrenderer.cswitch(args-blob_mem){caseVIRGL_RENDERER_BLOB_MEM_GUEST:has_host_storagefalse;has_guest_storagetrue;break;caseVIRGL_RENDERER_BLOB_MEM_HOST3D:has_host_storagetrue;has_guest_storagefalse;break;caseVIRGL_RENDERER_BLOB_MEM_HOST3D_GUEST:has_host_storagetrue;has_guest_storagetrue;break;}这两个布尔量决定了后续的走向只有 guest 存储GUEST核心根本不需要问后端直接用 guest 的 iovec 建资源virgl_resource_create_from_iov走的是最短路径。有 host 存储HOST3D/HOST3D_GUEST核心必须调ctx-get_blob(...)让后端去分配真实的 host 存储——这才是 blob 机制的“重头戏”。一句话记忆blob_mem决定“要不要惊动后端”。3、维度二blob_flags —— 可见性与共享语义blob_mem决定存储在哪blob_flags就决定这块存储能被谁、以什么方式看见。它是一组可叠加的位标志flag诉求对后端的硬约束USE_MAPPABLEhost 存储要能映射进 guest 地址空间必须能mmapmemfd / dmabuf / shmUSE_SHAREABLE可跨 context 共享不能用会失效的 opaque handleUSE_CROSS_DEVICE要能被别的设备使用必须导出成 dma-buf这三个 flag 每一个都不是“建议”而是倒逼后端选择存储介质的强约束。举两个例子体会一下例一CROSS_DEVICE强制 dma-buf。在 venus 后端vkr_device_memory.c里能清楚看到这条约束落地if(blob_flagsVIRGL_RENDERER_BLOB_FLAG_USE_CROSS_DEVICE){if(!can_export_dma_buf){vkr_log(mem cannot export to dma_buf for cross device blob sharing);returnfalse;}fd_typeVIRGL_RESOURCE_FD_DMABUF;/* 别无选择只能 dmabuf */}因为只有 dma-buf 这种内核对象才能被 display、编码器、别的进程认识。opaque fd 出了原设备就失去意义。例二SHAREABLE禁用 opaque handle。opaque handle比如 GEM handle是某个 context 私有的整数一旦离开原 context/进程就变成悬空的野值。所以规范规定一旦要SHAREABLE后端就不能用 opaque handle必须退到真正的内核对象 fd。这条约束在 virgl_resource.h 的注释里写得很直白。一句话记忆blob_flags决定“存储介质必须是什么形态”。4、维度三blob_id —— 引用一块已有的 host 内存前两个维度描述“新建一块存储”而blob_id解决另一类问题guest 想引用 host 侧此前已经建立、正等待被“具象化”成资源的一块内存。最典型的场景是 venusVulkanguest 应用先vkAllocateMemoryvenus 在 host 侧真正分配了一块VkDeviceMemory并给它编号之后 guest 才决定“把这块 memory 变成一个 virtio-gpu 资源”于是发RESOURCE_CREATE_BLOB用blob_id指向第 1 步那块 memory后端凭blob_id找回那块 memory导出 fd填进 blob。所以blob_id本质是host 对象的一次性提货凭证。规范特别强调它的“一次性”——get_blob的注释virgl_context.h写道get_blob is a one-time thing. The context object might be destroyed or reject subsequent get_blob calls.也就是说同一个blob_id提货一次后就作废不能重复兑现避免两个资源指向同一块存储造成所有权混乱。一句话记忆blob_id决定“兑现哪一张此前开出的提货凭证”。5、三维合起来一张决策矩阵三个维度正交但真正决定“后端产出什么”的是它们的组合。我们把常见组合摊平成一张矩阵GUESTHOST3D / _GUESTCROSS_DEVICESHAREABLE仅 MAPPABLE无 flag / 同 ctxRESOURCE_CREATE_BLOBblob_mem · blob_flags · blob_idblob_mem?用 guest iovec 建资源不惊动后端ctx-get_blob 交给后端blob_flags?dma-buf fd内核对象 fd禁用 opaque handledmabuf / opaque fd / shmopaque handle 或 va把这张矩阵和第 1 篇文末那张“四种存储形态”的剧透图对照你会发现它们其实是同一件事的两个视角规范输入组合后端典型产出承载它的 union 成员HOST3D CROSS_DEVICEdma-buf fdu.fdHOST3D MAPPABLEopaqueopaque fd Vulkan UUIDu.fdvulkan_infoHOST3D同 contextGEM opaque handleu.opaque_handleHOST3D SVM 扩展虚拟地址u.va_handleGUEST不经后端用 iovec——这张对照表就是第 11 篇讲virgl_context_blob时的“入口”——结构体里那些看似杂乱的 union 分支全都是这张矩阵的产物。6、本篇小结与下一站这一篇我们拆开了 blob 的“语义骨架”blob_mem决定存储在哪、要不要惊动后端GUEST / HOST3D / HOST3D_GUESTblob_flags决定存储介质必须是什么形态MAPPABLE / SHAREABLE / CROSS_DEVICE 都是强约束blob_id是一张一次性提货凭证用来引用 host 侧已有的内存对象三者的组合直接决定了后端产出四种存储形态中的哪一种。下一篇第 4 篇我们顺着MAPPABLE这条线往下走——host 分配的内存究竟怎么“出现”在 guest 里让 guest 用户态访问得到这就要引出 host-visible 内存区以及RESOURCE_MAP_BLOB/UNMAP_BLOB这对命令还有那个一路要传到 hypervisor 页表的map_info。 这是跨域(host/guest)共享的机制之一全专栏的底层核心不要错过。导航上一篇第 2 篇 整栈全景图一次 blob 分配要穿过多少层下一篇第 4 篇 host-visible 内存区与 MAP/UNMAP_BLOB 命令
返回列表