From: Niu Yawei Date: Fri, 1 Jun 2012 06:28:45 +0000 (-0700) Subject: LU-1438 quota: fix race in quota_chk_acq_common() X-Git-Tag: 2.1.4-RC1~45 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=5588c6dd280355f47003c34f6f4e34eae4b577b5;p=fs%2Flustre-release.git 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: Ia8c5cb593abf515cf4dc041c63c8a247ebe0cd03 Reviewed-on: http://review.whamcloud.com/2996 Reviewed-by: Johann Lombardi Reviewed-by: Fan Yong Tested-by: Hudson Tested-by: Maloo Reviewed-by: Oleg Drokin --- diff --git a/lustre/quota/quota_context.c b/lustre/quota/quota_context.c index 499cb84..0eb9330 100644 --- a/lustre/quota/quota_context.c +++ b/lustre/quota/quota_context.c @@ -1228,8 +1228,31 @@ qctxt_adjust_qunit(struct obd_device *obd, struct lustre_quota_ctxt *qctxt, struct qunit_data qdata[MAXQUOTAS]; ENTRY; - if (quota_is_set(obd, id, isblk ? QB_SET : QI_SET) == 0) - RETURN(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, id, isblk ? QB_SET : QI_SET) == 0) + RETURN(0); for (i = 0; i < MAXQUOTAS; i++) { qdata[i].qd_id = id[i];