Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
The only slightly tricky merge conflict was the netdevsim because the mutex locking fix overlapped a lot of driver reload reorganization. The rest were (relatively) trivial in nature. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
623
net/core/dev.c
623
net/core/dev.c
@@ -146,6 +146,7 @@
|
||||
#include "net-sysfs.h"
|
||||
|
||||
#define MAX_GRO_SKBS 8
|
||||
#define MAX_NEST_DEV 8
|
||||
|
||||
/* This should be increased if a protocol with a bigger head is added. */
|
||||
#define GRO_MAX_HEAD (MAX_HEADER + 128)
|
||||
@@ -392,88 +393,6 @@ static RAW_NOTIFIER_HEAD(netdev_chain);
|
||||
DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);
|
||||
EXPORT_PER_CPU_SYMBOL(softnet_data);
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
/*
|
||||
* register_netdevice() inits txq->_xmit_lock and sets lockdep class
|
||||
* according to dev->type
|
||||
*/
|
||||
static const unsigned short netdev_lock_type[] = {
|
||||
ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_EETHER, ARPHRD_AX25,
|
||||
ARPHRD_PRONET, ARPHRD_CHAOS, ARPHRD_IEEE802, ARPHRD_ARCNET,
|
||||
ARPHRD_APPLETLK, ARPHRD_DLCI, ARPHRD_ATM, ARPHRD_METRICOM,
|
||||
ARPHRD_IEEE1394, ARPHRD_EUI64, ARPHRD_INFINIBAND, ARPHRD_SLIP,
|
||||
ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6, ARPHRD_RSRVD,
|
||||
ARPHRD_ADAPT, ARPHRD_ROSE, ARPHRD_X25, ARPHRD_HWX25,
|
||||
ARPHRD_PPP, ARPHRD_CISCO, ARPHRD_LAPB, ARPHRD_DDCMP,
|
||||
ARPHRD_RAWHDLC, ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD,
|
||||
ARPHRD_SKIP, ARPHRD_LOOPBACK, ARPHRD_LOCALTLK, ARPHRD_FDDI,
|
||||
ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE,
|
||||
ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET,
|
||||
ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL,
|
||||
ARPHRD_FCFABRIC, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM,
|
||||
ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, ARPHRD_PHONET_PIPE,
|
||||
ARPHRD_IEEE802154, ARPHRD_VOID, ARPHRD_NONE};
|
||||
|
||||
static const char *const netdev_lock_name[] = {
|
||||
"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25",
|
||||
"_xmit_PRONET", "_xmit_CHAOS", "_xmit_IEEE802", "_xmit_ARCNET",
|
||||
"_xmit_APPLETLK", "_xmit_DLCI", "_xmit_ATM", "_xmit_METRICOM",
|
||||
"_xmit_IEEE1394", "_xmit_EUI64", "_xmit_INFINIBAND", "_xmit_SLIP",
|
||||
"_xmit_CSLIP", "_xmit_SLIP6", "_xmit_CSLIP6", "_xmit_RSRVD",
|
||||
"_xmit_ADAPT", "_xmit_ROSE", "_xmit_X25", "_xmit_HWX25",
|
||||
"_xmit_PPP", "_xmit_CISCO", "_xmit_LAPB", "_xmit_DDCMP",
|
||||
"_xmit_RAWHDLC", "_xmit_TUNNEL", "_xmit_TUNNEL6", "_xmit_FRAD",
|
||||
"_xmit_SKIP", "_xmit_LOOPBACK", "_xmit_LOCALTLK", "_xmit_FDDI",
|
||||
"_xmit_BIF", "_xmit_SIT", "_xmit_IPDDP", "_xmit_IPGRE",
|
||||
"_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET",
|
||||
"_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL",
|
||||
"_xmit_FCFABRIC", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM",
|
||||
"_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", "_xmit_PHONET_PIPE",
|
||||
"_xmit_IEEE802154", "_xmit_VOID", "_xmit_NONE"};
|
||||
|
||||
static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)];
|
||||
static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)];
|
||||
|
||||
static inline unsigned short netdev_lock_pos(unsigned short dev_type)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(netdev_lock_type); i++)
|
||||
if (netdev_lock_type[i] == dev_type)
|
||||
return i;
|
||||
/* the last key is used by default */
|
||||
return ARRAY_SIZE(netdev_lock_type) - 1;
|
||||
}
|
||||
|
||||
static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock,
|
||||
unsigned short dev_type)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = netdev_lock_pos(dev_type);
|
||||
lockdep_set_class_and_name(lock, &netdev_xmit_lock_key[i],
|
||||
netdev_lock_name[i]);
|
||||
}
|
||||
|
||||
static inline void netdev_set_addr_lockdep_class(struct net_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = netdev_lock_pos(dev->type);
|
||||
lockdep_set_class_and_name(&dev->addr_list_lock,
|
||||
&netdev_addr_lock_key[i],
|
||||
netdev_lock_name[i]);
|
||||
}
|
||||
#else
|
||||
static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock,
|
||||
unsigned short dev_type)
|
||||
{
|
||||
}
|
||||
static inline void netdev_set_addr_lockdep_class(struct net_device *dev)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Protocol management and registration routines
|
||||
@@ -6711,6 +6630,9 @@ struct netdev_adjacent {
|
||||
/* upper master flag, there can only be one master device per list */
|
||||
bool master;
|
||||
|
||||
/* lookup ignore flag */
|
||||
bool ignore;
|
||||
|
||||
/* counter for the number of times this device was added to us */
|
||||
u16 ref_nr;
|
||||
|
||||
@@ -6733,7 +6655,7 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __netdev_has_upper_dev(struct net_device *upper_dev, void *data)
|
||||
static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data)
|
||||
{
|
||||
struct net_device *dev = data;
|
||||
|
||||
@@ -6754,7 +6676,7 @@ bool netdev_has_upper_dev(struct net_device *dev,
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
return netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev,
|
||||
return netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,
|
||||
upper_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_has_upper_dev);
|
||||
@@ -6772,7 +6694,7 @@ EXPORT_SYMBOL(netdev_has_upper_dev);
|
||||
bool netdev_has_upper_dev_all_rcu(struct net_device *dev,
|
||||
struct net_device *upper_dev)
|
||||
{
|
||||
return !!netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev,
|
||||
return !!netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev,
|
||||
upper_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu);
|
||||
@@ -6816,6 +6738,22 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_master_upper_dev_get);
|
||||
|
||||
static struct net_device *__netdev_master_upper_dev_get(struct net_device *dev)
|
||||
{
|
||||
struct netdev_adjacent *upper;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (list_empty(&dev->adj_list.upper))
|
||||
return NULL;
|
||||
|
||||
upper = list_first_entry(&dev->adj_list.upper,
|
||||
struct netdev_adjacent, list);
|
||||
if (likely(upper->master) && !upper->ignore)
|
||||
return upper->dev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* netdev_has_any_lower_dev - Check if device is linked to some device
|
||||
* @dev: device
|
||||
@@ -6866,6 +6804,23 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu);
|
||||
|
||||
static struct net_device *__netdev_next_upper_dev(struct net_device *dev,
|
||||
struct list_head **iter,
|
||||
bool *ignore)
|
||||
{
|
||||
struct netdev_adjacent *upper;
|
||||
|
||||
upper = list_entry((*iter)->next, struct netdev_adjacent, list);
|
||||
|
||||
if (&upper->list == &dev->adj_list.upper)
|
||||
return NULL;
|
||||
|
||||
*iter = &upper->list;
|
||||
*ignore = upper->ignore;
|
||||
|
||||
return upper->dev;
|
||||
}
|
||||
|
||||
static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
|
||||
struct list_head **iter)
|
||||
{
|
||||
@@ -6883,34 +6838,111 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
|
||||
return upper->dev;
|
||||
}
|
||||
|
||||
static int __netdev_walk_all_upper_dev(struct net_device *dev,
|
||||
int (*fn)(struct net_device *dev,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
|
||||
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
|
||||
int ret, cur = 0;
|
||||
bool ignore;
|
||||
|
||||
now = dev;
|
||||
iter = &dev->adj_list.upper;
|
||||
|
||||
while (1) {
|
||||
if (now != dev) {
|
||||
ret = fn(now, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
next = NULL;
|
||||
while (1) {
|
||||
udev = __netdev_next_upper_dev(now, &iter, &ignore);
|
||||
if (!udev)
|
||||
break;
|
||||
if (ignore)
|
||||
continue;
|
||||
|
||||
next = udev;
|
||||
niter = &udev->adj_list.upper;
|
||||
dev_stack[cur] = now;
|
||||
iter_stack[cur++] = iter;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!next) {
|
||||
if (!cur)
|
||||
return 0;
|
||||
next = dev_stack[--cur];
|
||||
niter = iter_stack[cur];
|
||||
}
|
||||
|
||||
now = next;
|
||||
iter = niter;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
|
||||
int (*fn)(struct net_device *dev,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct net_device *udev;
|
||||
struct list_head *iter;
|
||||
int ret;
|
||||
struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
|
||||
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
|
||||
int ret, cur = 0;
|
||||
|
||||
for (iter = &dev->adj_list.upper,
|
||||
udev = netdev_next_upper_dev_rcu(dev, &iter);
|
||||
udev;
|
||||
udev = netdev_next_upper_dev_rcu(dev, &iter)) {
|
||||
/* first is the upper device itself */
|
||||
ret = fn(udev, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
now = dev;
|
||||
iter = &dev->adj_list.upper;
|
||||
|
||||
/* then look at all of its upper devices */
|
||||
ret = netdev_walk_all_upper_dev_rcu(udev, fn, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
while (1) {
|
||||
if (now != dev) {
|
||||
ret = fn(now, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
next = NULL;
|
||||
while (1) {
|
||||
udev = netdev_next_upper_dev_rcu(now, &iter);
|
||||
if (!udev)
|
||||
break;
|
||||
|
||||
next = udev;
|
||||
niter = &udev->adj_list.upper;
|
||||
dev_stack[cur] = now;
|
||||
iter_stack[cur++] = iter;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!next) {
|
||||
if (!cur)
|
||||
return 0;
|
||||
next = dev_stack[--cur];
|
||||
niter = iter_stack[cur];
|
||||
}
|
||||
|
||||
now = next;
|
||||
iter = niter;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu);
|
||||
|
||||
static bool __netdev_has_upper_dev(struct net_device *dev,
|
||||
struct net_device *upper_dev)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
return __netdev_walk_all_upper_dev(dev, ____netdev_has_upper_dev,
|
||||
upper_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* netdev_lower_get_next_private - Get the next ->private from the
|
||||
* lower neighbour list
|
||||
@@ -7007,34 +7039,119 @@ static struct net_device *netdev_next_lower_dev(struct net_device *dev,
|
||||
return lower->dev;
|
||||
}
|
||||
|
||||
static struct net_device *__netdev_next_lower_dev(struct net_device *dev,
|
||||
struct list_head **iter,
|
||||
bool *ignore)
|
||||
{
|
||||
struct netdev_adjacent *lower;
|
||||
|
||||
lower = list_entry((*iter)->next, struct netdev_adjacent, list);
|
||||
|
||||
if (&lower->list == &dev->adj_list.lower)
|
||||
return NULL;
|
||||
|
||||
*iter = &lower->list;
|
||||
*ignore = lower->ignore;
|
||||
|
||||
return lower->dev;
|
||||
}
|
||||
|
||||
int netdev_walk_all_lower_dev(struct net_device *dev,
|
||||
int (*fn)(struct net_device *dev,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct net_device *ldev;
|
||||
struct list_head *iter;
|
||||
int ret;
|
||||
struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
|
||||
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
|
||||
int ret, cur = 0;
|
||||
|
||||
for (iter = &dev->adj_list.lower,
|
||||
ldev = netdev_next_lower_dev(dev, &iter);
|
||||
ldev;
|
||||
ldev = netdev_next_lower_dev(dev, &iter)) {
|
||||
/* first is the lower device itself */
|
||||
ret = fn(ldev, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
now = dev;
|
||||
iter = &dev->adj_list.lower;
|
||||
|
||||
/* then look at all of its lower devices */
|
||||
ret = netdev_walk_all_lower_dev(ldev, fn, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
while (1) {
|
||||
if (now != dev) {
|
||||
ret = fn(now, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
next = NULL;
|
||||
while (1) {
|
||||
ldev = netdev_next_lower_dev(now, &iter);
|
||||
if (!ldev)
|
||||
break;
|
||||
|
||||
next = ldev;
|
||||
niter = &ldev->adj_list.lower;
|
||||
dev_stack[cur] = now;
|
||||
iter_stack[cur++] = iter;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!next) {
|
||||
if (!cur)
|
||||
return 0;
|
||||
next = dev_stack[--cur];
|
||||
niter = iter_stack[cur];
|
||||
}
|
||||
|
||||
now = next;
|
||||
iter = niter;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev);
|
||||
|
||||
static int __netdev_walk_all_lower_dev(struct net_device *dev,
|
||||
int (*fn)(struct net_device *dev,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
|
||||
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
|
||||
int ret, cur = 0;
|
||||
bool ignore;
|
||||
|
||||
now = dev;
|
||||
iter = &dev->adj_list.lower;
|
||||
|
||||
while (1) {
|
||||
if (now != dev) {
|
||||
ret = fn(now, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
next = NULL;
|
||||
while (1) {
|
||||
ldev = __netdev_next_lower_dev(now, &iter, &ignore);
|
||||
if (!ldev)
|
||||
break;
|
||||
if (ignore)
|
||||
continue;
|
||||
|
||||
next = ldev;
|
||||
niter = &ldev->adj_list.lower;
|
||||
dev_stack[cur] = now;
|
||||
iter_stack[cur++] = iter;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!next) {
|
||||
if (!cur)
|
||||
return 0;
|
||||
next = dev_stack[--cur];
|
||||
niter = iter_stack[cur];
|
||||
}
|
||||
|
||||
now = next;
|
||||
iter = niter;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
|
||||
struct list_head **iter)
|
||||
{
|
||||
@@ -7049,28 +7166,99 @@ static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
|
||||
return lower->dev;
|
||||
}
|
||||
|
||||
static u8 __netdev_upper_depth(struct net_device *dev)
|
||||
{
|
||||
struct net_device *udev;
|
||||
struct list_head *iter;
|
||||
u8 max_depth = 0;
|
||||
bool ignore;
|
||||
|
||||
for (iter = &dev->adj_list.upper,
|
||||
udev = __netdev_next_upper_dev(dev, &iter, &ignore);
|
||||
udev;
|
||||
udev = __netdev_next_upper_dev(dev, &iter, &ignore)) {
|
||||
if (ignore)
|
||||
continue;
|
||||
if (max_depth < udev->upper_level)
|
||||
max_depth = udev->upper_level;
|
||||
}
|
||||
|
||||
return max_depth;
|
||||
}
|
||||
|
||||
static u8 __netdev_lower_depth(struct net_device *dev)
|
||||
{
|
||||
struct net_device *ldev;
|
||||
struct list_head *iter;
|
||||
u8 max_depth = 0;
|
||||
bool ignore;
|
||||
|
||||
for (iter = &dev->adj_list.lower,
|
||||
ldev = __netdev_next_lower_dev(dev, &iter, &ignore);
|
||||
ldev;
|
||||
ldev = __netdev_next_lower_dev(dev, &iter, &ignore)) {
|
||||
if (ignore)
|
||||
continue;
|
||||
if (max_depth < ldev->lower_level)
|
||||
max_depth = ldev->lower_level;
|
||||
}
|
||||
|
||||
return max_depth;
|
||||
}
|
||||
|
||||
static int __netdev_update_upper_level(struct net_device *dev, void *data)
|
||||
{
|
||||
dev->upper_level = __netdev_upper_depth(dev) + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __netdev_update_lower_level(struct net_device *dev, void *data)
|
||||
{
|
||||
dev->lower_level = __netdev_lower_depth(dev) + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int netdev_walk_all_lower_dev_rcu(struct net_device *dev,
|
||||
int (*fn)(struct net_device *dev,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct net_device *ldev;
|
||||
struct list_head *iter;
|
||||
int ret;
|
||||
struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
|
||||
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
|
||||
int ret, cur = 0;
|
||||
|
||||
for (iter = &dev->adj_list.lower,
|
||||
ldev = netdev_next_lower_dev_rcu(dev, &iter);
|
||||
ldev;
|
||||
ldev = netdev_next_lower_dev_rcu(dev, &iter)) {
|
||||
/* first is the lower device itself */
|
||||
ret = fn(ldev, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
now = dev;
|
||||
iter = &dev->adj_list.lower;
|
||||
|
||||
/* then look at all of its lower devices */
|
||||
ret = netdev_walk_all_lower_dev_rcu(ldev, fn, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
while (1) {
|
||||
if (now != dev) {
|
||||
ret = fn(now, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
next = NULL;
|
||||
while (1) {
|
||||
ldev = netdev_next_lower_dev_rcu(now, &iter);
|
||||
if (!ldev)
|
||||
break;
|
||||
|
||||
next = ldev;
|
||||
niter = &ldev->adj_list.lower;
|
||||
dev_stack[cur] = now;
|
||||
iter_stack[cur++] = iter;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!next) {
|
||||
if (!cur)
|
||||
return 0;
|
||||
next = dev_stack[--cur];
|
||||
niter = iter_stack[cur];
|
||||
}
|
||||
|
||||
now = next;
|
||||
iter = niter;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -7174,6 +7362,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
|
||||
adj->master = master;
|
||||
adj->ref_nr = 1;
|
||||
adj->private = private;
|
||||
adj->ignore = false;
|
||||
dev_hold(adj_dev);
|
||||
|
||||
pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n",
|
||||
@@ -7324,14 +7513,17 @@ static int __netdev_upper_dev_link(struct net_device *dev,
|
||||
return -EBUSY;
|
||||
|
||||
/* To prevent loops, check if dev is not upper device to upper_dev. */
|
||||
if (netdev_has_upper_dev(upper_dev, dev))
|
||||
if (__netdev_has_upper_dev(upper_dev, dev))
|
||||
return -EBUSY;
|
||||
|
||||
if ((dev->lower_level + upper_dev->upper_level) > MAX_NEST_DEV)
|
||||
return -EMLINK;
|
||||
|
||||
if (!master) {
|
||||
if (netdev_has_upper_dev(dev, upper_dev))
|
||||
if (__netdev_has_upper_dev(dev, upper_dev))
|
||||
return -EEXIST;
|
||||
} else {
|
||||
master_dev = netdev_master_upper_dev_get(dev);
|
||||
master_dev = __netdev_master_upper_dev_get(dev);
|
||||
if (master_dev)
|
||||
return master_dev == upper_dev ? -EEXIST : -EBUSY;
|
||||
}
|
||||
@@ -7353,6 +7545,13 @@ static int __netdev_upper_dev_link(struct net_device *dev,
|
||||
if (ret)
|
||||
goto rollback;
|
||||
|
||||
__netdev_update_upper_level(dev, NULL);
|
||||
__netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
|
||||
|
||||
__netdev_update_lower_level(upper_dev, NULL);
|
||||
__netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level,
|
||||
NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
@@ -7435,9 +7634,96 @@ void netdev_upper_dev_unlink(struct net_device *dev,
|
||||
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
|
||||
&changeupper_info.info);
|
||||
|
||||
__netdev_update_upper_level(dev, NULL);
|
||||
__netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL);
|
||||
|
||||
__netdev_update_lower_level(upper_dev, NULL);
|
||||
__netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level,
|
||||
NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_upper_dev_unlink);
|
||||
|
||||
static void __netdev_adjacent_dev_set(struct net_device *upper_dev,
|
||||
struct net_device *lower_dev,
|
||||
bool val)
|
||||
{
|
||||
struct netdev_adjacent *adj;
|
||||
|
||||
adj = __netdev_find_adj(lower_dev, &upper_dev->adj_list.lower);
|
||||
if (adj)
|
||||
adj->ignore = val;
|
||||
|
||||
adj = __netdev_find_adj(upper_dev, &lower_dev->adj_list.upper);
|
||||
if (adj)
|
||||
adj->ignore = val;
|
||||
}
|
||||
|
||||
static void netdev_adjacent_dev_disable(struct net_device *upper_dev,
|
||||
struct net_device *lower_dev)
|
||||
{
|
||||
__netdev_adjacent_dev_set(upper_dev, lower_dev, true);
|
||||
}
|
||||
|
||||
static void netdev_adjacent_dev_enable(struct net_device *upper_dev,
|
||||
struct net_device *lower_dev)
|
||||
{
|
||||
__netdev_adjacent_dev_set(upper_dev, lower_dev, false);
|
||||
}
|
||||
|
||||
int netdev_adjacent_change_prepare(struct net_device *old_dev,
|
||||
struct net_device *new_dev,
|
||||
struct net_device *dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!new_dev)
|
||||
return 0;
|
||||
|
||||
if (old_dev && new_dev != old_dev)
|
||||
netdev_adjacent_dev_disable(dev, old_dev);
|
||||
|
||||
err = netdev_upper_dev_link(new_dev, dev, extack);
|
||||
if (err) {
|
||||
if (old_dev && new_dev != old_dev)
|
||||
netdev_adjacent_dev_enable(dev, old_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_adjacent_change_prepare);
|
||||
|
||||
void netdev_adjacent_change_commit(struct net_device *old_dev,
|
||||
struct net_device *new_dev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
if (!new_dev || !old_dev)
|
||||
return;
|
||||
|
||||
if (new_dev == old_dev)
|
||||
return;
|
||||
|
||||
netdev_adjacent_dev_enable(dev, old_dev);
|
||||
netdev_upper_dev_unlink(old_dev, dev);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_adjacent_change_commit);
|
||||
|
||||
void netdev_adjacent_change_abort(struct net_device *old_dev,
|
||||
struct net_device *new_dev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
if (!new_dev)
|
||||
return;
|
||||
|
||||
if (old_dev && new_dev != old_dev)
|
||||
netdev_adjacent_dev_enable(dev, old_dev);
|
||||
|
||||
netdev_upper_dev_unlink(new_dev, dev);
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_adjacent_change_abort);
|
||||
|
||||
/**
|
||||
* netdev_bonding_info_change - Dispatch event about slave change
|
||||
* @dev: device
|
||||
@@ -7551,25 +7837,6 @@ void *netdev_lower_dev_get_private(struct net_device *dev,
|
||||
EXPORT_SYMBOL(netdev_lower_dev_get_private);
|
||||
|
||||
|
||||
int dev_get_nest_level(struct net_device *dev)
|
||||
{
|
||||
struct net_device *lower = NULL;
|
||||
struct list_head *iter;
|
||||
int max_nest = -1;
|
||||
int nest;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
netdev_for_each_lower_dev(dev, lower, iter) {
|
||||
nest = dev_get_nest_level(lower);
|
||||
if (max_nest < nest)
|
||||
max_nest = nest;
|
||||
}
|
||||
|
||||
return max_nest + 1;
|
||||
}
|
||||
EXPORT_SYMBOL(dev_get_nest_level);
|
||||
|
||||
/**
|
||||
* netdev_lower_change - Dispatch event about lower device state change
|
||||
* @lower_dev: device
|
||||
@@ -8376,7 +8643,8 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (prog->aux->id == prog_id) {
|
||||
/* prog->aux->id may be 0 for orphaned device-bound progs */
|
||||
if (prog->aux->id && prog->aux->id == prog_id) {
|
||||
bpf_prog_put(prog);
|
||||
return 0;
|
||||
}
|
||||
@@ -8844,7 +9112,7 @@ static void netdev_init_one_queue(struct net_device *dev,
|
||||
{
|
||||
/* Initialize queue lock */
|
||||
spin_lock_init(&queue->_xmit_lock);
|
||||
netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type);
|
||||
lockdep_set_class(&queue->_xmit_lock, &dev->qdisc_xmit_lock_key);
|
||||
queue->xmit_lock_owner = -1;
|
||||
netdev_queue_numa_node_write(queue, NUMA_NO_NODE);
|
||||
queue->dev = dev;
|
||||
@@ -8891,6 +9159,43 @@ void netif_tx_stop_all_queues(struct net_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(netif_tx_stop_all_queues);
|
||||
|
||||
static void netdev_register_lockdep_key(struct net_device *dev)
|
||||
{
|
||||
lockdep_register_key(&dev->qdisc_tx_busylock_key);
|
||||
lockdep_register_key(&dev->qdisc_running_key);
|
||||
lockdep_register_key(&dev->qdisc_xmit_lock_key);
|
||||
lockdep_register_key(&dev->addr_list_lock_key);
|
||||
}
|
||||
|
||||
static void netdev_unregister_lockdep_key(struct net_device *dev)
|
||||
{
|
||||
lockdep_unregister_key(&dev->qdisc_tx_busylock_key);
|
||||
lockdep_unregister_key(&dev->qdisc_running_key);
|
||||
lockdep_unregister_key(&dev->qdisc_xmit_lock_key);
|
||||
lockdep_unregister_key(&dev->addr_list_lock_key);
|
||||
}
|
||||
|
||||
void netdev_update_lockdep_key(struct net_device *dev)
|
||||
{
|
||||
struct netdev_queue *queue;
|
||||
int i;
|
||||
|
||||
lockdep_unregister_key(&dev->qdisc_xmit_lock_key);
|
||||
lockdep_unregister_key(&dev->addr_list_lock_key);
|
||||
|
||||
lockdep_register_key(&dev->qdisc_xmit_lock_key);
|
||||
lockdep_register_key(&dev->addr_list_lock_key);
|
||||
|
||||
lockdep_set_class(&dev->addr_list_lock, &dev->addr_list_lock_key);
|
||||
for (i = 0; i < dev->num_tx_queues; i++) {
|
||||
queue = netdev_get_tx_queue(dev, i);
|
||||
|
||||
lockdep_set_class(&queue->_xmit_lock,
|
||||
&dev->qdisc_xmit_lock_key);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_update_lockdep_key);
|
||||
|
||||
/**
|
||||
* register_netdevice - register a network device
|
||||
* @dev: device to register
|
||||
@@ -8925,7 +9230,7 @@ int register_netdevice(struct net_device *dev)
|
||||
BUG_ON(!net);
|
||||
|
||||
spin_lock_init(&dev->addr_list_lock);
|
||||
netdev_set_addr_lockdep_class(dev);
|
||||
lockdep_set_class(&dev->addr_list_lock, &dev->addr_list_lock_key);
|
||||
|
||||
ret = dev_get_valid_name(net, dev, dev->name);
|
||||
if (ret < 0)
|
||||
@@ -9442,8 +9747,12 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
|
||||
|
||||
dev_net_set(dev, &init_net);
|
||||
|
||||
netdev_register_lockdep_key(dev);
|
||||
|
||||
dev->gso_max_size = GSO_MAX_SIZE;
|
||||
dev->gso_max_segs = GSO_MAX_SEGS;
|
||||
dev->upper_level = 1;
|
||||
dev->lower_level = 1;
|
||||
|
||||
INIT_LIST_HEAD(&dev->napi_list);
|
||||
INIT_LIST_HEAD(&dev->unreg_list);
|
||||
@@ -9524,6 +9833,8 @@ void free_netdev(struct net_device *dev)
|
||||
free_percpu(dev->pcpu_refcnt);
|
||||
dev->pcpu_refcnt = NULL;
|
||||
|
||||
netdev_unregister_lockdep_key(dev);
|
||||
|
||||
/* Compatibility with error handling in drivers */
|
||||
if (dev->reg_state == NETREG_UNINITIALIZED) {
|
||||
netdev_freemem(dev);
|
||||
@@ -9692,7 +10003,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
|
||||
call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
|
||||
rcu_barrier();
|
||||
|
||||
new_nsid = peernet2id_alloc(dev_net(dev), net);
|
||||
new_nsid = peernet2id_alloc(dev_net(dev), net, GFP_KERNEL);
|
||||
/* If there is an ifindex conflict assign a new one */
|
||||
if (__dev_get_by_index(net, dev->ifindex))
|
||||
new_ifindex = dev_new_index(net);
|
||||
|
Reference in New Issue
Block a user