Kernel quotactl() interface uses u_uit64_t to transfer block usage etc. However quota tools use qsize_t which is a int64_t.
When I hit a bug in GFS2 kernel driver, I got a very high number of block usage from the kernel. But when storing the value into quota tools structures, the value overflows. The quotaio_xfs.c:xfs_kern2utildqblk() does arithmetic without checking ranges:
static inline void xfs_kern2utildqblk(struct util_dqblk *u, struct xfs_kern_dqblk * k) { u->dqb_ihardlimit = k->d_ino_hardlimit; u->dqb_isoftlimit = k->d_ino_softlimit; u->dqb_bhardlimit = k->d_blk_hardlimit >> 1; u->dqb_bsoftlimit = k->d_blk_softlimit >> 1; u->dqb_curinodes = k->d_icount; u->dqb_curspace = ((qsize_t)k->d_bcount) << 9; u->dqb_itime = k->d_itimer; u->dqb_btime = k->d_btimer; }
Before I will try to implement necessary checks, I have a question: Why qsize_t is signed? Is it safe to change the typedef to u_int64_t? Various printf's format the value using %llu.
Anonymous
qsize_t is signed in kernel, because cluster filesystems (such as GFS2 or OCFS2) can temporarily show negative quota usage because quota usage accounting isn't completely synchronized between nodes (this happens for example when you allocate files on one node and delete them on another node).
So I think it is better to keep qsize_t signed and a check to xfs_kern2utildqblk().
OK, I made quota tools treat return used space and inodes as signed values.