Skip to content

Commit 779b995

Browse files
yosrym93akpm00
authored andcommitted
mm: zswap: move allocations during CPU init outside the lock
In zswap_cpu_comp_prepare(), allocations are made and assigned to various members of acomp_ctx under acomp_ctx->mutex. However, allocations may recurse into zswap through reclaim, trying to acquire the same mutex and deadlocking. Move the allocations before the mutex critical section. Only the initialization of acomp_ctx needs to be done with the mutex held. Link: https://lkml.kernel.org/r/20250113214458.2123410-1-yosryahmed@google.com Fixes: 12dcb0e ("mm: zswap: properly synchronize freeing resources during CPU hotunplug") Signed-off-by: Yosry Ahmed <yosryahmed@google.com> Reviewed-by: Chengming Zhou <chengming.zhou@linux.dev> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Nhat Pham <nphamcs@gmail.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent f1897f2 commit 779b995

File tree

1 file changed

+24
-18
lines changed

1 file changed

+24
-18
lines changed

mm/zswap.c

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -820,37 +820,41 @@ static int zswap_cpu_comp_prepare(unsigned int cpu, struct hlist_node *node)
820820
{
821821
struct zswap_pool *pool = hlist_entry(node, struct zswap_pool, node);
822822
struct crypto_acomp_ctx *acomp_ctx = per_cpu_ptr(pool->acomp_ctx, cpu);
823-
struct crypto_acomp *acomp;
824-
struct acomp_req *req;
823+
struct crypto_acomp *acomp = NULL;
824+
struct acomp_req *req = NULL;
825+
u8 *buffer = NULL;
825826
int ret;
826827

827-
mutex_lock(&acomp_ctx->mutex);
828-
acomp_ctx->buffer = kmalloc_node(PAGE_SIZE * 2, GFP_KERNEL, cpu_to_node(cpu));
829-
if (!acomp_ctx->buffer) {
828+
buffer = kmalloc_node(PAGE_SIZE * 2, GFP_KERNEL, cpu_to_node(cpu));
829+
if (!buffer) {
830830
ret = -ENOMEM;
831-
goto buffer_fail;
831+
goto fail;
832832
}
833833

834834
acomp = crypto_alloc_acomp_node(pool->tfm_name, 0, 0, cpu_to_node(cpu));
835835
if (IS_ERR(acomp)) {
836836
pr_err("could not alloc crypto acomp %s : %ld\n",
837837
pool->tfm_name, PTR_ERR(acomp));
838838
ret = PTR_ERR(acomp);
839-
goto acomp_fail;
839+
goto fail;
840840
}
841-
acomp_ctx->acomp = acomp;
842-
acomp_ctx->is_sleepable = acomp_is_async(acomp);
843841

844-
req = acomp_request_alloc(acomp_ctx->acomp);
842+
req = acomp_request_alloc(acomp);
845843
if (!req) {
846844
pr_err("could not alloc crypto acomp_request %s\n",
847845
pool->tfm_name);
848846
ret = -ENOMEM;
849-
goto req_fail;
847+
goto fail;
850848
}
851-
acomp_ctx->req = req;
852849

850+
/*
851+
* Only hold the mutex after completing allocations, otherwise we may
852+
* recurse into zswap through reclaim and attempt to hold the mutex
853+
* again resulting in a deadlock.
854+
*/
855+
mutex_lock(&acomp_ctx->mutex);
853856
crypto_init_wait(&acomp_ctx->wait);
857+
854858
/*
855859
* if the backend of acomp is async zip, crypto_req_done() will wakeup
856860
* crypto_wait_req(); if the backend of acomp is scomp, the callback
@@ -859,15 +863,17 @@ static int zswap_cpu_comp_prepare(unsigned int cpu, struct hlist_node *node)
859863
acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
860864
crypto_req_done, &acomp_ctx->wait);
861865

866+
acomp_ctx->buffer = buffer;
867+
acomp_ctx->acomp = acomp;
868+
acomp_ctx->is_sleepable = acomp_is_async(acomp);
869+
acomp_ctx->req = req;
862870
mutex_unlock(&acomp_ctx->mutex);
863871
return 0;
864872

865-
req_fail:
866-
crypto_free_acomp(acomp_ctx->acomp);
867-
acomp_fail:
868-
kfree(acomp_ctx->buffer);
869-
buffer_fail:
870-
mutex_unlock(&acomp_ctx->mutex);
873+
fail:
874+
if (acomp)
875+
crypto_free_acomp(acomp);
876+
kfree(buffer);
871877
return ret;
872878
}
873879

0 commit comments

Comments
 (0)