登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

磁盘空间没满却无法写入:inode、配额与保留块检查

来源:17golang原创

时间:2026-10-07 12:21:19 326浏览 收藏

Linux 报 No space left on device,并不只表示“磁盘字节用完”。创建或扩展文件至少会受到四类限制:文件系统的数据块、可分配 inode、当前用户/组/项目的配额,以及 ext2/3/4 留给特权进程的保留块。只看一眼 df -h 的容量百分比,很容易删错目录或误改文件系统参数。

我处理这类问题时,先固定报错路径和执行身份,再记录四组基线指标。目标不是立刻“释放一点空间”,而是找出哪一个计数先到边界。ENOSPC 表示设备没有可用空间,EDQUOT 表示磁盘配额耗尽;不少应用会把底层错误统一包装成相似文案,所以最终仍要回到文件系统指标。

GNU df 官方文档:https://www.gnu.org/software/coreutils/manual/html_node/df-invocation.html

Linux 内核 ext4 文档:https://www.kernel.org/doc/html/latest/filesystems/ext4/

判断顺序
  • 先用 findmnt -T 确认报错目录究竟落在哪个挂载点和文件系统。
  • df -h 看数据块,df -i 看 inode;两者是独立资源。
  • 两组都有余量时,检查当前用户、组或项目是否碰到配额 hard limit。
  • 只有文件系统是 ext2/3/4 时,才检查特权进程保留块;不要把 XFS、Btrfs 或网络文件系统套进 ext 的处理方式。

先建立基线:确认路径、挂载点和四组指标

一次让我印象很深的故障发生在日志目录:根分区看起来还有空间,应用却无法创建新的轮转文件。最初大家围着最大的日志删文件,后来才发现应用目录是单独挂载,且小文件把 inode 用完了。这个经历之后,我不再从设备名猜挂载点,而是始终让命令围绕真实报错路径执行。

# 把这里改成真正报错的目录,所有检查都围绕同一路径进行。
target_path="/srv/app/data"

# 确认该路径对应的设备、文件系统类型、挂载点和挂载选项。
findmnt -T "$target_path" -o SOURCE,FSTYPE,TARGET,OPTIONS

# 检查数据块总量、已用量、普通进程可用量和使用率。
df -hT -- "$target_path"

# 检查 inode 总数、已用数、可用数和 IUse%。
df -i -- "$target_path"

df 接收路径时,会报告包含该路径的文件系统;-i 则把块使用信息换成 inode 使用信息。GNU 文档把 inode 定义为保存文件所有者、权限、时间戳和磁盘位置等信息的索引节点。对 ext4 来说,inode 表按块组预先组织,因此“还有很多数据块”和“还能不能创建新文件”是两个问题。

基线指标危险证据优先假设
df -h 的 Avail普通进程可用量为 0数据块耗尽,或只剩特权进程保留块
df -i 的 IFree / IUse%IFree 为 0 或 IUse% 为 100%inode 耗尽,常见于海量小文件
quota 的 used / hard块或文件数达到 hard limit用户、组或项目配额阻止继续写入
文件系统类型ext2、ext3 或 ext4继续核对保留块;其他类型走各自工具
目标挂载点的数据块、inode、身份配额和特权保留块四类写入容量关系
图1:写入容量的四维静态结构。目标挂载点同时受数据块与 inode 约束,调用身份还可能受到用户、组或项目配额限制;ext 保留块只对特定特权身份开放。这是结构说明图,不是运行截图。

假设一:inode 用完,字节容量仍然充足

inode 耗尽最符合“空间没满却创建不了新文件”的直觉冲突。一个很大的文件通常只占一个 inode,而百万级缓存碎片、会话文件、邮件队列或未清理的空文件,会快速消耗 inode,却未必占用多少数据块。

# 继续检查同一目标路径,避免把其他分区的 inode 指标当成证据。
target_path="/srv/app/data"
df -i -- "$target_path"

# 只在已确认的挂载点内按目录汇总文件数量,-xdev 避免跨入其他文件系统。
find "$target_path" -xdev -type f -printf '%h\n' \
  | sort \
  | uniq -c \
  | sort -nr \
  | head -n 20

第二段命令可能在文件极多时本身也比较重,应先缩小到业务已知目录,并避开高峰。证据成立时,正确动作通常是按业务保留期清理、归档或合并小文件,调整缓存和轮转策略;不是去删除某个大文件。inode 数量通常在文件系统创建时确定,后续不能把剩余字节简单“转换”为 inode。

复测也必须看两项:删除或归档后,IFree 应增加;应用使用原身份在原目录创建文件应恢复。只看到 df -h 的 Used 降低,不足以证明 inode 问题已经解决。

假设二:当前身份达到配额,文件系统全局仍有余量

配额是另一套独立计数。Linux 配额系统可以对用户、组和项目限制文件系统中的空间与 inode 使用量。hard limit 不能超越;soft limit 可以暂时超过,但过了宽限期会按硬限制处理。于是管理员查看全局 df 时还有余量,应用账号仍可能收到配额错误。

# 以当前登录身份查看用户配额,-s 使用易读单位。
quota -s

# 查看当前用户所属组的组配额;不同发行版可能需要安装 quota 工具包。
quota -g -s

# 管理员汇总本机已启用文件系统的用户与组配额,命令仅做报告。
sudo repquota -a

检查时要同时看空间块和文件数限制。有些账号没有碰到字节 hard limit,却已经达到 inode hard limit;有些容器或工作目录使用项目配额,普通 quota -s 看不到项目维度,需要按文件系统类型使用管理工具核对项目 ID。

