summaryrefslogtreecommitdiff
path: root/rquota_server.c
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 /rquota_server.c
parent803a300b63cc9065818354c1d11a8125dbbdb571 (diff)
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>
Diffstat (limited to 'rquota_server.c')
-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;