diff options
author | Kuniyuki Iwashima <kuniyu@amazon.com> | 2025-02-27 20:23:18 -0800 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2025-03-03 15:04:09 -0800 |
commit | fa336adc100e1d76a50da782c3e9abb1541a72f3 (patch) | |
tree | 1db590f13d0a1ffbc3d7dd0c22be687d295e49c3 | |
parent | e5bf1c39e894d754092ff55b06035ed222a359ec (diff) |
ipv4: fib: Allocate fib_info_hash[] and fib_info_laddrhash[] by kvcalloc().
Both fib_info_hash[] and fib_info_laddrhash[] are hash tables for
struct fib_info and are allocated by kvzmalloc() separately.
Let's replace the two kvzmalloc() calls with kvcalloc() to remove
the fib_info_laddrhash pointer later.
Note that fib_info_hash_alloc() allocates a new hash table based on
fib_info_hash_bits because we will remove fib_info_hash_size later.
Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20250228042328.96624-3-kuniyu@amazon.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | net/ipv4/fib_semantics.c | 43 |
1 files changed, 25 insertions, 18 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index d2cee5c314f5..23aae379ba42 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -357,6 +357,18 @@ static inline unsigned int fib_info_hashfn(struct fib_info *fi) return fib_info_hashfn_result(fi->fib_net, val); } +static struct hlist_head *fib_info_hash_alloc(unsigned int hash_bits) +{ + /* The second half is used for prefsrc */ + return kvcalloc((1 << hash_bits) * 2, sizeof(struct hlist_head *), + GFP_KERNEL); +} + +static void fib_info_hash_free(struct hlist_head *head) +{ + kvfree(head); +} + /* no metrics, only nexthop id */ static struct fib_info *fib_find_info_nh(struct net *net, const struct fib_config *cfg) @@ -1249,9 +1261,9 @@ fib_info_laddrhash_bucket(const struct net *net, __be32 val) } static void fib_info_hash_move(struct hlist_head *new_info_hash, - struct hlist_head *new_laddrhash, unsigned int new_size) { + struct hlist_head *new_laddrhash = new_info_hash + new_size; struct hlist_head *old_info_hash, *old_laddrhash; unsigned int old_size = fib_info_hash_size; unsigned int i; @@ -1293,8 +1305,7 @@ static void fib_info_hash_move(struct hlist_head *new_info_hash, } } - kvfree(old_info_hash); - kvfree(old_laddrhash); + fib_info_hash_free(old_info_hash); } __be32 fib_info_update_nhc_saddr(struct net *net, struct fib_nh_common *nhc, @@ -1412,22 +1423,18 @@ struct fib_info *fib_create_info(struct fib_config *cfg, err = -ENOBUFS; if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; struct hlist_head *new_info_hash; - struct hlist_head *new_laddrhash; - size_t bytes; - - if (!new_size) - new_size = 16; - bytes = (size_t)new_size * sizeof(struct hlist_head *); - new_info_hash = kvzalloc(bytes, GFP_KERNEL); - new_laddrhash = kvzalloc(bytes, GFP_KERNEL); - if (!new_info_hash || !new_laddrhash) { - kvfree(new_info_hash); - kvfree(new_laddrhash); - } else { - fib_info_hash_move(new_info_hash, new_laddrhash, new_size); - } + unsigned int new_hash_bits; + + if (!fib_info_hash_bits) + new_hash_bits = 4; + else + new_hash_bits = fib_info_hash_bits + 1; + + new_info_hash = fib_info_hash_alloc(new_hash_bits); + if (new_info_hash) + fib_info_hash_move(new_info_hash, 1 << new_hash_bits); + if (!fib_info_hash_size) goto failure; } |