> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/man/man9/buf.9.md).

# buf.9

`buf` — FreeBSD VM 系统中使用的内核缓冲区 I/O 方案

## 名称

`buf`

## 描述

内核实现了缓冲区缓存的 KVM 抽象，允许将可能分散的 vm\_page 映射到连续的 KVM 中，供（主要是文件系统）设备和设备 I/O 使用。此抽象支持从 `DEV_BSIZE`（通常为 512）到数页或更多的块大小。它还支持相对原始的字节粒度有效范围和脏范围，目前硬编码用于 NFS。实现 VM 缓冲区抽象的代码主要集中于 FreeBSD 源码树的 `sys/kern/vfs_bio.c` 中。

处理缓冲区指针（`struct buf`）时需要记住的最重要事项之一是，底层页面直接从缓冲区缓存映射。在该方案本身中不会发生数据复制，尽管某些文件系统（如 UFS）在处理文件片段时确实需要少量复制。需要记住的第二重要事项是，由于底层页面映射，buf 中的 `b_data` 基指针始终是 *页* 对齐的，而非 *块* 对齐的。当有一个表示某个 `b_offset` 和 `b_size` 的 VM 缓冲区时，缓冲区的实际起始位置是 `b_data + (b_offset & PAGE_MASK)`，而不只是 `b_data`。最后，VM 系统的核心缓冲区缓存以 `DEV_BSIZE` 块为单位支持页面有效位和脏位（`m->valid`、`m->dirty`）。因此，硬件页大小为 4096 字节的平台有 8 个有效位和 8 个脏位。这些位通常根据支持页面的设备块大小成组设置和清除。整页的位通常使用 `VM_PAGE_BITS_ALL` 位掩码（即，如果硬件页大小为 4096，则为 0xFF）引用。

VM 缓冲区还跟踪字节粒度的脏范围和有效范围。此功能通常仅由 NFS 子系统使用。实际上，我不确定为什么还要使用它，因为 VM 缓冲区内已有 `DEV_BSIZE` 有效/脏粒度。如果缓冲区脏操作创建了一个"空洞"，脏范围将扩展以覆盖该空洞。如果缓冲区验证操作创建了一个"空洞"，字节粒度的有效范围将保持不变，不会考虑新的扩展。因此，整个字节粒度抽象被视为一个糟糕的权宜之计，如果能完全摆脱它会更好。

VM 缓冲区能够将底层 VM 缓存页映射到 KVM 中，以允许内核直接操作与（`vnode`、`b_offset`、`b_size`）关联的数据。内核通常在不再需要 VM 缓冲区时立即取消映射，但通常会保持 `struct buf` 结构实例化，甚至保持 `bp->b_pages` 数组实例化，尽管已将它们从 KVM 取消映射。如果组成 VM 缓冲区的页面即将进行 I/O，系统通常会将其从 KVM 取消映射，并用一个名为 bogus\_page 的占位符替换 `b_pages[]` 数组中的页面。占位符强制任何引用相关 `struct buf` 的内核子系统重新查找关联的页面。我相信使用占位符技巧是为了允许复杂的设备（如文件系统设备）重新映射底层页面，以便处理例如将文件片段重新映射到文件块的情况。

VM 缓冲区用于跟踪内核中的 I/O 操作。不幸的是，I/O 实现也有些权宜之计，因为内核想在将 I/O 排队到 VFS 设备时就清除底层页面的脏位，而不是在实际启动物理 I/O 时。这会在使用延迟写的文件系统设备中造成混乱，因为最终会出现标记为干净但实际仍然脏的页面。如果不小心处理，这些页面可能会被丢弃！实际上，直到 FreeBSD 2.2.8 和 FreeBSD 3.0 发布才修复了与此权宜之计相关的许多严重错误。内核使用实例化的 VM 缓冲区（即 `struct buf`）来占位处于此特殊状态的页面。缓冲区通常标记为 `B_DELWRI`。当设备不再需要缓冲区时，通常将其标记为 `B_RELBUF`。由于底层页面被标记为干净，`B_DELWRI|B_RELBUF` 组合必须被解释为缓冲区实际仍然脏，必须先写入其后备存储然后才能真正释放。在未设置 `B_DELWRI` 的情况下，底层脏页仍然正确标记为脏，缓冲区可以完全释放而不会丢失该干净/脏状态信息。（XXX 我们是否需要检查与此情况相关的其他标志？？？）

内核保留一部分 KVM 空间来保存 VM 缓冲区的数据映射。即使这是虚拟空间（因为缓冲区从缓冲区缓存映射），也不能使其任意大，因为实例化的 VM 缓冲区（`struct buf`）会阻止其在缓冲区缓存中的底层页面被释放。这会使分页系统的工作复杂化。

## 历史

`buf` 手册页最初由 Matthew Dillon 编写，首次出现于 FreeBSD 3.1（1998 年 12 月）。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/man/man9/buf.9.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
