xfs下限制单个目录大小必须使用project配额,因其基于目录树的projectid属性强制统计和限制,而user/group配额按uid/gid计费、不绑定路径,无法实现目录级隔离。

直接说结论:XFS 下限制单个目录大小,必须用 project 配额,不能用 user 或 group 配额 —— 因为后者作用对象是用户/组,不是路径。
为什么 xfs_quota -u 对目录无效
很多人试过 xfs_quota -x -c 'limit -u bhard=10g username' /mnt,发现改了配额但往 /mnt/subdir 写文件完全不受限。这是因为 -u 是按 UID 统计写入行为,只要该用户在挂载点下任意位置写入,都算进配额;它不绑定到某个子目录路径。你真正想锁死的是“这个目录及其所有子目录下的总用量”,这只能靠 project 实现。
-
-u/-g配额依赖用户登录、进程 UID/GID,对 daemon 进程或 root 操作容易绕过 -
project配额基于目录树的 inode 扩展属性(projectid),内核在每次 write 时强制检查路径归属,更可靠 - 同一个挂载点上,
user、group、project配额不能混用 —— XFS 只允许启用其中一种类型(见mount输出里的prjquota/usrquota)
prjquota 挂载参数和 /etc/projects 必须配对
只加 prjquota 到 /etc/fstab 不够,还必须让内核知道“哪个 project ID 对应哪个目录”。否则 xfs_quota -c 'project -s' /path 会报 cannot set project ID: No such file or directory。
- 编辑
/etc/projects:每行格式为ID:PATH,例如101:/data/app1(注意路径必须是挂载点下的绝对路径,且已存在) - 编辑
/etc/projid:定义项目别名,例如app1:101,方便后续命令用名字而非数字 - 运行
xfs_quota -x -c 'project -s app1' /data—— 这步会扫描/data/app1下所有文件并打上projectid=101标签(耗时取决于目录大小) - 若跳过
-s直接limit,新写入文件会被标记,但已有文件不算配额,导致“看似没生效”
limit -p 设置后立即生效,但 report 要等延迟更新
执行 xfs_quota -x -c 'limit -p bhard=5g app1' /data 后,超出限制的 write 系统调用会立刻返回 EDQUOT 错误(应用层表现为“磁盘空间不足”)。但 xfs_quota -c 'report -h' /data 显示的用量可能滞后几秒到几十秒 —— 这是 XFS 的配额统计异步刷新机制导致的,并非配置失败。
- 强制刷新统计:运行
xfs_quota -x -c 'sync' /data(仅影响统计缓存,不影响配额 enforcement) - 查精确当前用量:用
xfs_quota -c 'quota -p app1' /data,它读取实时的 projectid 统计,比report更准 - 硬限制触发后,连
rm都可能失败(因为 unlink 也需要写日志),此时需先腾出空间再操作
常见错误:挂载选项写错、权限未同步、SELinux 干扰
最常卡住的三个点:
-
/etc/fstab中写成usrquota或漏掉prjquota(XFS 下必须用prjquota,usrquota是 ext4 的) - 修改
/etc/fstab后只mount -o remount,但旧挂载没卸载干净,导致mount | grep仍显示noquota—— 正确做法是umount /data && mount /data - SELinux 开启时,
xfs_quota命令可能被阻止读取/etc/projects,临时验证可setenforce 0,长期方案是修复上下文:restorecon -v /etc/projects /etc/projid
project 配额真正的复杂点在于:它把目录当“容器”来管,但这个容器的边界由内核通过 projectid 属性维护,不是靠路径字符串匹配。一旦 project -s 扫描完成,mv 文件进出该目录都会自动更新统计 —— 这个自动性很省心,但出问题时也最难 debug,因为看不到中间状态。











