619d78
From 7e1c5c8074e5d83cfda5b66140c177954b836118 Mon Sep 17 00:00:00 2001
619d78
From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= <ppisar@redhat.com>
619d78
Date: Thu, 6 Jan 2011 17:59:27 +0100
619d78
Subject: [PATCH] Make RPC block factor dynamic
619d78
619d78
Former static factor (RPC_DQBLK_SIZE_BITS) had problem to carry values
619d78
bigger than hard-coded limit (2^(32 + RPC_DQBLK_SIZE_BITS) - 1).
619d78
619d78
This patch makes the factor dynamic. It selects best value to prevent
619d78
overflow (XDR has 32b variables, some file system support 64b quotas)
619d78
and to achieve highest possible precision.
619d78
619d78
The client site uses the factor carried via RPC correctly.
619d78
619d78
There is similar problem with setquota. This patch does not address it,
619d78
however it can be easily resused and fixed.
619d78
---
619d78
 rquota_server.c |   34 +++++++++++++++++++++++++++++-----
619d78
 1 files changed, 29 insertions(+), 5 deletions(-)
619d78
619d78
diff --git a/rquota_server.c b/rquota_server.c
619d78
index 0e83689..cff6191 100644
619d78
--- a/rquota_server.c
619d78
+++ b/rquota_server.c
619d78
@@ -91,17 +91,42 @@ static inline void servnet2utildqblk(struct util_dqblk *u, sq_dqblk * n)
619d78
 		u->dqb_itime = 0;
619d78
 }
619d78
 
619d78
+/* XDR transports 32b variables exactly. Find smallest needed shift to fit
619d78
+ * 64b variable into into 32 bits and to preserve precision as high as
619d78
+ * possible. */
619d78
+static int find_block_shift(qsize_t hard, qsize_t soft, qsize_t cur)
619d78
+{
619d78
+	int shift;
619d78
+	qsize_t value;
619d78
+    
619d78
+	value = (hard > soft) ? hard : soft;
619d78
+	for (shift = QUOTABLOCK_BITS; value; shift++) value >>= 1;
619d78
+
619d78
+	cur >>= shift;
619d78
+	for (; cur; shift++) cur >>= 1;
619d78
+
619d78
+	shift -= 32;
619d78
+	if (shift < 0) shift = 0;
619d78
+
619d78
+	return shift;
619d78
+}
619d78
+
619d78
 static inline void servutil2netdqblk(struct rquota *n, struct util_dqblk *u)
619d78
 {
619d78
 	time_t now;
619d78
+	int shift;
619d78
 
619d78
-	time(&now);
619d78
-	n->rq_bhardlimit = (u->dqb_bhardlimit << QUOTABLOCK_BITS) >> RPC_DQBLK_SIZE_BITS;
619d78
-	n->rq_bsoftlimit = (u->dqb_bsoftlimit << QUOTABLOCK_BITS) >> RPC_DQBLK_SIZE_BITS;
619d78
+	shift = find_block_shift(u->dqb_bhardlimit, u->dqb_bsoftlimit,
619d78
+		u->dqb_curspace);
619d78
+	n->rq_bsize = 1 << shift;
619d78
+	n->rq_bhardlimit = (u->dqb_bhardlimit << QUOTABLOCK_BITS) >> shift;
619d78
+	n->rq_bsoftlimit = (u->dqb_bsoftlimit << QUOTABLOCK_BITS) >> shift;
619d78
 	n->rq_fhardlimit = u->dqb_ihardlimit;
619d78
 	n->rq_fsoftlimit = u->dqb_isoftlimit;
619d78
-	n->rq_curblocks = (u->dqb_curspace + RPC_DQBLK_SIZE - 1) >> RPC_DQBLK_SIZE_BITS;
619d78
+	n->rq_curblocks = (u->dqb_curspace + n->rq_bsize - 1) >> shift;
619d78
 	n->rq_curfiles = u->dqb_curinodes;
619d78
+
619d78
+	time(&now);
619d78
 	if (u->dqb_btime)
619d78
 		n->rq_btimeleft = u->dqb_btime - now;
619d78
 	else
619d78
@@ -258,7 +283,6 @@ getquota_rslt *getquotainfo(int lflags, caddr_t * argp, struct svc_req * rqstp)
619d78
 	}
619d78
 
619d78
 	result.status = Q_NOQUOTA;
619d78
-	result.getquota_rslt_u.gqr_rquota.rq_bsize = RPC_DQBLK_SIZE;
619d78
 
619d78
 	if (init_mounts_scan(1, &pathp, MS_QUIET | MS_NO_MNTPOINT | MS_NFS_ALL | ((flags & FL_AUTOFS) ? 0 : MS_NO_AUTOFS)) < 0)
619d78
 		goto out;
619d78
-- 
619d78
1.7.3.4
619d78