summaryrefslogtreecommitdiff
path: root/debian/patches/libdde_ucast_list.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/libdde_ucast_list.patch')
-rw-r--r--debian/patches/libdde_ucast_list.patch488
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);