
我原来把这个文件看成“安装设备加上一组统一转发函数”。这个理解仍然是主线但要把它用起来还得分清三个东西设备表位置、设备号以及设备大类/子类型。本次核对本地na-kernel的历史版本490d5f0d3adf83c5670a181a2708a5c4a670d4c6文件为 kernel/src/dev/device.c 和 device.h。其设备表、编号公式和转发结构与原截图对应没有证据证明原截图恰好来自同一个提交不把不同日期的块设备代码强行拼成一个可运行版本。历史源码。1. 设备表不是设备号数组devices保存device_t结构devices_idxs记录各子类型已经分配的次编号。设备在devices里的下标不等于dev字段。这个版本查找设备号时是线性扫描而不是直接用dev当数组下标。原文说“name设置为null”不准确这里name被复制字符串null并不是名字指针被设为NULL。type/subtype设为DEV_NULL、dev置零部分回调置NULL。devices是静态存储对象首次启动时其未显式写的字段也会零初始化但device_init并没有显式重置ptr、poll、map全部字段。所以不能从“第一次初始化没问题”推导出它支持随时完整重置设备表。本次测试不修改内核实现仅标明这个边界。2. 安装是取得槽位、填写字段再注册到devfsget_null_device从下标1开始用typeDEV_NULL判断空闲找不到返回NULL。保留槽位0和给设备号赋值是两件事。ptr不是指向device_t自身的必然指针它由驱动传入可以指向私有状态。统一层只保存它之后再原样交回回调。name、parent和各回调也都在此时填入最后调用devfs_register_device。这份历史代码没有在取槽后检查NULL也未在此函数内验证subtype范围、长名称的终止情况或并发分配。阅读时要记录这些前置条件本文不执行越界或空指针输入不把“正常路径测试通过”说成注册接口已经健壮。编号公式是(subtype 8) | minorminor来自该子类型的计数再自增。它是这个内核的编码方式不是现代Linux dev_t的通用布局。当前表共256槽、安装跳过槽0若以后扩大容量或支持反复注销安装也需重审minor位宽与编号唯一性。3. device_find按子类型枚举不按大类筛选这是原文最需要修正的一句device_find(DEV_BLOCK, 0)并不表示“第一块设备”。DEV_BLOCK是type枚举函数比较的是subtype应传DEV_DISK、DEV_PART等具体子类型。device_t *first_disk device_find(DEV_DISK, 0); device_t *second_disk device_find(DEV_DISK, 1);idx表示按设备表扫描顺序遇到的第几个匹配项不是设备号minor字段的查询条件。这份只安装不注销的正常流程可能让两者恰好一致但函数实现并没有比较minor。device_get扫描dev字段。初始化后大量空槽dev都是0因此这个版本device_get(0)可以返回槽位0不会自动得到NULL。调用者不能把“非NULL”直接当作“已安装的活跃设备”。4. 统一转发层要看三个分支状态ioctl/read/write/poll统一层的行为找不到设备号返回-ENODEV找到设备但对应回调为空返回-ENOSYS回调存在传入device-ptr和操作参数返回驱动结果“不存在”和“不支持”不是一个错误。回调自己的负错误码也应原样传回不能在封装层吞掉变成成功。已确认的局部链路 device_ioctl(dev, cmd, args) - device_get(dev) - device-ioctl(device-ptr, cmd, args)原文写“用户ioctl - VFS - device_ioctl”那是一条需要继续查调用者的更长链路仅凭这个文件不能证明系统调用、文件描述符与devfs上层都已经接通。本文的实测止于上面的局部接口。这张历史块设备图使用整数drive/cmd/arg而本版本device.h中的ioctl签名是int (*)(void *, int, void *)。它能展示“按操作号分发”的思路但不能据图断言两个版本的函数可直接互换。本次驱动桩严格使用device.h的回调签名。read/write的返回类型是ssize_t允许表示负错误idx、count、flags都被继续传入。统一层本身并不转换字节与扇区单位单位要查具体驱动的约定。map不能照搬普通read的返回值判定这里用转换为指针的负错误值表示失败上层必须遵循该内核的错误指针约定不能只判断NULL就把它当可访问地址。这个约定与可移植C接口也要分开看。5. 怎么验证不用真的去访问磁盘本次从历史提交提取真实device.c与device.h仅把三个内核头文件依赖换为宿主测试头EXPORT_SYMBOL在测试中置空注册devfs使用记录调用的桩。没有另写一份相似的设备层代替原代码。驱动桩保存一个可识别的状态对象ioctl验证收到的ptr、cmd、argsread/write/poll/map也记录各自参数和返回值。这样能发现“驱动被调用了但拿到的却是错误对象或参数”。测试项核对内容安装两种子类型空槽从1分配计数按子类型独立devfs桩得到同一设备对象find/get按子类型找第0/1项按dev找原对象越过已安装数量返回NULL正常与缺失回调私有状态及操作参数不丢失驱动返回值原样传回不存在设备四种整数返回接口及map的错误表示初始化约定首次静态零初始化device_get(0)确实命中空槽不声称完整重置宿主环境用GCC编译并运行断言。这个版本的注册参数使用void*传入回调依赖内核工具链支持不能把测试通过说成ISO C对任意平台都保证这种转换。本次不是启动naos不是硬件读写也没有验证VFS系统调用端到端。它证实的是对应历史实现的注册和转发行为缺失的容量检查、重置语义与版本差异仍然是审查发现不因正常测试通过就被抹掉。和device.h分析一起看头文件定义了驱动能力device.c把能力装进统一入口。读这种封装层除了看“它转发了”还要追问它找的是谁传给谁的什么状态失败如何向上表示。