net: Don't register pernet_operations if only one of id or size is specified.

We can allocate per-netns memory for struct pernet_operations by specifying
id and size.

register_pernet_operations() assigns an id to pernet_operations and later
ops_init() allocates the specified size of memory as net->gen->ptr[id].

If id is missing, no memory is allocated.  If size is not specified,
pernet_operations just wastes an entry of net->gen->ptr[] for every netns.

net_generic is available only when both id and size are specified, so let's
ensure that.

While we are at it, we add const to both fields.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Kuniyuki Iwashima 2024-07-31 13:07:17 -07:00 committed by David S. Miller
parent 1ad001347f
commit 768e4bb6a7
2 changed files with 10 additions and 6 deletions

View File

@ -451,8 +451,8 @@ struct pernet_operations {
/* Following method is called with RTNL held. */
void (*exit_batch_rtnl)(struct list_head *net_exit_list,
struct list_head *dev_kill_list);
unsigned int *id;
size_t size;
unsigned int * const id;
const size_t size;
};
/*

View File

@ -125,7 +125,7 @@ static int ops_init(const struct pernet_operations *ops, struct net *net)
int err = -ENOMEM;
void *data = NULL;
if (ops->id && ops->size) {
if (ops->id) {
data = kzalloc(ops->size, GFP_KERNEL);
if (!data)
goto out;
@ -140,7 +140,7 @@ static int ops_init(const struct pernet_operations *ops, struct net *net)
if (!err)
return 0;
if (ops->id && ops->size) {
if (ops->id) {
ng = rcu_dereference_protected(net->gen,
lockdep_is_held(&pernet_ops_rwsem));
ng->ptr[*ops->id] = NULL;
@ -182,7 +182,8 @@ static void ops_free_list(const struct pernet_operations *ops,
struct list_head *net_exit_list)
{
struct net *net;
if (ops->size && ops->id) {
if (ops->id) {
list_for_each_entry(net, net_exit_list, exit_list)
kfree(net_generic(net, *ops->id));
}
@ -1244,7 +1245,7 @@ static int __register_pernet_operations(struct list_head *list,
LIST_HEAD(net_exit_list);
list_add_tail(&ops->list, list);
if (ops->init || (ops->id && ops->size)) {
if (ops->init || ops->id) {
/* We held write locked pernet_ops_rwsem, and parallel
* setup_net() and cleanup_net() are not possible.
*/
@ -1310,6 +1311,9 @@ static int register_pernet_operations(struct list_head *list,
{
int error;
if (WARN_ON(!!ops->id ^ !!ops->size))
return -EINVAL;
if (ops->id) {
error = ida_alloc_min(&net_generic_ids, MIN_PERNET_OPS_ID,
GFP_KERNEL);