From 57d88137e12472cf5ea08aa28957b4767abd475c Mon Sep 17 00:00:00 2001 From: Sergey Cheremencev Date: Thu, 21 Oct 2021 23:28:01 +0300 Subject: [PATCH] LU-15263 quota: fix bug in qmt_pool_recalc 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: [] lu_context_key_get+0x17/0x30 [obdclass] ... Call Trace: [] lu_object_free.isra.30+0x68/0x170 [obdclass] [] lu_object_put+0xc5/0x3e0 [obdclass] [] qmt_pool_free+0x30c/0x590 [lquota] [] qmt_pool_recalc+0x365/0x1260 [lquota] [] kthread+0xd1/0xe0 [] ret_from_fork_nospec_begin+0x21/0x21 HPE-bug-id: LUS-10426 Change-Id: Ic23dcb858ff811757f38948aa572c936c076e21e Signed-off-by: Sergey Cheremencev Reviewed-by: Vladimir Saveliev Reviewed-by: Andriy Skulysh Reviewed-on: https://review.whamcloud.com/45632 Tested-by: jenkins Reviewed-by: Andriy Skulysh Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/quota/qmt_pool.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/lustre/quota/qmt_pool.c b/lustre/quota/qmt_pool.c index 37bb488..7bb1ee3 100644 --- a/lustre/quota/qmt_pool.c +++ b/lustre/quota/qmt_pool.c @@ -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; } -- 1.8.3.1