From 423bfd10973c4adf18a68f9a8e11f934da6394e0 Mon Sep 17 00:00:00 2001 From: Niu Yawei Date: Mon, 28 May 2012 02:12:08 -0700 Subject: [PATCH] LU-1438 quota: fix race in quota_chk_acq_common() quota_check_common() & qctxt_adjust_qunit() uses different way to check if quota is enforced on certain ID, which could result in infinite loop in quota_chk_acq_common() when the QB/QI_SET flag is cleared just after checking. This patch used a non-instrusive way to fix this rare race. Signed-off-by: Niu Yawei Change-Id: I7212e9fc85e98a40e36d2773c02f838ca68339bb Reviewed-on: http://review.whamcloud.com/2927 Tested-by: Hudson Tested-by: Maloo Reviewed-by: Johann Lombardi --- lustre/quota/quota_context.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lustre/quota/quota_context.c b/lustre/quota/quota_context.c index 255dbd0..12fb024 100644 --- a/lustre/quota/quota_context.c +++ b/lustre/quota/quota_context.c @@ -1132,7 +1132,31 @@ qctxt_adjust_qunit(struct obd_device *obd, struct lustre_quota_ctxt *qctxt, struct qunit_data qdata[MAXQUOTAS]; ENTRY; - if (quota_is_set(obd, uid, gid, isblk ? QB_SET : QI_SET) == 0) + /* XXX In quota_chk_acq_common(), we do something like: + * + * while (quota_check_common() & QUOTA_RET_ACQUOTA) { + * rc = qctxt_adjust_qunit(); + * } + * + * to make sure the slave acquired enough quota from master. + * + * Unfortunately, qctxt_adjust_qunit() checks QB/QI_SET to + * decide if do real DQACQ or not, but quota_check_common() + * doesn't check QB/QI_SET flags. This inconsistence could + * lead into an infinite loop. + * + * We can't fix it by simply adding QB/QI_SET checking in the + * quota_check_common(), since we must guarantee that the + * paried quota_pending_commit() has same QB/QI_SET, but the + * flags can be actually cleared at any time... + * + * A quick non-intrusive solution is to just skip the + * QB/QI_SET checking here when the @wait is non-zero. + * (If the @wait is non-zero, the caller must have already + * checked the QB/QI_SET). + */ + if (!wait && + quota_is_set(obd, uid, gid, isblk ? QB_SET : QI_SET) == 0) RETURN(0); for (i = 0; i < MAXQUOTAS; i++) { -- 1.8.3.1