> 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/4.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/di-san-bu-fen-io-xi-tong/7.6.-pei-e.md).

# 7.6 配额

配额系统允许管理员控制任何用户在每个文件系统上可分配的 inode 数和数据块数。每个用户的配额按文件系统分别维护。

配额主要作为分配例程的辅助部分接入系统。图 7.18 显示，分配例程收到来自 `bmap()` 的新块请求时，请求先由 `quotachk()` 校验：`quotachk()` 查阅文件属主的配额。属主未超配额，请求获准并计入其使用统计；属主已达或超出自己的配额，请求遭拒，分配器便像文件系统已满那样向 `bmap()` 返回失败。

![图 7.18 配额控制的过程式接口](https://1991889543-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FilVST9xTgD47M0g8ham7%2Fuploads%2Fgit-blob-b33e4638f819232b6c817ebb37565c1c147c5d6a%2Ffig-7-18-figure-7-18-procedural.png?alt=media)

文件系统挂载之后才指派配额。一个系统调用把含配额的文件与挂载的文件系统关联起来。按惯例，该文件名为 **quotas**，位于挂载文件系统的根。系统打开 **quotas** 文件，在挂载表与该文件系统相关的表项中持有它的引用；图 7.19 展示挂载表中的引用。需要不同用户的配额时，从 **quotas** 文件取来。

![图 7.19 对 quotas 文件的访问](https://1991889543-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FilVST9xTgD47M0g8ham7%2Fuploads%2Fgit-blob-01df5a8dc698c362f67abfeafb925c37cfb271a6%2Ffig-7-19-figure-7-19-access.png?alt=media)

**quotas** 文件维护为按用户标识符索引的配额记录数组；图 7.20 展示一条典型记录。要找用户标识符 *i* 的配额，系统在配额文件中定位到 *i* × `sizeof`（`quota` 结构）处，读取那里的配额结构。每个配额结构包含对该用户在此文件系统上的限制：块数和 inode 数的硬限制与软限制、当前已分配的块数和 inode 数，以及软限制被当作硬限制执行之前用户还能收到的警告次数。

图 7.20 配额记录的内容

```
/quotas 文件: uid 0: | uid 1: | ... | uid i: | ... | uid n:
                                      ↓
              ┌─────────────────────────────┐
              │ uid i 的配额块              │
              │  块配额                     │
              │  块限额                     │
              │  当前块数                   │
              │  剩余块警告次数             │
              │  inode 配额                 │
              │  inode 限额                 │
              │  当前 inode 数              │
              │  剩余 inode 警告次数        │
              └─────────────────────────────┘
```

配额保存在一张称为 dquot 表的系统表中；图 7.21 展示两个典型表项。与 inode 表一样，dquot 表在配额信息驻留期间维护附加信息，以加快访问和识别。由于每次写文件都可能要更新配额，`quotachk()` 必须能快速找到并操作配额。因此，文件关联的 dquot 结构只需在文件首次打开时查找一次：文件的 inode 首次进入 inode 表时，系统检查是否与之关联了配额。有配额，inode 便被配置为在驻留期间持有对 dquot 结构的引用。`quotachk()` 例程只须检查 dquot 指针非空即可判断文件有配额；非空则所需信息都能直接访问。用户在同一文件系统打开多个文件时，描述这些文件的 inode 都指向同一个 dquot 表项。于是，随时都能轻易而一致地知道某用户被分配了多少块。

![图 7.21 dquot 表](https://1991889543-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FilVST9xTgD47M0g8ham7%2Fuploads%2Fgit-blob-3c824306824da42d3e88343466f429b13acde1d5%2Ffig-7-21-figure-7-21-the.png?alt=media)

dquot 表中的表项数量可能变得很大。为加快访问，dquot 表采用散列查找，按文件系统和用户标识符作键。散列结构和空闲链的建立方式与图 7.11 中的 inode 表相同。dquot 结构的引用计数归零时，该表项便被链到空闲链上；dquot 结构不从散列链摘除，因此很快要再用时仍能定位。只有当 dquot 结构被回收用作新的 dquot 结构时，才会把它摘下并重新链入散列链。

散列结构便于快速找到最近使用过的 dquot 结构，却解决不了“如何发现用户在某文件系统上没有配额”的问题。用户没有配额时，查找配额会落空；为了发现这一点而去读盘上的配额文件，代价高得无法接受。为避免每次访问新文件都做这项工作，系统维护一张配额表，每个活跃用户标识符占一个表项；图 7.22 展示一张典型的配额表。某用户的 inode 首次被访问而该用户在配额表中尚无表项时，系统为该用户在配额表中建立表项。此时系统检查每个启用了配额的文件系统，判断该用户在这个文件系统上是否有配额：有配额，就为该文件系统保存指向 dquot 表的指针；没有配额，就把相应表项标记为无配额。为让用户打开自己的文件这一常见情形处理得更快，系统从每个 proc 表表项维护一个指针，指向该进程所属用户在配额表中的表项。进程打开由运行它的用户所拥有的文件时，系统沿指针找到该用户在配额表中的表项；若该用户在这个文件系统上有配额，系统就递增相应 dquot 结构的引用计数，并把引用存入 inode。进程打开其他用户的文件时，系统必须用散列查找在配额表中找到该用户的表项；找到后即可走同样的流程。

图 7.22 配额表

```
proc 表:          配额表:                     dquot 表:
  ⋮               uid = 7 引用计数 = 1        dev = /      uid = 7  配额块
  uid 10        → <无>                        dev = /usr   uid = 7  配额块
  uid 7           ⋮                           dev = /arch  uid = 10 配额块
  uid 10        → uid = 10 引用计数 = 2       dev = /usr   uid = 8  配额块
  ⋮               <无> <无>                   dev = /arch  uid = 8  配额块
  uid 8        →  ⋮
  ⋮               uid = 8 引用计数 = 1
                  <无>
```


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://book.bsdcn.org/4.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/di-san-bu-fen-io-xi-tong/7.6.-pei-e.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
