Whamcloud - gitweb
LU-15191 quota: set correct revoke_time 47/45447/4
authorSergey Cheremencev <sergey.cheremencev@hpe.com>
Tue, 12 Oct 2021 15:21:49 +0000 (18:21 +0300)
committerOleg Drokin <green@whamcloud.com>
Tue, 30 Nov 2021 03:45:13 +0000 (03:45 +0000)
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 <c17819@cray.com>
Reviewed-by: Alexander Boyko <alexander.boyko@hpe.com>
Tested-by: Elena Gryaznova <c17455@cray.com>
Signed-off-by: Sergey Cheremencev <sergey.cheremencev@hpe.com>
Reviewed-on: https://review.whamcloud.com/45447
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andriy Skulysh <andriy.skulysh@hpe.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/quota/qmt_entry.c

index da525a5..387806b 100644 (file)
@@ -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);
 }