summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Písař <ppisar@redhat.com>2011-01-06 17:59:27 +0100
committerJan Kara <jack@suse.cz>2011-10-04 22:10:32 +0200
commitfef44fb2d924c6249a8aadfe7cf5e1093ebd2e43 (patch)
treec867d162f8c87e6961204401b0b338a03891930a
parent803a300b63cc9065818354c1d11a8125dbbdb571 (diff)
downloadlinuxquota-fef44fb2d924c6249a8aadfe7cf5e1093ebd2e43.tar.gz
Make RPC block factor dynamic
Former static factor (RPC_DQBLK_SIZE_BITS) had problem to carry values bigger than hard-coded limit (2^(32 + RPC_DQBLK_SIZE_BITS) - 1). This patch makes the factor dynamic. It selects best value to prevent overflow (XDR has 32b variables, some file system support 64b quotas) and to achieve highest possible precision. The client site uses the factor carried via RPC correctly. There is similar problem with setquota. This patch does not address it, however it can be easily resused and fixed. Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--rquota_server.c33
1 files changed, 28 insertions, 5 deletions
diff --git a/rquota_server.c b/rquota_server.c
index 0e83689..3293de7 100644
--- a/rquota_server.c
+++ b/rquota_server.c
@@ -91,17 +91,41 @@ static inline void servnet2utildqblk(struct util_dqblk *u, sq_dqblk * n)
u->dqb_itime = 0;
}
+/* XDR transports 32b variables exactly. Find smallest needed shift to fit
+ * 64b variable into into 32 bits and to preserve precision as high as
+ * possible. */
+static int find_block_shift(qsize_t hard, qsize_t soft, qsize_t cur)
+{
+ int shift;
+ qsize_t value = hard;
+
+ if (value < soft)
+ value = soft;
+ if (value < cur)
+ value = cur;
+ value >>= 32 + QUOTABLOCK_BITS;
+ for (shift = QUOTABLOCK_BITS; value; shift++)
+ value >>= 1;
+
+ return shift;
+}
+
static inline void servutil2netdqblk(struct rquota *n, struct util_dqblk *u)
{
time_t now;
+ int shift;
- time(&now);
- n->rq_bhardlimit = (u->dqb_bhardlimit << QUOTABLOCK_BITS) >> RPC_DQBLK_SIZE_BITS;
- n->rq_bsoftlimit = (u->dqb_bsoftlimit << QUOTABLOCK_BITS) >> RPC_DQBLK_SIZE_BITS;
+ shift = find_block_shift(u->dqb_bhardlimit, u->dqb_bsoftlimit,
+ u->dqb_curspace);
+ n->rq_bsize = 1 << shift;
+ n->rq_bhardlimit = (u->dqb_bhardlimit << QUOTABLOCK_BITS) >> shift;
+ n->rq_bsoftlimit = (u->dqb_bsoftlimit << QUOTABLOCK_BITS) >> shift;
n->rq_fhardlimit = u->dqb_ihardlimit;
n->rq_fsoftlimit = u->dqb_isoftlimit;
- n->rq_curblocks = (u->dqb_curspace + RPC_DQBLK_SIZE - 1) >> RPC_DQBLK_SIZE_BITS;
+ n->rq_curblocks = (u->dqb_curspace + n->rq_bsize - 1) >> shift;
n->rq_curfiles = u->dqb_curinodes;
+
+ time(&now);
if (u->dqb_btime)
n->rq_btimeleft = u->dqb_btime - now;
else
@@ -258,7 +282,6 @@ getquota_rslt *getquotainfo(int lflags, caddr_t * argp, struct svc_req * rqstp)
}
result.status = Q_NOQUOTA;
- result.getquota_rslt_u.gqr_rquota.rq_bsize = RPC_DQBLK_SIZE;
if (init_mounts_scan(1, &pathp, MS_QUIET | MS_NO_MNTPOINT | MS_NFS_ALL | ((flags & FL_AUTOFS) ? 0 : MS_NO_AUTOFS)) < 0)
goto out;