ARTICLE DETAIL

建站实战干货

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

SerenityOS 内核中的 /dev/zero 设备:实现原理、设备号与实用示例

2026/9/10 16:17:46 拓冰建站 浏览量
SerenityOS 内核中的 /dev/zero 设备:实现原理、设备号与实用示例 SerenityOS 内核中的 /dev/zero 设备实现原理、设备号与实用示例【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity/dev/zero是 SerenityOS 提供的一个字符设备文件读它永远得到全\0字节流写它则被静默丢弃。本文以 zero(4) 手册页 为骨架深入 ZeroDevice 内核实现 与设备号分配机制帮助你理解数据汇data sink设备在内核中的工作方式并掌握在 SerenityOS 中使用与手动创建/dev/zero的完整方法。Name 与核心语义什么是 /dev/zero手册页 zero(4) 给出的定义非常精炼zero- data sink数据汇/dev/zero是一个字符设备文件其行为可以概括为两条规则写入即丢弃任何写入/dev/zero的数据都会被直接抛弃不做存储、不做处理读取返回全零从/dev/zero读取时返回\0字节即值为 0 的字节读取操作正常结束进程退出状态为 0。在 POSIX 风格系统中/dev/zero通常与/dev/null黑洞数据汇和/dev/full恒满设备并列为三类典型的“虚拟字符设备”。SerenityOS 的 null(4) 与 full(4) 手册页与之互相引用共同构成该主题的完整文档。内核实现ZeroDevice 的读取与写入/dev/zero的设备节点背后是内核类ZeroDevice其完整实现位于 Kernel/Devices/Generic/ZeroDevice.cpp声明位于 Kernel/Devices/Generic/ZeroDevice.h。从类声明可以看出它是一个典型的字符设备class ZeroDevice final : public CharacterDevice { // ^CharacterDevice virtual ErrorOrsize_t read(OpenFileDescription, u64, UserOrKernelBuffer, size_t) override; virtual ErrorOrsize_t write(OpenFileDescription, u64, UserOrKernelBuffer const, size_t) override; virtual bool can_read(OpenFileDescription const, u64) const override; virtual bool can_write(OpenFileDescription const, u64) const override { return true; } virtual StringView class_name() const override { return ZeroDevicesv; } };read()批量填充零字节read的实现是整个设备的核心仅有三行ErrorOrsize_t ZeroDevice::read(OpenFileDescription, u64, UserOrKernelBuffer buffer, size_t size) { TRY(buffer.memset(0, size)); return size; }它直接调用UserOrKernelBuffer::memset将用户缓冲区的前size个字节全部清零然后返回size表示“已读取”的字节数等于请求的字节数。由于can_read()恒返回true进程对/dev/zero的读取永远不会遇到 EOF可以无限地读取零字节流。write()数据汇写入即成功丢弃ErrorOrsize_t ZeroDevice::write(OpenFileDescription, u64, UserOrKernelBuffer const, size_t size) { return size; }write不去触碰传入的缓冲区内容直接返回size表示“已写入”全部字节——这正是“data sink数据汇”一词的含义数据被吸收、丢弃且写操作总是成功。设备号的来源Generic 家族minor 5设备构造时指定了设备号ZeroDevice::ZeroDevice() : CharacterDevice(MajorAllocation::CharacterDeviceFamily::Generic, 5) { }也就是说/dev/zero的主设备号major来自Generic字符设备家族次设备号minor为 5。设备号分配MajorNumberAllocation 机制主设备号的分配集中管理在 Kernel/API/MajorNumberAllocation.h 中。该文件定义了CharacterDeviceFamily枚举并明确约定Generic 1通用字符设备家族/dev/null、/dev/zero、/dev/full均属于此家族后续依次为DeviceControl 2、Serial 4、Console 5、Mouse 10、GPURender 28、VirtualConsole 35、Keyboard 85、Audio 116、MasterPTY 200、SlavePTY 201、GPU 226、VirtIOConsole 229等。代码中还有编译期static_assert保证这些家族编号按升序排列避免主设备号冲突。同类“数据汇”设备在 Generic 家族中的次设备号分布如下来自各设备构造代码设备节点类主设备号次设备号文件行为/dev/nullNullDevice1Generic3NullDevice.cpp读取返回 0EOF写入全部丢弃/dev/zeroZeroDevice1Generic5ZeroDevice.cpp读取返回\0流写入全部丢弃/dev/fullFullDevice1Generic7FullDevice.cpp读取返回\0流写入返回ENOSPC三者对比可见设计上的分工/dev/null读返回 EOF、/dev/zero读返回零字节、/dev/full写返回ENOSPC磁盘已满错误覆盖了程序测试与错误处理演练的常见需求。启动注册设备在何时创建ZeroDevice实例在系统启动早期由 Kernel/Arch/init.cpp 创建(void)MemoryDevice::must_create().leak_ref(); (void)ZeroDevice::must_create().leak_ref(); (void)FullDevice::must_create().leak_ref(); (void)FUSEDevice::must_create().leak_ref(); (void)RandomDevice::must_create().leak_ref();must_create()内部通过Device::try_create_deviceZeroDevice()完成实例化配合UNMAP_AFTER_INIT标记使该设备的初始化代码在引导完成后可从内核映像中释放。与RandomDevice随机数设备、PTYMultiplexer伪终端等一同在存储管理初始化前被注册保证用户态一启动即可访问/dev/zero。另外值得注意ZeroDevice::is_openable_by_jailed_processes()返回true说明该设备允许被 jailed受限进程打开属于内核信任的通用基础设备。实际使用从手册页示例到完整操作手册页自带示例zero(4) 中的示例展示了最基本的验证方式$ head -c 8 /dev/zero | hexdump 00 00 00 00 00 00 00 00head -c 8从/dev/zero读取恰好 8 个字节经管道交给hexdump后可见 8 个00字节——这正是read()中memset(0, size)的直接体现。生成固定大小的零填充文件在 SerenityOS 的 Shell 中可以用dd借助/dev/zero创建任意大小的零填充文件dd if/dev/zero ofblank.bin bs1024 count1024该命令会生成一个 1 MiB1024 × 1024 字节的全零文件常用于为后续格式化或文件系统操作准备空白镜像测试磁盘与文件系统对“大文件预分配”的处理抹除敏感数据前的占位填充配合/dev/random等随机源交替使用。手动重建设备节点与 full(4) 手册页给出的方式一致若/dev/zero节点缺失或损坏可以用mknod手动重建mknod /dev/zero c 1 5 chmod 666 /dev/zero其中c表示创建字符设备文件字符设备在 SerenityOS 中也可写作u1是主设备号对应MajorAllocation::CharacterDeviceFamily::Generic5是次设备号对应ZeroDevicechmod 666保证所有用户可读可写。mknod是 Userland 的标准工具实现见 Userland/Utilities/mknod.cpp支持-m mode参数指定八进制或符号权限默认0666支持b块设备、c/u字符设备、pFIFO四种类型并在创建 FIFO 时禁止指定设备号。例如显式指定权限的等价写法mknod -m 666 /dev/zero c 1 5注意事项与常见误区读取不会遇到 EOFcan_read()恒为true因此cat /dev/zero或dd if/dev/zero不指定count时会无限输出务必配合head -c N、dd bs... count...等限定字节数的手段写入恒成功对/dev/zero写数据不会返回错误与/dev/full的ENOSPC行为形成鲜明对比适合用来测试程序对“写入成功但数据被丢弃”场景的容错设备号不要混淆/dev/null是1 3/dev/zero是1 5/dev/full是1 7三者同属 Generic 家族但次设备号不同手动mknod时写错 minor 会导致行为不符合预期。相关手册页null(4) —— 数据黑洞设备full(4) —— 恒满设备结合阅读这三份手册页与对应的 Generic 设备内核实现即可完整掌握 SerenityOS 虚拟字符设备的全貌从设备号分配、内核 read/write 语义到用户态的实际使用与节点重建。【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考