nextpnr 磁盘写满:No space left on device 速查
更新时间:2026-10-25。FAQ 速查页,属于 FPGA 开源工具链排错系列。yosys + nextpnr + icepack(或 ecppack)这套开源流程本身是轻量的,单个设计产物不算大,但 CI 里每天几十轮回归、每轮都新建构建目录,磁盘照样会被慢慢填满。报错本身直白,难的是分清「是 nextpnr 写的文件大,还是工程管理方式不对」。同簇相邻问题见 yosys 磁盘写满、Quartus 磁盘写满,内存侧见 nextpnr 资源耗尽。
本文要回答的问题
- nextpnr 一次布线会写哪些文件?各自多大、哪些能安全删?
df显示满了,怎么三分钟找到最大的目录?- 构建目录和日志怎么设保留轮数,不再半夜撑爆 CI?
- /tmp 写失败和工程盘写失败,处置为什么完全不同?
一、报错原文与现象
ERROR: failed to write ascii file 'build/top.asc': No space left on device
Info: Writing timing analysis report 'build/top.tim'... failed: No space left on device
icepack: can't open build/top.config for writing: No space left on device
write error: No space left on device先看报错路径落在哪:写 build/ 失败是工程分区的事;写到一半 tools 自己崩了、报的是系统路径,那是 /tmp 的事。还有一种隐蔽形态:流程「正常结束」但 .asc 只有正常大小的一半——那是写盘被截断,比特流烧进去必然不工作。烧录前瞄一眼产物大小是和平时同量级,是最便宜的完整性检查。
二、可能原因总览
| 报错/现象 | 可能原因 | 处置 |
|---|---|---|
| build/ 写失败 | 工程分区满 | du 找大户,清旧构建目录 |
| 系统路径写失败 | /tmp 小分区被占满 | 清临时文件或改 TMPDIR |
| 每轮回归磁盘涨一截 | 每轮新建 build 目录从不删 | 保留最近 N 轮,旧的整目录删 |
| .asc 只有半截 | 写盘过程中分区被打满 | 清盘后重跑,烧录前校验产物大小 |
| 日志越滚越大 | 回归日志无轮转无压缩 | 按天轮转 + gzip 归档 |
| du 与 df 对不上 | 已删文件仍被进程占用 | lsof 查僵尸句柄,重启进程 |
| 个人报错、分区有余 | 用户 quota 打满 | quota -s 自查,清理或申请提额 |
| 空间有余写不进 | inode 耗尽 | df -i 确认,清海量小文件 |
三、逐条排查展开
先清出喘息空间再排查。 磁盘 100% 时连 shell 的历史文件都写不进去,编辑器也开不了临时文件。先删一个确定无用的旧构建目录或压缩一个大日志,腾出几百 MB 再开始系统排查,不要在满盘状态下跑任何会写盘的命令。
两条命令定位「哪个分区、谁占的」。
df -h . # 当前目录所在分区占用率
du -sh */ | sort -rh | head # 当前目录下谁最大df -h 输出里 Use% 到顶的那行就是出事分区,进去逐层 du -sh 下钻。FPGA 开源流程的大户很固定:历轮 build/ 目录(每轮完整保存 .json 网表、.asc、.config、时序报告,ECP5 大器件一轮上百 MB 不稀奇)、累积的回归日志、仿真留下的 VCD 波形(这个经常比比特流大几个数量级)。
构建目录轮转写进脚本。 回归脚本每轮新建 build_20261024/、build_20261025/ 而不删旧的,一周就把盘吃满。处置:脚本里写死只保留最近 N 轮(N 取 3 到 5,够回溯对比一次即可),更旧的整目录删除。删之前 lsof +D <目录> 确认没有进程还开着它。中间产物里 .json 网表通常最大且可重生(从 RTL 重新综合就是),.config 比特流是必须留的交付物,取舍时先删可再生的。
日志限额与压缩。 单次 nextpnr 全程日志几 MB 起步,天天跑不轮转,日志目录自己长成大户。两条线:单次日志按大小设上限并告警;历史日志按天轮转、gzip 压缩后限期保留。Makefile 里把 nextpnr-ice40 ... | tee build/route.log 的输出统一落到带日期戳的目录,轮转脚本才好按目录清理。
/tmp 满了可以绕开。 共享构建机的 /tmp 是公用的,且经常只有几个 G。把临时目录指到工程盘:
export TMPDIR=<工程盘>/.tmp/$USER
mkdir -p "$TMPDIR"工具链的中间临时文件都尊重 TMPDIR,既不用和别人抢 /tmp,自己的临时文件也好清理。
「删了空间没回来」查僵尸句柄。 df 满、du 算不出那么大——经典场景是有人 rm 了一个还被进程打开写的大日志。lsof +L1 列出已删除但仍被占用的文件,找到进程优雅重启即可释放,别再 rm 一遍。
quota 与 inode 两种假满。 分区明明还有几百 G 却报 No space left:quota -s 查个人配额;空间有余但写不进任何新文件:df -i 查 inode 是否被海量小文件耗尽(逐测试点的报告目录是重灾区),处置是删过期小文件或打包归档。
CI 场景还有一类「慢性满」。 定时任务每天跑回归,磁盘曲线是锯齿式缓慢爬升,平时看一直在 80% 上下,某天设计规模涨了一档、单轮产物变大,锯齿的谷底也顶到了 100%。所以清理纪律不能只看「当前满不满」,要每周看一次趋势:如果谷底每周都在抬高,说明清理策略追不上产物增长,要么缩短保留轮数,要么扩容。把磁盘使用率纳入和回归结果同一张报表,是比任何单点排查都划算的保险。
产物清单先分清「可再生」与「交付物」。 清理时最大的心理障碍是「这个文件以后还要不要」。一条简单的判据:从源码一条命令能重新生成的(JSON 网表、asc、时序报告)都是可再生的,删了不心疼;比特流 config、签发的版本记录、与客户现场对应的归档是交付物,进长期归档目录不动。构建脚本里把两类产物分目录落盘,清理脚本只碰可再生目录,误判风险就降到了零。
四、清理与限额流程
读这张图抓住两个时间尺度:红蓝橙绿这条竖线是「今晚救活 CI」的应急动作,紫色节点是「以后不再被叫醒」的常态机制。只做完应急不做紫色那步,同一个故障每月重演一次。
五、预防与纪律
- 构建目录自带轮转:每轮结束自动删第 N+1 轮之前的 build 目录,N 写死在脚本配置里。
- TMPDIR 指到工程盘:不依赖 /tmp 余量,CI 作业脚本第一行就设。
- 日志大小与天数双限额:单文件超限告警,历史日志压缩归档限期保留。
- VCD 波形限期死亡:调试用波形标注保留期,到期脚本自动删——波形是用一次就该走的数据。
- 85% 告警线:分区使用率到 85% 就通知责任人,把「写满报错」变成「提前收到通知」。
- 烧录前校验产物大小:
.asc/.config与历史正常值同量级才允许烧板,挡住半截文件。
这一篇在知识体系里的位置
本篇是 FPGA 开源工具链排错簇中「磁盘资源」节点的 FAQ 页:与 yosys 磁盘写满(综合阶段同型问题)、nextpnr 资源耗尽(内存/句柄侧)、nextpnr 权限被拒(能写但没权限)互补,三者覆盖「没空间 / 没资源 / 没权限」三类环境级写失败;路径类相邻问题见 nextpnr 路径/文件不存在,系列总览见 FPGA 知识版图。
一句话总结
nextpnr 磁盘写满先 df -h 定位满的分区、du -sh 下钻抓大户,然后按类处置:旧 build 目录保留最近 N 轮、日志轮转压缩、VCD 波形限期删除、TMPDIR 指工程盘自管目录;du 与 df 对不上查 lsof +L1,分区有余个人报错查 quota -s,空间有余写不进查 df -i;最后把「保留 N 轮 + 85% 告警线 + 烧录前校验产物大小」写进回归脚本,让磁盘写满从半夜故障变成提前通知。