如果配额正是组织的隔离策略,不要通过换成 root 写入来“绕过去”。合理修复是清理该身份拥有的过期数据,或由管理员根据容量预算调整 hard limit。调整后用同一个应用账号、同一个目录复测,避免管理员身份成功而业务进程仍失败。

假设三:ext 保留块让普通进程先看到 Avail 为零

ext2、ext3 和 ext4 可以保留一部分文件系统块,只允许特权进程分配。tune2fs 手册说明,这样做一方面降低文件系统严重填满时的碎片风险,另一方面让 syslogd 等系统守护进程在普通进程被禁止写入后仍能继续工作;默认保留比例通常是 5%。

这个机制只应在 findmnt 已确认文件系统为 ext2/3/4 后检查。下面命令只读取超级块,不修改参数:

# 从真实报错路径解析底层设备和文件系统类型。
target_path="/srv/app/data"
filesystem_type="$(findmnt -n -o FSTYPE -T "$target_path")"
source_device="$(findmnt -n -o SOURCE -T "$target_path")"

# 只有 ext2/3/4 才使用 tune2fs 读取保留块;其他类型必须改用对应工具。
case "$filesystem_type" in
  ext2|ext3|ext4)
    sudo tune2fs -l "$source_device" \
      | grep -E 'Block count|Free blocks|Reserved block count|Reserved block percentage'
    ;;
  *)
    printf '文件系统 %s 不适用 tune2fs 保留块检查\n' "$filesystem_type"
    ;;
esac

如果 df -h 显示普通进程的 Avail 已接近零,而超级块仍有明显的 Reserved block count,就能解释为什么 root 还能写、业务账号却失败。但这不是“隐藏的免费空间”。直接把保留比例调到 0 会削弱系统在满盘时保留日志、远程登录和清理能力,尤其不适合根文件系统。

对于超大、纯数据用途且有独立监控和应急预案的 ext 文件系统,可以在容量评审后评估较低比例;真正的长期方案仍是扩容、限流和清理策略。本文只检查,不给出一条可盲目复制的修改命令。

df 块指标、df inode 指标、quota 限制、findmnt 类型和 tune2fs 保留块的静态证据矩阵
图2:只读诊断证据矩阵。df -h、df -i、quota、findmnt 与 tune2fs 分别回答不同问题;要让证据指向同一目标挂载点和同一调用身份。这是静态说明图,不是终端截图。

按证据改动,而不是按错误文案猜原因

证据组合结论优先处置不建议
Avail 为 0,inode 有余量数据块或保留块边界先清理/扩容,再按文件系统类型检查保留策略只删大量空文件
IFree 为 0,块有余量inode 耗尽归档小文件,修正缓存与轮转只删除一个大文件
块和 inode 都有余量,quota 达 hard身份配额限制清理该身份数据或审批调整配额改用 root 绕过
ext 文件系统、普通 Avail 为 0、仍有保留块只剩特权保留容量恢复安全余量,评估专用数据盘比例在根分区盲目设为 0

如果四组指标都没有触边,就要扩大排查范围:挂载点是否变成只读、应用是否写到另一个 namespace、删除但仍被进程打开的文件是否占用块、底层存储或网络文件系统是否延迟分配失败。它们同样可能造成写入失败,但不能用 inode、配额或保留块的结论硬解释。

复测方法:同一路径、同一身份、同一类型操作

修复后,我会保留变更前后的四项数值,而不是只看应用重启后“暂时不报错”。复测应满足:

  1. findmnt -T 仍指向预期挂载点,没有把测试写到别的文件系统。
  2. df -h 的 Avail 留出运维安全余量,不是刚从 0 变成极小值。
  3. df -i 的 IFree 明显恢复,并且增长速度受清理或轮转策略约束。
  4. 应用身份的空间和文件数配额都低于 hard limit,必要时也核对项目配额。
  5. 使用业务进程的同一用户,在原目录完成真实的创建、追加和删除,而不是只让 root 执行 touch。

指标驱动的价值在这里很直接:inode 问题修复后,IFree 会变化;配额问题修复后,used 与 hard 之间会重新出现余量;保留块问题则会体现为普通进程可用量与特权可用范围的差异。每个改动都应有对应数字,而不是依赖“删了一些东西”的感觉。

常见问题

df -h 没到 100%,为什么仍然写不进去?

先看 Avail 而不是只看 Use%。还要核对 inode 和配额。ext 文件系统只剩保留块时,普通进程可能已经没有可分配块,而特权进程仍保有应急空间。

df -i 的 IUse% 为 100% 应该删大文件吗?

通常优先找海量小文件。大文件和小文件都需要 inode,但一个大文件通常只占一个 inode;删除单个大文件会释放数据块,却未必解决 inode 耗尽。

root 能写、应用账号不能写就一定是保留块吗?

不一定。用户、组或项目配额以及目录权限也会造成身份差异。先看 errno、quota 报告和文件系统类型,再判断是否是 ext 保留块。

可以直接把 ext4 保留块比例改成 0 吗?

不建议把它当成通用修复。根文件系统尤其需要保留应急写入能力。专用大数据盘是否降低比例,应结合容量、碎片风险、监控和故障恢复方案单独评审。

“磁盘空间没满却无法写入”不是一个单指标问题。数据块回答还能写多少字节,inode 回答还能创建多少文件对象,配额回答当前身份还能使用多少资源,保留块回答普通进程与特权进程的可用边界。把这四类证据放在同一个目标路径上,排障才会从猜测变成可复查的判断。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>