diff options
Diffstat (limited to 'debian/patches/libdde_ucast_list.patch')
-rw-r--r-- | debian/patches/libdde_ucast_list.patch | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/debian/patches/libdde_ucast_list.patch b/debian/patches/libdde_ucast_list.patch new file mode 100644 index 00000000..5abd3443 --- /dev/null +++ b/debian/patches/libdde_ucast_list.patch @@ -0,0 +1,488 @@ +commit ccffad25b5136958d4769ed6de5e87992dd9c65c +Author: Jiri Pirko <jpirko@redhat.com> +Date: Fri May 22 23:22:17 2009 +0000 + + net: convert unicast addr list + + This patch converts unicast address list to standard list_head using + previously introduced struct netdev_hw_addr. It also relaxes the + locking. Original spinlock (still used for multicast addresses) is not + needed and is no longer used for a protection of this list. All + reading and writing takes place under rtnl (with no changes). + + I also removed a possibility to specify the length of the address + while adding or deleting unicast address. It's always dev->addr_len. + + The convertion touched especially e1000 and ixgbe codes when the + change is not so trivial. + + Signed-off-by: Jiri Pirko <jpirko@redhat.com> + + drivers/net/bnx2.c | 13 +-- + drivers/net/e1000/e1000_main.c | 24 +++-- + drivers/net/ixgbe/ixgbe_common.c | 14 ++-- + drivers/net/ixgbe/ixgbe_common.h | 4 +- + drivers/net/ixgbe/ixgbe_main.c | 6 +- + drivers/net/ixgbe/ixgbe_type.h | 4 +- + drivers/net/macvlan.c | 11 +- + drivers/net/mv643xx_eth.c | 11 +- + drivers/net/niu.c | 7 +- + drivers/net/virtio_net.c | 7 +- + drivers/s390/net/qeth_l2_main.c | 6 +- + drivers/scsi/fcoe/fcoe.c | 16 ++-- + include/linux/netdevice.h | 18 ++-- + net/8021q/vlan.c | 4 +- + net/8021q/vlan_dev.c | 10 +- + net/core/dev.c | 195 +++++++++++++++++++++++++++----------- + net/dsa/slave.c | 10 +- + net/packet/af_packet.c | 4 +- + 18 files changed, 227 insertions(+), 137 deletions(-) + Signed-off-by: David S. Miller <davem@davemloft.net> + +Index: hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h +=================================================================== +--- hurd-debian.orig/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:34:43.000000000 +0000 ++++ hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:34:46.000000000 +0000 +@@ -215,9 +215,12 @@ + struct list_head list; + unsigned char addr[MAX_ADDR_LEN]; + unsigned char type; +-#define NETDEV_HW_ADDR_T_LAN 1 +-#define NETDEV_HW_ADDR_T_SAN 2 +-#define NETDEV_HW_ADDR_T_SLAVE 3 ++#define NETDEV_HW_ADDR_T_LAN 1 ++#define NETDEV_HW_ADDR_T_SAN 2 ++#define NETDEV_HW_ADDR_T_SLAVE 3 ++#define NETDEV_HW_ADDR_T_UNICAST 4 ++ int refcount; ++ bool synced; + struct rcu_head rcu_head; + }; + +@@ -738,10 +741,11 @@ + unsigned char addr_len; /* hardware address length */ + unsigned short dev_id; /* for shared network cards */ + +- spinlock_t addr_list_lock; +- struct dev_addr_list *uc_list; /* Secondary unicast mac addresses */ ++ struct list_head uc_list; /* Secondary unicast mac ++ addresses */ + int uc_count; /* Number of installed ucasts */ + int uc_promisc; ++ spinlock_t addr_list_lock; + struct dev_addr_list *mc_list; /* Multicast mac addresses */ + int mc_count; /* Number of installed mcasts */ + unsigned int promiscuity; +@@ -1816,8 +1820,8 @@ + /* Functions used for secondary unicast and multicast support */ + extern void dev_set_rx_mode(struct net_device *dev); + extern void __dev_set_rx_mode(struct net_device *dev); +-extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen); +-extern int dev_unicast_add(struct net_device *dev, void *addr, int alen); ++extern int dev_unicast_delete(struct net_device *dev, void *addr); ++extern int dev_unicast_add(struct net_device *dev, void *addr); + extern int dev_unicast_sync(struct net_device *to, struct net_device *from); + extern void dev_unicast_unsync(struct net_device *to, struct net_device *from); + extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all); +Index: hurd-debian/libdde_linux26/lib/src/net/core/dev.c +=================================================================== +--- hurd-debian.orig/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:34:43.000000000 +0000 ++++ hurd-debian/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:34:46.000000000 +0000 +@@ -3399,8 +3399,9 @@ + + /* hw addresses list handling functions */ + +-static int __hw_addr_add(struct list_head *list, unsigned char *addr, +- int addr_len, unsigned char addr_type) ++static int __hw_addr_add(struct list_head *list, int *delta, ++ unsigned char *addr, int addr_len, ++ unsigned char addr_type) + { + struct netdev_hw_addr *ha; + int alloc_size; +@@ -3408,6 +3409,15 @@ + if (addr_len > MAX_ADDR_LEN) + return -EINVAL; + ++ list_for_each_entry(ha, list, list) { ++ if (!memcmp(ha->addr, addr, addr_len) && ++ ha->type == addr_type) { ++ ha->refcount++; ++ return 0; ++ } ++ } ++ ++ + alloc_size = sizeof(*ha); + if (alloc_size < L1_CACHE_BYTES) + alloc_size = L1_CACHE_BYTES; +@@ -3416,7 +3426,11 @@ + return -ENOMEM; + memcpy(ha->addr, addr, addr_len); + ha->type = addr_type; ++ ha->refcount = 1; ++ ha->synced = false; + list_add_tail_rcu(&ha->list, list); ++ if (delta) ++ (*delta)++; + return 0; + } + +@@ -3428,29 +3442,30 @@ + kfree(ha); + } + +-static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr, +- int addr_len, unsigned char addr_type, +- int ignore_index) ++static int __hw_addr_del(struct list_head *list, int *delta, ++ unsigned char *addr, int addr_len, ++ unsigned char addr_type) + { + struct netdev_hw_addr *ha; +- int i = 0; + + list_for_each_entry(ha, list, list) { +- if (i++ != ignore_index && +- !memcmp(ha->addr, addr, addr_len) && ++ if (!memcmp(ha->addr, addr, addr_len) && + (ha->type == addr_type || !addr_type)) { ++ if (--ha->refcount) ++ return 0; + list_del_rcu(&ha->list); + call_rcu(&ha->rcu_head, ha_rcu_free); ++ if (delta) ++ (*delta)--; + return 0; + } + } + return -ENOENT; + } + +-static int __hw_addr_add_multiple_ii(struct list_head *to_list, +- struct list_head *from_list, +- int addr_len, unsigned char addr_type, +- int ignore_index) ++static int __hw_addr_add_multiple(struct list_head *to_list, int *to_delta, ++ struct list_head *from_list, int addr_len, ++ unsigned char addr_type) + { + int err; + struct netdev_hw_addr *ha, *ha2; +@@ -3458,7 +3473,8 @@ + + list_for_each_entry(ha, from_list, list) { + type = addr_type ? addr_type : ha->type; +- err = __hw_addr_add(to_list, ha->addr, addr_len, type); ++ err = __hw_addr_add(to_list, to_delta, ha->addr, ++ addr_len, type); + if (err) + goto unroll; + } +@@ -3469,27 +3485,69 @@ + if (ha2 == ha) + break; + type = addr_type ? addr_type : ha2->type; +- __hw_addr_del_ii(to_list, ha2->addr, addr_len, type, +- ignore_index); ++ __hw_addr_del(to_list, to_delta, ha2->addr, ++ addr_len, type); + } + return err; + } + +-static void __hw_addr_del_multiple_ii(struct list_head *to_list, +- struct list_head *from_list, +- int addr_len, unsigned char addr_type, +- int ignore_index) ++static void __hw_addr_del_multiple(struct list_head *to_list, int *to_delta, ++ struct list_head *from_list, int addr_len, ++ unsigned char addr_type) + { + struct netdev_hw_addr *ha; + unsigned char type; + + list_for_each_entry(ha, from_list, list) { + type = addr_type ? addr_type : ha->type; +- __hw_addr_del_ii(to_list, ha->addr, addr_len, addr_type, +- ignore_index); ++ __hw_addr_del(to_list, to_delta, ha->addr, ++ addr_len, addr_type); + } + } + ++static int __hw_addr_sync(struct list_head *to_list, int *to_delta, ++ struct list_head *from_list, int *from_delta, ++ int addr_len) ++{ ++ int err = 0; ++ struct netdev_hw_addr *ha, *tmp; ++ ++ list_for_each_entry_safe(ha, tmp, from_list, list) { ++ if (!ha->synced) { ++ err = __hw_addr_add(to_list, to_delta, ha->addr, ++ addr_len, ha->type); ++ if (err) ++ break; ++ ha->synced = true; ++ ha->refcount++; ++ } else if (ha->refcount == 1) { ++ __hw_addr_del(to_list, to_delta, ha->addr, ++ addr_len, ha->type); ++ __hw_addr_del(from_list, from_delta, ha->addr, ++ addr_len, ha->type); ++ } ++ } ++ return err; ++} ++ ++static void __hw_addr_unsync(struct list_head *to_list, int *to_delta, ++ struct list_head *from_list, int *from_delta, ++ int addr_len) ++{ ++ struct netdev_hw_addr *ha, *tmp; ++ ++ list_for_each_entry_safe(ha, tmp, from_list, list) { ++ if (ha->synced) { ++ __hw_addr_del(to_list, to_delta, ha->addr, ++ addr_len, ha->type); ++ ha->synced = false; ++ __hw_addr_del(from_list, from_delta, ha->addr, ++ addr_len, ha->type); ++ } ++ } ++} ++ ++ + static void __hw_addr_flush(struct list_head *list) + { + struct netdev_hw_addr *ha, *tmp; +@@ -3520,7 +3578,7 @@ + + INIT_LIST_HEAD(&dev->dev_addr_list); + memset(addr, 0, sizeof(*addr)); +- err = __hw_addr_add(&dev->dev_addr_list, addr, sizeof(*addr), ++ err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, sizeof(*addr), + NETDEV_HW_ADDR_T_LAN); + if (!err) { + /* +@@ -3552,7 +3610,7 @@ + + ASSERT_RTNL(); + +- err = __hw_addr_add(&dev->dev_addr_list, addr, dev->addr_len, ++ err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, dev->addr_len, + addr_type); + if (!err) + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); +@@ -3575,11 +3633,20 @@ + unsigned char addr_type) + { + int err; ++ struct netdev_hw_addr *ha; + + ASSERT_RTNL(); + +- err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len, +- addr_type, 0); ++ /* ++ * We can not remove the first address from the list because ++ * dev->dev_addr points to that. ++ */ ++ ha = list_first_entry(&dev->dev_addr_list, struct netdev_hw_addr, list); ++ if (ha->addr == dev->dev_addr && ha->refcount == 1) ++ return -ENOENT; ++ ++ err = __hw_addr_del(&dev->dev_addr_list, NULL, addr, dev->addr_len, ++ addr_type); + if (!err) + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + return err; +@@ -3606,9 +3673,9 @@ + + if (from_dev->addr_len != to_dev->addr_len) + return -EINVAL; +- err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list, +- &from_dev->dev_addr_list, +- to_dev->addr_len, addr_type, 0); ++ err = __hw_addr_add_multiple(&to_dev->dev_addr_list, NULL, ++ &from_dev->dev_addr_list, ++ to_dev->addr_len, addr_type); + if (!err) + call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); + return err; +@@ -3633,9 +3700,9 @@ + + if (from_dev->addr_len != to_dev->addr_len) + return -EINVAL; +- __hw_addr_del_multiple_ii(&to_dev->dev_addr_list, +- &from_dev->dev_addr_list, +- to_dev->addr_len, addr_type, 0); ++ __hw_addr_del_multiple(&to_dev->dev_addr_list, NULL, ++ &from_dev->dev_addr_list, ++ to_dev->addr_len, addr_type); + call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); + return 0; + } +@@ -3705,24 +3772,22 @@ + * dev_unicast_delete - Release secondary unicast address. + * @dev: device + * @addr: address to delete +- * @alen: length of @addr + * + * Release reference to a secondary unicast address and remove it + * from the device if the reference count drops to zero. + * + * The caller must hold the rtnl_mutex. + */ +-int dev_unicast_delete(struct net_device *dev, void *addr, int alen) ++int dev_unicast_delete(struct net_device *dev, void *addr) + { + int err; + + ASSERT_RTNL(); + +- netif_addr_lock_bh(dev); +- err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0); ++ err = __hw_addr_del(&dev->uc_list, &dev->uc_count, addr, ++ dev->addr_len, NETDEV_HW_ADDR_T_UNICAST); + if (!err) + __dev_set_rx_mode(dev); +- netif_addr_unlock_bh(dev); + return err; + } + EXPORT_SYMBOL(dev_unicast_delete); +@@ -3731,24 +3796,22 @@ + * dev_unicast_add - add a secondary unicast address + * @dev: device + * @addr: address to add +- * @alen: length of @addr + * + * Add a secondary unicast address to the device or increase + * the reference count if it already exists. + * + * The caller must hold the rtnl_mutex. + */ +-int dev_unicast_add(struct net_device *dev, void *addr, int alen) ++int dev_unicast_add(struct net_device *dev, void *addr) + { + int err; + + ASSERT_RTNL(); + +- netif_addr_lock_bh(dev); +- err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0); ++ err = __hw_addr_add(&dev->uc_list, &dev->uc_count, addr, ++ dev->addr_len, NETDEV_HW_ADDR_T_UNICAST); + if (!err) + __dev_set_rx_mode(dev); +- netif_addr_unlock_bh(dev); + return err; + } + EXPORT_SYMBOL(dev_unicast_add); +@@ -3805,8 +3868,7 @@ + * @from: source device + * + * Add newly added addresses to the destination device and release +- * addresses that have no users left. The source device must be +- * locked by netif_addr_lock_bh. ++ * addresses that have no users left. + * + * This function is intended to be called from the dev->set_rx_mode + * function of layered software devices. +@@ -3815,12 +3877,15 @@ + { + int err = 0; + +- netif_addr_lock_bh(to); +- err = __dev_addr_sync(&to->uc_list, &to->uc_count, +- &from->uc_list, &from->uc_count); ++ ASSERT_RTNL(); ++ ++ if (to->addr_len != from->addr_len) ++ return -EINVAL; ++ ++ err = __hw_addr_sync(&to->uc_list, &to->uc_count, ++ &from->uc_list, &from->uc_count, to->addr_len); + if (!err) + __dev_set_rx_mode(to); +- netif_addr_unlock_bh(to); + return err; + } + EXPORT_SYMBOL(dev_unicast_sync); +@@ -3836,18 +3901,33 @@ + */ + void dev_unicast_unsync(struct net_device *to, struct net_device *from) + { +- netif_addr_lock_bh(from); +- netif_addr_lock(to); ++ ASSERT_RTNL(); + +- __dev_addr_unsync(&to->uc_list, &to->uc_count, +- &from->uc_list, &from->uc_count); +- __dev_set_rx_mode(to); ++ if (to->addr_len != from->addr_len) ++ return; + +- netif_addr_unlock(to); +- netif_addr_unlock_bh(from); ++ __hw_addr_unsync(&to->uc_list, &to->uc_count, ++ &from->uc_list, &from->uc_count, to->addr_len); ++ __dev_set_rx_mode(to); + } + EXPORT_SYMBOL(dev_unicast_unsync); + ++static void dev_unicast_flush(struct net_device *dev) ++{ ++ /* rtnl_mutex must be held here */ ++ ++ __hw_addr_flush(&dev->uc_list); ++ dev->uc_count = 0; ++} ++ ++static void dev_unicast_init(struct net_device *dev) ++{ ++ /* rtnl_mutex must be held here */ ++ ++ INIT_LIST_HEAD(&dev->uc_list); ++} ++ ++ + static void __dev_addr_discard(struct dev_addr_list **list) + { + struct dev_addr_list *tmp; +@@ -3866,9 +3946,6 @@ + { + netif_addr_lock_bh(dev); + +- __dev_addr_discard(&dev->uc_list); +- dev->uc_count = 0; +- + __dev_addr_discard(&dev->mc_list); + dev->mc_count = 0; + +@@ -4459,6 +4536,7 @@ + /* + * Flush the unicast and multicast chains + */ ++ dev_unicast_flush(dev); + dev_addr_discard(dev); + + if (dev->netdev_ops->ndo_uninit) +@@ -4975,6 +5053,8 @@ + dev = (struct net_device *) + (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); + dev->padded = (char *)dev - (char *)p; ++ dev_unicast_init(dev); ++ + dev_net_set(dev, &init_net); + + dev->_tx = tx; +@@ -5173,6 +5253,7 @@ + /* + * Flush the unicast and multicast chains + */ ++ dev_unicast_flush(dev); + dev_addr_discard(dev); + + netdev_unregister_kobject(dev); |