Contributors: 18
Author Tokens Token Proportion Commits Commit Proportion
Jakub Kiciński 237 46.56% 15 38.46%
Stanislav Fomichev 107 21.02% 7 17.95%
Kuniyuki Iwashima 28 5.50% 2 5.13%
Alexander Aring 26 5.11% 1 2.56%
Patrick McHardy 24 4.72% 1 2.56%
Michal Kubeček 16 3.14% 1 2.56%
Michael Chan 16 3.14% 1 2.56%
Heiner Kallweit 10 1.96% 1 2.56%
Antoine Tenart 10 1.96% 1 2.56%
Andrea Mayer 8 1.57% 1 2.56%
Steffen Klassert 6 1.18% 1 2.56%
Florian Fainelli 5 0.98% 1 2.56%
Jiri Pirko 5 0.98% 1 2.56%
David S. Miller 4 0.79% 1 2.56%
Kory Maincent 3 0.59% 1 2.56%
Vivien Didelot 2 0.39% 1 2.56%
Thomas Gleixner 1 0.20% 1 2.56%
Rahul Rameshbabu 1 0.20% 1 2.56%
Total 509 39


/* SPDX-License-Identifier: GPL-2.0-or-later */

#ifndef _NET_NETDEV_LOCK_H
#define _NET_NETDEV_LOCK_H

#include <linux/lockdep.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>

static inline bool netdev_trylock(struct net_device *dev)
{
	return mutex_trylock(&dev->lock);
}

static inline void netdev_assert_locked(const struct net_device *dev)
{
	lockdep_assert_held(&dev->lock);
}

static inline void
netdev_assert_locked_or_invisible(const struct net_device *dev)
{
	if (dev->reg_state == NETREG_REGISTERED ||
	    dev->reg_state == NETREG_UNREGISTERING)
		netdev_assert_locked(dev);
}

static inline bool netdev_need_ops_lock(const struct net_device *dev)
{
	bool ret = dev->request_ops_lock || !!dev->queue_mgmt_ops;

#if IS_ENABLED(CONFIG_NET_SHAPER)
	ret |= !!dev->netdev_ops->net_shaper_ops;
#endif

	return ret;
}

static inline void netdev_lock_ops(struct net_device *dev)
{
	if (netdev_need_ops_lock(dev))
		netdev_lock(dev);
}

static inline void netdev_unlock_ops(struct net_device *dev)
{
	if (netdev_need_ops_lock(dev))
		netdev_unlock(dev);
}

static inline void netdev_lock_ops_to_full(struct net_device *dev)
{
	if (netdev_need_ops_lock(dev))
		netdev_assert_locked(dev);
	else
		netdev_lock(dev);
}

static inline void netdev_unlock_full_to_ops(struct net_device *dev)
{
	if (netdev_need_ops_lock(dev))
		netdev_assert_locked(dev);
	else
		netdev_unlock(dev);
}

static inline void netdev_assert_locked_ops_compat(const struct net_device *dev)
{
	if (netdev_need_ops_lock(dev))
		lockdep_assert_held(&dev->lock);
	else
		ASSERT_RTNL();
}

static inline void
netdev_assert_locked_ops_compat_or_invisible(const struct net_device *dev)
{
	if (dev->reg_state == NETREG_REGISTERED ||
	    dev->reg_state == NETREG_UNREGISTERING)
		netdev_assert_locked_ops_compat(dev);
}

static inline void netdev_assert_locked_ops(const struct net_device *dev)
{
	if (netdev_need_ops_lock(dev))
		netdev_assert_locked(dev);
}

static inline void netdev_lock_ops_compat(struct net_device *dev)
{
	if (netdev_need_ops_lock(dev))
		netdev_lock(dev);
	else
		rtnl_lock();
}

static inline void netdev_unlock_ops_compat(struct net_device *dev)
{
	if (netdev_need_ops_lock(dev))
		netdev_unlock(dev);
	else
		rtnl_unlock();
}

/* Matching "ops protected" category from netdevice.h */
static inline int netdev_is_locked_ops_compat(const struct net_device *dev)
{
	if (netdev_need_ops_lock(dev))
		return lockdep_is_held(&dev->lock);
	return lockdep_rtnl_is_held();
}

static inline int netdev_lock_cmp_fn(const struct lockdep_map *a,
				     const struct lockdep_map *b)
{
	if (a == b)
		return 0;

	/* Allow locking multiple devices only under rtnl_lock,
	 * the exact order doesn't matter.
	 * Note that upper devices don't lock their ops, so nesting
	 * mostly happens in batched device removal for now.
	 */
	return lockdep_rtnl_is_held() ? -1 : 1;
}

#define netdev_lockdep_set_classes(dev)				\
{								\
	static struct lock_class_key qdisc_tx_busylock_key;	\
	static struct lock_class_key qdisc_xmit_lock_key;	\
	static struct lock_class_key dev_addr_list_lock_key;	\
	static struct lock_class_key dev_instance_lock_key;	\
	unsigned int i;						\
								\
	(dev)->qdisc_tx_busylock = &qdisc_tx_busylock_key;	\
	lockdep_set_class(&(dev)->addr_list_lock,		\
			  &dev_addr_list_lock_key);		\
	lockdep_set_class(&(dev)->lock,				\
			  &dev_instance_lock_key);		\
	lock_set_cmp_fn(&dev->lock, netdev_lock_cmp_fn, NULL);	\
	for (i = 0; i < (dev)->num_tx_queues; i++)		\
		lockdep_set_class(&(dev)->_tx[i]._xmit_lock,	\
				  &qdisc_xmit_lock_key);	\
}

#define netdev_lock_dereference(p, dev)				\
	rcu_dereference_protected(p, lockdep_is_held(&(dev)->lock))

#define netdev_ops_lock_dereference(p, dev)				\
	rcu_dereference_protected(p, netdev_is_locked_ops_compat(dev))

int netdev_debug_event(struct notifier_block *nb, unsigned long event,
		       void *ptr);

#endif