From e8ecb8775389fb7febd2d0c659f0e80440f0b620 Mon Sep 17 00:00:00 2001 From: Sergey Cheremencev Date: Tue, 12 Oct 2021 18:21:49 +0300 Subject: [PATCH] LU-15191 quota: set correct revoke_time When we do qmt_adjust_qunit, there are several lqes and lqe_revoke_time is set for some of them, it means appropriate OSTs have been already notified with the least qunit and there is no chance to free more space. If a qunit of the current lqe becomes equal to the least qunit, find an lqe with the minimum(earliest) revoke_time and set this revoke_time to the current one. This patch fixes the following case. For example, we have 8 OSTs and 4 MDTs(i.e. 12 slaves) and a pool with just one OST. Global hard block limit for the user is 50M, and 10M for this user in a pool. User's usage is 0. As global pool has 12 slaves it's initial qunit value is 1M, i.e. equal to the least qunit. At the same time initial qunit value for the pool with one OST is 4M. When user begins to write, pool's qunit is decreased to 1M, but lqe_revoke is not set - it should be set only after sending new qunit to OSTs in qmt_lvbo_update. However, it won't be send because appropriate lge_qunit in lqe global array already has the same value. This problem caused sanity-quota_72 to hang instead of fail with EDQUOT in test_1_check_write. HPE-bug-id: LUS-10516 Change-Id: I5878c1e719ae83a69ad5dbc3653717bb1b4de632 Reviewed-by: Andriy Skulysh Reviewed-by: Alexander Boyko Tested-by: Elena Gryaznova Signed-off-by: Sergey Cheremencev Reviewed-on: https://review.whamcloud.com/45447 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Andriy Skulysh Reviewed-by: Oleg Drokin --- lustre/quota/qmt_entry.c | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/lustre/quota/qmt_entry.c b/lustre/quota/qmt_entry.c index da525a5..387806b 100644 --- a/lustre/quota/qmt_entry.c +++ b/lustre/quota/qmt_entry.c @@ -652,6 +652,33 @@ __u64 qmt_alloc_expand(struct lquota_entry *lqe, __u64 granted, __u64 spare) RETURN(0); } +static inline void +qmt_adjust_qunit_set_revoke(const struct lu_env *env, struct lquota_entry *lqe, + unsigned long least_qunit) +{ + struct lquota_entry *lqe2; + time64_t min = 0; + int i; + + if (qti_lqes_cnt(env) <= 1) + return; + + for (i = 0; i < qti_lqes_cnt(env); i++) { + lqe2 = qti_lqes(env)[i]; + if ((lqe2->lqe_qunit == least_qunit) && lqe2->lqe_revoke_time) { + if (!min) { + min = lqe2->lqe_revoke_time; + continue; + } + min = lqe2->lqe_revoke_time < min ? + lqe2->lqe_revoke_time : min; + } + } + + lqe->lqe_revoke_time = min; +} + + /* * Adjust qunit size according to quota limits and total granted count. * The caller must have locked the lqe. @@ -771,10 +798,17 @@ done: /* reset revoke time */ lqe->lqe_revoke_time = 0; - if (lqe->lqe_qunit >= qunit && - (lqe->lqe_qunit == pool->qpi_least_qunit)) { - /* initial qunit value is the smallest one */ - lqe->lqe_revoke_time = ktime_get_seconds(); + if (lqe->lqe_qunit == pool->qpi_least_qunit) { + if (lqe->lqe_qunit >= qunit) + /* initial qunit value is the smallest one */ + lqe->lqe_revoke_time = ktime_get_seconds(); + /* If there are several lqes and lqe_revoke_time is set for + * some of them, it means appropriate OSTs have been already + * notified with the least qunit and there is no chance to + * free more space. Find an lqe with the minimum(earliest) + * revoke_time and set this time to the current one. + */ + qmt_adjust_qunit_set_revoke(env, lqe, pool->qpi_least_qunit); } RETURN(need_reseed); } -- 1.8.3.1