Commit 5dd70852 authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: create quota preallocation watermarks for realtime quota



Refactor the quota preallocation watermarking code so that it'll work
for realtime quota too.  Convert the do_div calls into div_u64 for
compactness.

Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 9a17ebfe
Loading
Loading
Loading
Loading
+21 −16
Original line number Diff line number Diff line
@@ -277,6 +277,25 @@ xfs_qm_init_dquot_blk(
		xfs_trans_log_buf(tp, bp, 0, BBTOB(q->qi_dqchunklen) - 1);
}

static void
xfs_dquot_set_prealloc(
	struct xfs_dquot_pre		*pre,
	const struct xfs_dquot_res	*res)
{
	xfs_qcnt_t			space;

	pre->q_prealloc_hi_wmark = res->hardlimit;
	pre->q_prealloc_lo_wmark = res->softlimit;

	space = div_u64(pre->q_prealloc_hi_wmark, 100);
	if (!pre->q_prealloc_lo_wmark)
		pre->q_prealloc_lo_wmark = space * 95;

	pre->q_low_space[XFS_QLOWSP_1_PCNT] = space;
	pre->q_low_space[XFS_QLOWSP_3_PCNT] = space * 3;
	pre->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5;
}

/*
 * Initialize the dynamic speculative preallocation thresholds. The lo/hi
 * watermarks correspond to the soft and hard limits by default. If a soft limit
@@ -285,22 +304,8 @@ xfs_qm_init_dquot_blk(
void
xfs_dquot_set_prealloc_limits(struct xfs_dquot *dqp)
{
	uint64_t space;

	dqp->q_prealloc_hi_wmark = dqp->q_blk.hardlimit;
	dqp->q_prealloc_lo_wmark = dqp->q_blk.softlimit;
	if (!dqp->q_prealloc_lo_wmark) {
		dqp->q_prealloc_lo_wmark = dqp->q_prealloc_hi_wmark;
		do_div(dqp->q_prealloc_lo_wmark, 100);
		dqp->q_prealloc_lo_wmark *= 95;
	}

	space = dqp->q_prealloc_hi_wmark;

	do_div(space, 100);
	dqp->q_low_space[XFS_QLOWSP_1_PCNT] = space;
	dqp->q_low_space[XFS_QLOWSP_3_PCNT] = space * 3;
	dqp->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5;
	xfs_dquot_set_prealloc(&dqp->q_blk_prealloc, &dqp->q_blk);
	xfs_dquot_set_prealloc(&dqp->q_rtb_prealloc, &dqp->q_rtb);
}

/*
+14 −4
Original line number Diff line number Diff line
@@ -56,6 +56,12 @@ xfs_dquot_res_over_limits(
	return false;
}

struct xfs_dquot_pre {
	xfs_qcnt_t		q_prealloc_lo_wmark;
	xfs_qcnt_t		q_prealloc_hi_wmark;
	int64_t			q_low_space[XFS_QLOWSP_MAX];
};

/*
 * The incore dquot structure
 */
