Subject: | quota block count truncation |
There's a small bug in the Perl Quota module that truncates the number
of blocks to 32-bits, meaning that really big quotas (eg. 15 TB), don't
show up correctly. This is related to a patch in the rquotad server
available in CVS (committed 14 Dec 2009) at
http://sourceforge.net/projects/linuxquota/. My co-worker has been
working with the developer there (jkar8572). Basically, we want to have
15 TB (15*2^40 byte) quotas, but using the standard 1kB (2^10 byte)
block size, that overflows the 32-bit integer for the number of blocks.
With the help of that developer, we made it start using a 1 MB block
size (2^20 byte), which means we only have 15*2^20 blocks (was 15*2^30
blocks), which fits.
I'm running on an x86_64 CentOS Linux 5.3 machine with Perl v5.8.8
(stock), quota-tools v3.13 (also stock), and the Perl Quota module
v1.6.3 (not stock). In the Quota.xs file, we have things like this:
dqp->QS_BHARD = gq_rslt.GQR_RQUOTA.rq_bhardlimit * qb_fac;
The "dqp->QS_BHARD" is 64-bit on this system, but
"gq_rslt.GQR_RQUOTA.rq_bhardlimit" and "qb_fac" are both 32-bit. The
individual values both fit inside a 32-bit integer, but the product
doesn't. Therefore, I'm simply casting them to qsize_t, before the
multiplication, like this:
dqp->QS_BHARD = (qsize_t)gq_rslt.GQR_RQUOTA.rq_bhardlimit * (qsize_t)qb_fac;
I'm sure this is a very messy patch, and not very portable across
architectures, OSs, etc. I'm honestly not certain of the implications
in the wider scope.
I can help test if need be. Just let me know.
Lloyd Brown
Subject: | Perl_Quota_overflow.patch |
--- Quota-1.6.3/Quota.xs 2008-12-21 05:05:53.000000000 -0700
+++ Quota-1.6.3.patched/Quota.xs 2009-12-15 15:04:02.659000000 -0700
@@ -193,9 +193,9 @@
/* we rely on the fact that block sizes are always powers of 2 */
/* so the conversion factor will never be a fraction */
int qb_fac = gq_rslt.GQR_RQUOTA.rq_bsize / DEV_QBSIZE;
- dqp->QS_BHARD = gq_rslt.GQR_RQUOTA.rq_bhardlimit * qb_fac;
- dqp->QS_BSOFT = gq_rslt.GQR_RQUOTA.rq_bsoftlimit * qb_fac;
- dqp->QS_BCUR = gq_rslt.GQR_RQUOTA.rq_curblocks * qb_fac;
+ dqp->QS_BHARD = (qsize_t)gq_rslt.GQR_RQUOTA.rq_bhardlimit * (qsize_t)qb_fac;
+ dqp->QS_BSOFT = (qsize_t)gq_rslt.GQR_RQUOTA.rq_bsoftlimit * (qsize_t)qb_fac;
+ dqp->QS_BCUR = (qsize_t)gq_rslt.GQR_RQUOTA.rq_curblocks * (qsize_t)qb_fac;
}
else {
int qb_fac = DEV_QBSIZE / gq_rslt.GQR_RQUOTA.rq_bsize;