Part 1.1 — 用户态入口:设备文件、ioctl 分发与 fd 类型

发布时间:2026/9/16 8:34:36

Part 1.1 — 用户态入口:设备文件、ioctl 分发与 fd 类型 UVM Part 1 用户态接口首篇。适用代码kernel-open/nvidia-uvm/关联源码uvm.c、uvm_fd_type.h、uvm_fd_type.c、uvm_ioctl.h、uvm_api.h1. 本篇要回答的问题前两篇讲的是内核里有哪些结构。本篇回到最上游——用户态请求是怎么进内核的CUDA 打开/dev/nvidia-uvm后一个struct file承载什么状态UVM_*ioctl 是如何被分发到具体uvm_api_*处理函数的为什么一个 fd 要区分UVM_FD_VA_SPACE/UVM_FD_MM等类型初始化为什么要做原子 CAS2. 代码地图关注点符号位置设备文件操作表uvm_fopsuvm.cstatic const struct file_operations打开设备uvm_open()uvm.cioctl 分发uvm_ioctl()uvm.c分发宏UVM_ROUTE_CMD_*uvm_api.h初始化uvm_api_initialize()uvm.cfd 类型uvm_fd_type_t,uvm_fd_type()uvm_fd_type.h/.cioctl 号 / 参数UVM_*_PARAMSuvm_ioctl.h3. 设备文件操作表uvm_fopsUVM 注册一个字符设备nvidia-uvm其file_operations极简staticconststructfile_operationsuvm_fops{.openuvm_open_entry,.releaseuvm_release_entry,.mmapuvm_mmap_entry,.unlocked_ioctluvm_unlocked_ioctl_entry,#ifNVCPU_IS_X86_64.compat_ioctluvm_unlocked_ioctl_entry,#endif.ownerTHIS_MODULE,};四个入口的分工回调作用后续篇open每个struct file建立独立address_space本篇第 4 节mmap把托管 / 信号量 / P2P 内存映射进用户 VAPart 1.2 / Part 3unlocked_ioctl所有UVM_*控制命令的总入口本篇第 6 节release关闭 fd销毁 VA space可能延迟到 kthreadPart 1.2每个*_entry包装函数用UVM_ENTRY_RET宏包裹真正实现统一做线程上下文 / 栈检查等是 UVM 的通用模式。4.uvm_open()为什么每个 fd 要独立 address_spaceuvm_open()做了一件不显眼但关键的事——给每个打开的文件分配独立的struct address_spacemappinguvm_kvmalloc(sizeof(*mapping));address_space_init_once(mapping);mapping-hostinode;mapping-a_opsinode-i_mapping-a_ops;filp-private_dataNULL;// 初始为 UVM_FD_UNINITIALIZEDfilp-f_mappingmapping;原因源码注释已说明默认同一 inode 上所有进程的struct file共享inode 的address_space那么unmap_mapping_range会跨进程一起解映射。而UVM 把 mapping offset 当作该进程文件的 VA因此必须让每个进程的映射相互隔离。此时filp-private_data NULL即UVM_FD_UNINITIALIZED尚未绑定任何 VA space。5. fd 类型系统一个 fd 可以是什么filp-private_data不是简单地存一个指针而是用低位打包类型标签uvm_fd_type.htypedefenum{UVM_FD_UNINITIALIZED,// 刚 open未初始化UVM_FD_INITIALIZING,// 正在初始化CAS 中间态UVM_FD_VA_SPACE,// 已绑定 uvm_va_space_tUVM_FD_MM,// 绑定 mm用于 va_space_mm 机制UVM_FD_TEST,// 测试用UVM_FD_COUNT}uvm_fd_type_t;#defineUVM_FD_TYPE_BITS3#defineUVM_FD_TYPE_MASK((1ULUVM_FD_TYPE_BITS)-1)因为指针天然按 8 字节对齐低 3 位恒为 0UVM 就把类型塞进低 3 位、高位存实际指针。uvm_fd_type(filp, ptr)解出{类型, 指针}uvm_fd_get_type(filp, TYPE)仅当类型匹配才返回指针。uvm_open()private_data NULLuvm_fd_type_init_cas()原子 CAS 抢占UVM_INITIALIZE 成功uvm_fd_type_set(VA_SPACE, va_space)创建失败回退允许重试UVM_MM_INITIALIZE测试路径uvm_release()UNINITINITIALIZINGVA_SPACEMMTEST6. ioctl 分发uvm_ioctl()的路由表所有控制命令进入uvm_ioctl()本质是一张大switch用一组UVM_ROUTE_CMD_*宏把 ioctl 号映射到uvm_api_*函数staticlonguvm_ioctl(structfile*filp,unsignedintcmd,unsignedlongarg){switch(cmd){caseUVM_DEINITIALIZE:return0;UVM_ROUTE_CMD_STACK_NO_INIT_CHECK(UVM_INITIALIZE,uvm_api_initialize);UVM_ROUTE_CMD_STACK_NO_INIT_CHECK(UVM_MM_INITIALIZE,uvm_api_mm_initialize);UVM_ROUTE_CMD_STACK_INIT_CHECK(UVM_REGISTER_GPU,uvm_api_register_gpu);UVM_ROUTE_CMD_STACK_INIT_CHECK(UVM_SET_PREFERRED_LOCATION,uvm_api_set_preferred_location);UVM_ROUTE_CMD_STACK_INIT_CHECK(UVM_MIGRATE,uvm_api_migrate);UVM_ROUTE_CMD_ALLOC_INIT_CHECK(UVM_ALLOC_SEMAPHORE_POOL,uvm_api_alloc_semaphore_pool);/* ...数十条... */}// 都没匹配 → 交给测试 ioctlreturnuvm_test_ioctl(filp,cmd,arg);}6.1 三种路由宏的区别宏名的差异编码了两个正交维度参数存放位置、是否需要已初始化的 VA space。宏参数缓冲VA space 检查典型命令..._STACK_NO_INIT_CHECK栈上不要求已初始化UVM_INITIALIZE、UVM_MM_INITIALIZE..._STACK_INIT_CHECK栈上要求UVM_FD_VA_SPACE绝大多数命令..._ALLOC_INIT_CHECK堆分配参数较大要求已初始化UVM_MAP_EXTERNAL_ALLOCATION、UVM_ALLOC_SEMAPHORE_POOL宏内部统一负责从用户空间copy_from_user参数、视宏而定校验 fd 已是 VA space、调用处理函数、再copy_to_user回写结果。因此每个uvm_api_*函数签名统一为NV_STATUS uvm_api_xxx(UVM_XXX_PARAMS *params, struct file *filp)。6.2 命令分类速览路由表里的命令大致可分为类别代表命令对应结构操作生命周期UVM_INITIALIZE/UVM_DEINITIALIZE创建 / 销毁uvm_va_space_tGPU 管理UVM_REGISTER_GPU/UVM_UNREGISTER_GPU改registered_gpus掩码PeerUVM_ENABLE_PEER_ACCESS改enabled_peers策略UVM_SET_PREFERRED_LOCATION/UVM_SET_ACCESSED_BY/UVM_ENABLE_READ_DUPLICATION改 rangepolicyPart 1.2迁移UVM_MIGRATE/UVM_POPULATE_PAGEABLE触发 make_residentPart 3.4外部内存UVM_MAP_EXTERNAL_ALLOCATION/UVM_IMPORT_DMA_BUFexternal / dma-buf range信号量 / P2PUVM_ALLOC_SEMAPHORE_POOL/UVM_ALLOC_DEVICE_P2P专用 range 类型工具UVM_TOOLS_*/UVM_QUERY_RESIDENCY观测Part 5.27.UVM_INITIALIZE并发安全的 VA space 创建UVM_INITIALIZE是把一个裸 fd 变成 VA space 的那一步也是并发处理的典范。多个线程可能同时对同一 fd 发UVM_INITIALIZE代码用原子 CAS保证只有一个线程真正创建old_fd_typeuvm_fd_type_init_cas(filp);// 期望 UNINIT → 换成 INITIALIZINGswitch(old_fd_type){caseUVM_FD_UNINITIALIZED:// 只有抢到的线程走这里statusuvm_va_space_create(filp-f_mapping,va_space,params-flags);if(status!NV_OK){uvm_fd_type_set(filp,UVM_FD_UNINITIALIZED,NULL);// 失败回退允许重试returnstatus;}uvm_fd_type_set(filp,UVM_FD_VA_SPACE,va_space);break;caseUVM_FD_VA_SPACE:// 已初始化仅当 flags 一致才算成功va_spaceuvm_va_space_get(filp);status(params-flags!va_space-initialization_flags)?NV_ERR_INVALID_ARGUMENT:NV_OK;break;caseUVM_FD_INITIALIZING:// 别人正在建 → 让用户重试statusNV_ERR_BUSY_RETRY;break;/* ... */}要点CAS 抢占uvm_fd_type_init_cas()把UNINIT原子换成INITIALIZING只有观察到UNINIT的线程负责创建 VA space。失败可重试创建失败时把状态复位为UNINIT其他线程只可能看到过INITIALIZING不会看到半成品VA_SPACE因此安全。幂等语义已是VA_SPACE时重复 initialize只要 flags 一致就返回成功。NV_ERR_BUSY_RETRY撞上中间态时返回让用户态重试而非阻塞等待。这一步成功后filp-private_data就指向 Part 0.2 讲的uvm_va_space_t后续所有UVM_ROUTE_CMD_STACK_INIT_CHECK命令才能通过 fd 类型检查。8. 完整入口时序uvm_api_*uvm_ioctl 路由uvm_fopsVFS用户态 (CUDA)uvm_api_*uvm_ioctl 路由uvm_fopsVFS用户态 (CUDA)open(/dev/nvidia-uvm)uvm_open()分配独立 address_spaceprivate_data UNINITioctl(fd, UVM_INITIALIZE, params)uvm_unlocked_ioctl_entryuvm_ioctl(filp, cmd, arg)uvm_api_initialize()CAS 建 va_spaceNV_OKfd 现为 VA_SPACEioctl(fd, UVM_REGISTER_GPU, ...)uvm_ioctl → 校验 fd 类型uvm_api_register_gpu()结果 copy_to_user9. 边界与坑点fd 类型必须先对UVM_ROUTE_CMD_STACK_INIT_CHECK会拒绝未初始化 fd工具类命令若在 initialize 前发出会失败。PM 锁uvm_unlocked_ioctl外层持g_uvm_global.pm.lock电源管理release若 trylock 失败会把销毁延迟到 kthreaduvm_release_deferred这在挂起 / 恢复期间尤其重要。测试 ioctl 兜底路由表未命中会落到uvm_test_ioctl仅在开启测试构建时有意义。别把UVM_FD_MM当 VA spaceUVM_MM_INITIALIZE走另一条 fd 类型用于va_space_mm机制Part 4 相关与主 VA space fd 不是一回事。10. 小结与下一篇uvm_fops只有 open / mmap / ioctl / release 四个入口open 为每个 fd 建独立address_space以隔离进程映射。fd 用低 3 位打包uvm_fd_type_tUVM_INITIALIZE通过原子 CAS 并发安全地绑定uvm_va_space_t。uvm_ioctl()用UVM_ROUTE_CMD_*宏把命令路由到统一签名的uvm_api_*宏名编码了参数放栈/堆 是否需已初始化。下一篇Part 1.211-vaspace-lifecycle深入uvm_va_space_create()/ GPU 注册 / range 创建与销毁把这些 ioctl 落到第 0.2 篇那棵结构树的增删改上。交叉引用fd 绑定的uvm_va_space_t字段见 01-four-layer-model策略类命令的语义见 Part 1.212-policy-apiUVM_MIGRATE的内核流程见 Part 3.433-make-resident-migrate。
延伸阅读

更多相关文章

2026/9/16 8:34:36

HTML5生鲜商城源码实战:从语义化骨架到响应式购物车优化

简介:这是一份面向前端初学者与中小型电商建站的HTML5水果蔬菜在线商城网站源码,适用于快速搭建网上蔬菜店、水果店或生鲜展示页面。资源打包为zip,共112个文件,压缩包仅4.53MB,以15个HTML页面、13个CSS样式文件、15个…

2026/9/16 8:29:35

CentOS7离线部署Python3.9+PyTorch深度学习环境实战

简介:本资源是一套面向人工智能初学者与进阶学习者的系统性自学资料包,覆盖机器学习基础、深度学习实践及环境配置等核心环节,适用于高校学生、转行入门者及自学备考人员。压缩包共105个文件,包含27个Jupyter Notebook&#xff08…

2026/9/16 9:29:48

静态网页设计期末作业95分攻略:从源码规范到交互实现

简介:这套基于原生 HTML、CSS、JavaScript 编写的前端静态网页大作业源码,精准面向高校网页设计课程期末作业场景,适合正在筹备大学生静态网页设计项目、需要高质量参考方案的学生。压缩包共 31 个文件,大小约 30.28MB&#xff0c…

2026/9/16 9:29:48

Agent技能工程化:用Nx+TypeScript构建可治理的技能契约体系

1. “agent-skills”不是库名,而是工程级能力抽象层的设计起点你第一次在 GitHub 或内部项目里看到agent-skills这个仓库名时,大概率会下意识认为:这是个封装了“AI Agent 常用工具函数”的 npm 包——比如调用天气 API、查数据库、发邮件、读…

2026/9/16 9:29:48

Windows自带三招查看电脑配置和显卡信息,不用装任何软件

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/16 9:29:48

不占CPU的GPIO高速采集:K60上PIT触发eDMA完整指南

简介:针对NXP Kinetis K60微控制器的GPIO与DMA驱动开发,这份压缩包给出了基于IAR环境的完整参考工程,面向嵌入式底层开发者与备赛学生,用于解决外设驱动配置繁琐、数据搬运占用CPU等问题。工程内附C源码与头文件,可学习…

2026/9/16 9:24:47

分布式能源系统选址定容的双层优化Matlab实现

1. 项目背景与核心价值分布式能源系统正在重塑现代电网的格局。作为一名在电力系统优化领域摸爬滚打多年的工程师,我亲眼见证了光伏储能组合如何从实验室走向商业化应用。这个项目要解决的痛点很明确:当大量分布式电源接入配电网时,如何科学地…

2026/9/15 4:54:30

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/16 0:04:09

PHP源码部署实战:从环境配置到运行情侣游戏全攻略

简介:这是一套面向情侣互动场景的PHP完整源码,集成情侣飞行棋、真心话大冒险、情趣骰子等玩法,并内置完整分销制度,可自定义多种返佣比例,源码完全开源无加密,支持微信无感自动授权登录与第三方授权&#x…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/15 21:31:11

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码