Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62256f98 authored by Florian Westphal's avatar Florian Westphal Committed by David S. Miller
Browse files

rtnetlink: add RTNL_FLAG_DOIT_UNLOCKED



Allow callers to tell rtnetlink core that its doit callback
should be invoked without holding rtnl mutex.

Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Reviewed-by: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6853dd48
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -8,6 +8,10 @@ typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *,
			      struct netlink_ext_ack *);
typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *);

enum rtnl_link_flags {
	RTNL_FLAG_DOIT_UNLOCKED = 1,
};

int __rtnl_register(int protocol, int msgtype,
		    rtnl_doit_func, rtnl_dumpit_func, unsigned int flags);
void rtnl_register(int protocol, int msgtype,
+15 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@
struct rtnl_link {
	rtnl_doit_func		doit;
	rtnl_dumpit_func	dumpit;
	unsigned int		flags;
};

static DEFINE_MUTEX(rtnl_mutex);
@@ -184,6 +185,7 @@ int __rtnl_register(int protocol, int msgtype,
		tab[msgindex].doit = doit;
	if (dumpit)
		tab[msgindex].dumpit = dumpit;
	tab[msgindex].flags |= flags;

	return 0;
}
@@ -233,6 +235,7 @@ int rtnl_unregister(int protocol, int msgtype)

	handlers[msgindex].doit = NULL;
	handlers[msgindex].dumpit = NULL;
	handlers[msgindex].flags = 0;
	rtnl_unlock();

	return 0;
@@ -4143,6 +4146,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
	struct rtnl_link *handlers;
	int err = -EOPNOTSUPP;
	rtnl_doit_func doit;
	unsigned int flags;
	int kind;
	int family;
	int type;
@@ -4209,6 +4213,17 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
		return err;
	}

	flags = READ_ONCE(handlers[type].flags);
	if (flags & RTNL_FLAG_DOIT_UNLOCKED) {
		refcount_inc(&rtnl_msg_handlers_ref[family]);
		doit = READ_ONCE(handlers[type].doit);
		rcu_read_unlock();
		if (doit)
			err = doit(skb, nlh, extack);
		refcount_dec(&rtnl_msg_handlers_ref[family]);
		return err;
	}

	rcu_read_unlock();

	rtnl_lock();