summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUladzislau Rezki (Sony) <urezki@gmail.com>2026-04-28 18:14:19 +0200
committerHerbert Xu <herbert@gondor.apana.org.au>2026-05-05 16:12:07 +0800
commitd1fa83ecac31093a550534a79a33bc7f4ba8fc10 (patch)
tree53e406c8ac9c7396ddca3ab02b0ada5d8d4bc73a
parentdad0d91cc2c3e6b6fb285ccfe7ddf71525797198 (diff)
rhashtable: Add bucket_table_free_atomic() helper
rhashtable_insert_rehash() allocates a new bucket table with GFP_ATOMIC, as it is called from an RCU read-side critical section. If rhashtable_rehash_attach() then fails, the new table is freed via kvfree(). This is unsafe, since kvfree() may fall back to vfree() for vmalloc-backed allocations, which can sleep and trigger: BUG: sleeping function called from invalid context Add bucket_table_free_atomic(), which uses kvfree_atomic() so the table can be freed safely from non-sleeping context. Signed-off-by: Uladzislau Rezki (Sony) <urezki@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--lib/rhashtable.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index 426d4e381f13..04b3a808fca9 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -114,6 +114,14 @@ static void bucket_table_free(const struct bucket_table *tbl)
kvfree(tbl);
}
+static void bucket_table_free_atomic(const struct bucket_table *tbl)
+{
+ if (tbl->nest)
+ nested_bucket_table_free(tbl);
+
+ kvfree_atomic(tbl);
+}
+
static void bucket_table_free_rcu(struct rcu_head *head)
{
bucket_table_free(container_of(head, struct bucket_table, rcu));
@@ -496,7 +504,7 @@ static int rhashtable_insert_rehash(struct rhashtable *ht,
err = rhashtable_rehash_attach(ht, tbl, new_tbl);
if (err) {
- bucket_table_free(new_tbl);
+ bucket_table_free_atomic(new_tbl);
if (err == -EEXIST)
err = 0;
} else