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