Whamcloud - gitweb
LU-15191 quota: set correct revoke_time
authorSergey Cheremencev <sergey.cheremencev@hpe.com>
Tue, 12 Oct 2021 15:21:49 +0000 (18:21 +0300)
committerAndreas Dilger <adilger@whamcloud.com>
Wed, 16 Mar 2022 23:49:13 +0000 (23:49 +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.

Lustre-change: https://review.whamcloud.com/45447
Lustre-commit: e8ecb8775389fb7febd2d0c659f0e80440f0b620

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-by: Andriy Skulysh <andriy.skulysh@hpe.com>
Reviewed-on: https://review.whamcloud.com/46790
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
lustre/quota/qmt_entry.c

index 8392c64..3ed5b92 100644 (file)
@@ -653,6 +653,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.
@@ -772,10 +799,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);
 }