@@ -76,9 +82,9 @@ struct xfs_dquot {

	struct xfs_dq_logitem	q_logitem;

	xfs_qcnt_t		q_prealloc_lo_wmark;
	xfs_qcnt_t		q_prealloc_hi_wmark;
	int64_t			q_low_space[XFS_QLOWSP_MAX];
	struct xfs_dquot_pre	q_blk_prealloc;
	struct xfs_dquot_pre	q_rtb_prealloc;

	struct mutex		q_qlock;
	struct completion	q_flush;
	atomic_t		q_pincount;
@@ -192,7 +198,11 @@ static inline bool xfs_dquot_lowsp(struct xfs_dquot *dqp)
	int64_t freesp;

	freesp = dqp->q_blk.hardlimit - dqp->q_blk.reserved;
	if (freesp < dqp->q_low_space[XFS_QLOWSP_1_PCNT])
	if (freesp < dqp->q_blk_prealloc.q_low_space[XFS_QLOWSP_1_PCNT])
		return true;

	freesp = dqp->q_rtb.hardlimit - dqp->q_rtb.reserved;
	if (freesp < dqp->q_rtb_prealloc.q_low_space[XFS_QLOWSP_1_PCNT])
		return true;

	return false;
+30 −7
Original line number Diff line number Diff line
@@ -353,16 +353,26 @@ xfs_quota_need_throttle(
	xfs_fsblock_t		alloc_blocks)
{
	struct xfs_dquot	*dq = xfs_inode_dquot(ip, type);
	struct xfs_dquot_res	*res;
	struct xfs_dquot_pre	*pre;

	if (!dq || !xfs_this_quota_on(ip->i_mount, type))
		return false;

	if (XFS_IS_REALTIME_INODE(ip)) {
		res = &dq->q_rtb;
		pre = &dq->q_rtb_prealloc;
	} else {
		res = &dq->q_blk;
		pre = &dq->q_blk_prealloc;
	}

	/* no hi watermark, no throttle */
	if (!dq->q_prealloc_hi_wmark)
	if (!pre->q_prealloc_hi_wmark)
		return false;

	/* under the lo watermark, no throttle */
	if (dq->q_blk.reserved + alloc_blocks < dq->q_prealloc_lo_wmark)
	if (res->reserved + alloc_blocks < pre->q_prealloc_lo_wmark)
		return false;

	return true;
@@ -377,22 +387,35 @@ xfs_quota_calc_throttle(
	int64_t			*qfreesp)
{
	struct xfs_dquot	*dq = xfs_inode_dquot(ip, type);
	struct xfs_dquot_res	*res;
	struct xfs_dquot_pre	*pre;
	int64_t			freesp;
	int			shift = 0;

	if (!dq) {
		res = NULL;
		pre = NULL;
	} else if (XFS_IS_REALTIME_INODE(ip)) {
		res = &dq->q_rtb;
		pre = &dq->q_rtb_prealloc;
	} else {
		res = &dq->q_blk;
		pre = &dq->q_blk_prealloc;
	}

	/* no dq, or over hi wmark, squash the prealloc completely */
	if (!dq || dq->q_blk.reserved >= dq->q_prealloc_hi_wmark) {
	if (!res || res->reserved >= pre->q_prealloc_hi_wmark) {
		*qblocks = 0;
		*qfreesp = 0;
		return;
	}

	freesp = dq->q_prealloc_hi_wmark - dq->q_blk.reserved;
	if (freesp < dq->q_low_space[XFS_QLOWSP_5_PCNT]) {
	freesp = pre->q_prealloc_hi_wmark - res->reserved;
	if (freesp < pre->q_low_space[XFS_QLOWSP_5_PCNT]) {
		shift = 2;
		if (freesp < dq->q_low_space[XFS_QLOWSP_3_PCNT])
		if (freesp < pre->q_low_space[XFS_QLOWSP_3_PCNT])
			shift += 2;
		if (freesp < dq->q_low_space[XFS_QLOWSP_1_PCNT])
		if (freesp < pre->q_low_space[XFS_QLOWSP_1_PCNT])
			shift += 2;
	}

+16 −5
Original line number Diff line number Diff line
@@ -2178,6 +2178,8 @@ xfs_inode_near_dquot_enforcement(
	xfs_dqtype_t		type)
{
	struct xfs_dquot	*dqp;
	struct xfs_dquot_res	*res;
	struct xfs_dquot_pre	*pre;
	int64_t			freesp;

	/* We only care for quotas that are enabled and enforced. */
@@ -2186,21 +2188,30 @@ xfs_inode_near_dquot_enforcement(
		return false;

	if (xfs_dquot_res_over_limits(&dqp->q_ino) ||
	    xfs_dquot_res_over_limits(&dqp->q_blk) ||
	    xfs_dquot_res_over_limits(&dqp->q_rtb))
		return true;

	if (XFS_IS_REALTIME_INODE(ip)) {
		res = &dqp->q_rtb;
		pre = &dqp->q_rtb_prealloc;
	} else {
		res = &dqp->q_blk;
		pre = &dqp->q_blk_prealloc;
	}

	/* For space on the data device, check the various thresholds. */
	if (!dqp->q_prealloc_hi_wmark)
	if (!pre->q_prealloc_hi_wmark)
		return false;

	if (dqp->q_blk.reserved < dqp->q_prealloc_lo_wmark)
	if (res->reserved < pre->q_prealloc_lo_wmark)
		return false;

	if (dqp->q_blk.reserved >= dqp->q_prealloc_hi_wmark)
	if (res->reserved >= pre->q_prealloc_hi_wmark)
		return true;

	freesp = dqp->q_prealloc_hi_wmark - dqp->q_blk.reserved;
	if (freesp < dqp->q_low_space[XFS_QLOWSP_5_PCNT])
	freesp = pre->q_prealloc_hi_wmark - res->reserved;
	if (freesp < pre->q_low_space[XFS_QLOWSP_5_PCNT])
		return true;

	return false;