mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
![Johannes Berg](/assets/img/avatar_default.png)
In addition to the problem Jeff Layton reported, I looked at the code and reproduced the same warning by subscribing and removing the genl family with a socket still open. This is a fairly tricky race which originates in the fact that generic netlink allows the family to go away while sockets are still open - unlike regular netlink which has a module refcount for every open socket so in general this cannot be triggered. Trying to resolve this issue by the obvious locking isn't possible as it will result in deadlocks between unregistration and group unbind notification (which incidentally lockdep doesn't find due to the home grown locking in the netlink table.) To really resolve this, introduce a "closing socket" reference counter (for generic netlink only, as it's the only affected family) in the core netlink code and use that in generic netlink to wait for all the sockets that are being closed at the same time as a generic netlink family is removed. This fixes the race that when a socket is closed, it will should call the unbind, but if the family is removed at the same time the unbind will not find it, leading to the warning. The real problem though is that in this case the unbind could actually find a new family that is registered to have a multicast group with the same ID, and call its mcast_unbind() leading to confusing. Also remove the warning since it would still trigger, but is now no longer a problem. This also moves the code in af_netlink.c to before unreferencing the module to avoid having the same problem in the normal non-genl case. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
42 lines
1.4 KiB
C
42 lines
1.4 KiB
C
#ifndef __LINUX_GENERIC_NETLINK_H
|
|
#define __LINUX_GENERIC_NETLINK_H
|
|
|
|
#include <uapi/linux/genetlink.h>
|
|
|
|
|
|
/* All generic netlink requests are serialized by a global lock. */
|
|
extern void genl_lock(void);
|
|
extern void genl_unlock(void);
|
|
#ifdef CONFIG_LOCKDEP
|
|
extern int lockdep_genl_is_held(void);
|
|
#endif
|
|
|
|
/* for synchronisation between af_netlink and genetlink */
|
|
extern atomic_t genl_sk_destructing_cnt;
|
|
extern wait_queue_head_t genl_sk_destructing_waitq;
|
|
|
|
/**
|
|
* rcu_dereference_genl - rcu_dereference with debug checking
|
|
* @p: The pointer to read, prior to dereferencing
|
|
*
|
|
* Do an rcu_dereference(p), but check caller either holds rcu_read_lock()
|
|
* or genl mutex. Note : Please prefer genl_dereference() or rcu_dereference()
|
|
*/
|
|
#define rcu_dereference_genl(p) \
|
|
rcu_dereference_check(p, lockdep_genl_is_held())
|
|
|
|
/**
|
|
* genl_dereference - fetch RCU pointer when updates are prevented by genl mutex
|
|
* @p: The pointer to read, prior to dereferencing
|
|
*
|
|
* Return the value of the specified RCU-protected pointer, but omit
|
|
* both the smp_read_barrier_depends() and the ACCESS_ONCE(), because
|
|
* caller holds genl mutex.
|
|
*/
|
|
#define genl_dereference(p) \
|
|
rcu_dereference_protected(p, lockdep_genl_is_held())
|
|
|
|
#define MODULE_ALIAS_GENL_FAMILY(family)\
|
|
MODULE_ALIAS_NET_PF_PROTO_NAME(PF_NETLINK, NETLINK_GENERIC, "-family-" family)
|
|
|
|
#endif /* __LINUX_GENERIC_NETLINK_H */
|