Whamcloud - gitweb
LU-15263 quota: fix bug in qmt_pool_recalc 32/45632/2
authorSergey Cheremencev <sergey.cheremencev@hpe.com>
Thu, 21 Oct 2021 20:28:01 +0000 (23:28 +0300)
committerOleg Drokin <green@whamcloud.com>
Mon, 13 Dec 2021 03:55:43 +0000 (03:55 +0000)
env should be freed at the end of qmt_pool_recalc,
as it is needed in qpi_putref. It causes a panic,
if pool has the last reference:
BUG: unable to handle kernel NULL pointer dereference at 00000000000000a0
IP: [<ffffffffc08de2d7>] lu_context_key_get+0x17/0x30 [obdclass]
...
Call Trace:
 [<ffffffffc08de358>] lu_object_free.isra.30+0x68/0x170 [obdclass]
 [<ffffffffc08e1a35>] lu_object_put+0xc5/0x3e0 [obdclass]
 [<ffffffffc100e56c>] qmt_pool_free+0x30c/0x590 [lquota]
 [<ffffffffc10100b5>] qmt_pool_recalc+0x365/0x1260 [lquota]
 [<ffffffff8bac1c31>] kthread+0xd1/0xe0
 [<ffffffff8c176c37>] ret_from_fork_nospec_begin+0x21/0x21

HPE-bug-id: LUS-10426
Change-Id: Ic23dcb858ff811757f38948aa572c936c076e21e
Signed-off-by: Sergey Cheremencev <sergey.cheremencev@hpe.com>
Reviewed-by: Vladimir Saveliev <vlaidimir.saveliev@hpe.com>
Reviewed-by: Andriy Skulysh <c17819@cray.com>
Reviewed-on: https://review.whamcloud.com/45632
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Andriy Skulysh <andriy.skulysh@hpe.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/quota/qmt_pool.c

index 37bb488..7bb1ee3 100644 (file)
@@ -1155,6 +1155,13 @@ static int qmt_pool_recalc(void *args)
 
        pool = args;
 
+       rc = lu_env_init(&env, LCT_MD_THREAD);
+       if (rc) {
+               CERROR("%s: cannot init env: rc = %d\n",
+                      pool->qpi_qmt->qmt_svname, rc);
+               GOTO(out, rc);
+       }
+
        obd = qmt_get_mgc(pool->qpi_qmt);
        if (IS_ERR(obd))
                GOTO(out, rc = PTR_ERR(obd));
@@ -1183,15 +1190,9 @@ static int qmt_pool_recalc(void *args)
         * solution looks more complex, so leave it as it is. */
        down_write(&pool->qpi_recalc_sem);
 
-       rc = lu_env_init(&env, LCT_MD_THREAD);
-       if (rc) {
-               CERROR("%s: cannot init env: rc = %d\n", obd->obd_name, rc);
-               GOTO(out, rc);
-       }
-
        glbl_pool = qmt_pool_lookup_glb(&env, pool->qpi_qmt, pool->qpi_rtype);
        if (IS_ERR(glbl_pool))
-               GOTO(out_env, rc = PTR_ERR(glbl_pool));
+               GOTO(out, rc = PTR_ERR(glbl_pool));
 
        slaves_cnt = qmt_sarr_count(pool);
        CDEBUG(D_QUOTA, "Starting pool recalculation for %d slaves in %s\n",
@@ -1237,8 +1238,6 @@ static int qmt_pool_recalc(void *args)
        GOTO(out_stop, rc);
 out_stop:
        qpi_putref(&env, glbl_pool);
-out_env:
-       lu_env_fini(&env);
 out:
        if (xchg(&pool->qpi_recalc_task, NULL) == NULL)
                /*
@@ -1251,12 +1250,20 @@ out:
 
        clear_bit(QPI_FLAG_RECALC_OFFSET, &pool->qpi_flags);
        /* Pool can't be changed, since sem has been down.
-        * Thus until up_read, no one can restart recalc thread. */
+        * Thus until up_read, no one can restart recalc thread.
+        */
        if (sem) {
                up_read(sem);
                up_write(&pool->qpi_recalc_sem);
        }
-       qpi_putref(&env, pool);
+
+       /* qpi_getref has been called in qmt_start_pool_recalc,
+        * however we can't call qpi_putref if lu_env_init failed.
+        */
+       if (env.le_ctx.lc_state == LCS_ENTERED) {
+               qpi_putref(&env, pool);
+               lu_env_fini(&env);
+       }
 
        return rc;
 }