是,硬配额超限时会直接拒绝写入,write()或creat()等系统调用返回-1并置errno为EDQUOT,前提是文件系统已正确启用配额(挂载含usrquota/grpquota、运行quotacheck和quotaon)。

硬配额超限会直接拒绝写入吗
硬配额(hard quota)触发时,write() 或 creat() 等系统调用会返回 -1,errno 设为 EDQUOT。这不是内核“悄悄截断”,而是明确拒绝——但前提是文件系统已启用配额且用户/组配额项处于激活状态。常见误区是以为只要 setquota 过就生效,实际还需:
• 挂载时带 usrquota/grpquota 选项
• 运行 quotacheck -u -g /mount/point 生成 aquota.user 和 aquota.group
• 执行 quotaon /mount/point
缺任一环,EDQUOT 都不会出现,写入照常成功。
如何在应用层提前检查软配额余量
不能依赖 EDQUOT 做软配额(soft quota)预警,因为软配额允许临时超额(在宽限期 grace period 内)。正确做法是调用 getquota()(需链接 -lquota)主动查询:
• 传入 QFMT_VFS_OLD 或 QFMT_VFS_V0 格式标识
• id 填用户 UID 或 GID,type 选 USRQUOTA/GRPQUOTA
• 返回的 struct dqblk 中:dqb_bhardlimit 和 dqb_bsoftlimit 单位是 KB,dqb_curspace 是当前已用字节数
• 判断是否即将超软限:若 dqb_curspace + expected_bytes > dqb_bsoftlimit * 1024,且 dqb_btime 非零(说明已在宽限期内),就要告警
为什么 getquota() 在容器里常返回 ENOSYS
容器默认不暴露配额接口给用户态。getquota() 底层走的是 QCMD(Q_GETQUOTA, ...) ioctl,而该 ioctl 仅对挂载点的根目录 fd 有效,且要求调用进程有 CAP_SYS_ADMIN 或在 init 命名空间中。典型失败场景:
• Docker 容器未加 --cap-add=SYS_ADMIN
• rootfs 是 overlayfs,而配额只在下层 ext4/xfs 物理分区上启用
• 使用了 userns-remap,导致 UID 映射后查不到对应配额项
替代方案是读取 /proc/mounts 找出真实块设备,再尝试 open 对应 /dev/sdX(需权限)或解析 /sys/fs/ext4/*/stats(ext4 专用,不稳定)
自定义配额检查服务要注意的边界
如果绕过内核配额、自己实现逻辑(如基于 inotify + stat 聚合),关键陷阱在:
• 不处理硬链接:同一 inode 多次统计会虚高用量
• 忽略交换文件(swapon 创建的)和设备文件(mknod),它们不计入 st_blocks
• st_blocks * 512 计算磁盘占用,但 XFS 的延迟分配(delayed allocation)会导致 st_blocks 滞后于实际写入
• 用户删除文件但进程仍 hold fd 时,空间未释放,但 stat 已不可见——必须结合 /proc/PID/fd/ 扫描
立即学习“C++免费学习笔记(深入)”;



















