vlan & net drivers: avoid a 4-order allocation]
Subsystems (5)
PATCH 1/1 vlan & net drivers: avoid a 4-order allocation]
Hello,
This patch splits the vlan_group struct into a multi-allocated struct. On x86_64, the size of the original struct is a little more than 32KB, causing a 4-order allocation, which is prune to problems caused by buddy-system external fragmentation conditions.
I couldn't just use vmalloc() because vfree() cannot be called in the softirq context of the RCU callback.
---
commit 3e6b63d0827461154066ff4c51f295bfd5006bd7
tree ccd06cfd2acd6e8f2d07dd2fa2f5cf31dc0c1011
parent 8d1117a9f5d302d8d460fbe7ef322b382e45c9ce
author Dan Aloni <[email protected]> Wed, 28 Feb 2007 14:20:36 +0200 committer Dan Aloni <[email protected]> Wed, 28 Feb 2007 14:20:36 +0200
drivers/net/8139cp.c | 3 +-- drivers/net/acenic.c | 5 +---- drivers/net/amd8111e.c | 3 +-- drivers/net/bnx2.c | 4 +--- drivers/net/bonding/bond_main.c | 14 +++++++------ drivers/net/chelsio/cxgb2.c | 3 +-- drivers/net/e1000/e1000_main.c | 13 +++++------- drivers/net/ehea/ehea_main.c | 3 +-- drivers/net/gianfar.c | 3 +-- drivers/net/ixgb/ixgb_main.c | 5 ++--- drivers/net/ns83820.c | 3 +-- drivers/net/r8169.c | 3 +-- drivers/net/s2io.c | 3 +-- drivers/net/sky2.c | 3 +-- drivers/net/starfire.c | 5 ++--- drivers/net/tg3.c | 3 +-- drivers/net/typhoon.c | 3 +-- drivers/s390/net/qeth_main.c | 25 ++++++++++++----------- include/linux/if_vlan.h | 25 ++++++++++++++++++++--- net/8021q/vlan.c | 42 ++++++++++++++++++++++++++++++--------- 20 files changed, 96 insertions(+), 75 deletions(-)
drivers/net/8139cp.c +1 -2
@@ -448,8 +448,7 @@ static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)spin_lock_irqsave (&cp->lock, flags); cp->cpcmd &= ~RxVlanOn;cpw16 (CpCmd, cp->cpcmd); -if (cp->vlgrp) - cp->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (cp->vlgrp, vid,NULL ); spin_unlock_irqrestore(&cp->lock, flags); }#endif /* CP_VLAN_TAG_USED */
drivers/net/acenic.c +1 -4
@@ -2293,10 +2293,7 @@ static void ace_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)local_irq_save (flags);ace_mask_irq (dev); - -if (ap->vlgrp) - ap->vlgrp->vlan_devices[vid] =NULL ; - +vlan_group_set_device (ap->vlgrp, vid,NULL );ace_unmask_irq (dev);local_irq_restore (flags); }
drivers/net/amd8111e.c +1 -2
@@ -1738,8 +1738,7 @@ static void amd8111e_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid {struct amd8111e_priv *lp =netdev_priv (dev);spin_lock_irq (&lp->lock); -if (lp->vlgrp) - lp->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (lp->vlgrp, vid,NULL );spin_unlock_irq (&lp->lock); }#endif
drivers/net/bnx2.c +1 -3
@@ -4470,9 +4470,7 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)struct bnx2 *bp =netdev_priv (dev);bnx2_netif_stop (bp); - -if (bp->vlgrp) - bp->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (bp->vlgrp, vid,NULL );bnx2_set_rx_mode (dev);bnx2_netif_start (bp);
drivers/net/bonding/bond_main.c +7 -7
@@ -489,9 +489,9 @@ static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid)/* Save and then restore vlan_dev in the grp array, * since the slave's driver might clear it. */ - vlan_dev = bond->vlgrp->vlan_devices[vid]; + vlan_dev =vlan_group_get_device (bond->vlgrp, vid); slave_dev->vlan_rx_kill_vid (slave_dev, vid); - bond->vlgrp->vlan_devices[vid] = vlan_dev; +vlan_group_set_device (bond->vlgrp, vid, vlan_dev); } }
@@ -551,9 +551,9 @@ static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *s/* Save and then restore vlan_dev in the grp array, * since the slave's driver might clear it. */ - vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; + vlan_dev =vlan_group_get_device (bond->vlgrp, vlan->vlan_id); slave_dev->vlan_rx_kill_vid (slave_dev, vlan->vlan_id); - bond->vlgrp->vlan_devices[vlan->vlan_id] = vlan_dev; +vlan_group_set_device (bond->vlgrp, vlan->vlan_id, vlan_dev); } unreg:
@@ -2400,7 +2400,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) vlan_id =0 ;list_for_each_entry_safe (vlan, vlan_next, &bond->vlan_list, vlan_list) { - vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; + vlan_dev =vlan_group_get_device (bond->vlgrp, vlan->vlan_id);if (vlan_dev == rt->u.dst.dev) { vlan_id = vlan->vlan_id; dprintk("basa: vlan match on %s %d\n",
@@ -2447,7 +2447,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond) }list_for_each_entry (vlan, &bond->vlan_list, vlan_list) { - vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; + vlan_dev =vlan_group_get_device (bond->vlgrp, vlan->vlan_id);if (vlan->vlan_ip) {bond_arp_send (slave->dev,ARPOP_REPLY , vlan->vlan_ip, vlan->vlan_ip, vlan->vlan_id);
@@ -3374,7 +3374,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event,list_for_each_entry_safe (vlan, vlan_next, &bond->vlan_list, vlan_list) { - vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; + vlan_dev =vlan_group_get_device (bond->vlgrp, vlan->vlan_id);if (vlan_dev == event_dev) {switch (event) {case NETDEV_UP :
drivers/net/chelsio/cxgb2.c +1 -2
@@ -919,8 +919,7 @@ static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)struct adapter *adapter = dev->priv;spin_lock_irq (&adapter->async_lock); -if (adapter->vlan_grp) - adapter->vlan_grp->vlan_devices[vid] =NULL ; +vlan_group_set_device (adapter->vlan_grp, vid,NULL ); spin_unlock_irq(&adapter->async_lock); }#endif
drivers/net/e1000/e1000_main.c +5 -8
@@ -376,7 +376,7 @@ e1000_update_mng_vlan(struct e1000_adapter *adapter)uint16_t vid = adapter->hw.mng_cookie.vlan_id;uint16_t old_vid = adapter->mng_vlan_id;if (adapter->vlgrp) { -if (!adapter->vlgrp->vlan_devices[vid]) { +if (!vlan_group_get_device (adapter->vlgrp, vid)) {if (adapter->hw.mng_cookie.status &E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT ) {e1000_vlan_rx_add_vid (netdev, vid);
@@ -386,7 +386,7 @@ e1000_update_mng_vlan(struct e1000_adapter *adapter)if ((old_vid != (uint16_t )E1000_MNG_VLAN_NONE ) && (vid != old_vid) && - !adapter->vlgrp->vlan_devices[old_vid]) + !vlan_group_get_device (adapter->vlgrp, old_vid))e1000_vlan_rx_kill_vid (netdev, old_vid); }else adapter->mng_vlan_id = vid;
@@ -1486,7 +1486,7 @@ e1000_close(struct net_device *netdev)if ((adapter->hw.mng_cookie.status &E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT ) && !(adapter->vlgrp && - adapter->vlgrp->vlan_devices[adapter->mng_vlan_id])) { +vlan_group_get_device (adapter->vlgrp, adapter->mng_vlan_id))) {e1000_vlan_rx_kill_vid (netdev, adapter->mng_vlan_id); }
@@ -5032,10 +5032,7 @@ e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)uint32_t vfta, index;e1000_irq_disable (adapter); - -if (adapter->vlgrp) - adapter->vlgrp->vlan_devices[vid] =NULL ; - +vlan_group_set_device (adapter->vlgrp, vid,NULL );e1000_irq_enable (adapter); if ((adapter->hw.mng_cookie.status &
@@ -5061,7 +5058,7 @@ e1000_restore_vlan(struct e1000_adapter *adapter)if (adapter->vlgrp) {uint16_t vid;for (vid =0 ; vid <VLAN_GROUP_ARRAY_LEN ; vid++) { -if (!adapter->vlgrp->vlan_devices[vid]) +if (!vlan_group_get_device (adapter->vlgrp, vid))continue ;e1000_vlan_rx_add_vid (adapter->netdev, vid); }
drivers/net/ehea/ehea_main.c +1 -2
@@ -1933,8 +1933,7 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)int index;u64 hret; -if (port->vgrp) - port->vgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (port->vgrp, vid,NULL ); cb1 =kzalloc (PAGE_SIZE ,GFP_KERNEL );if (!cb1) {
drivers/net/gianfar.c +1 -2
@@ -1132,8 +1132,7 @@ static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)spin_lock_irqsave (&priv->rxlock, flags); -if (priv->vlgrp) - priv->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (priv->vgrp, vid,NULL );spin_unlock_irqrestore (&priv->rxlock, flags); }
drivers/net/ixgb/ixgb_main.c +2 -3
@@ -2217,8 +2217,7 @@ ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)ixgb_irq_disable (adapter); -if (adapter->vlgrp) - adapter->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (adapter->vlgrp, vid,NULL );ixgb_irq_enable (adapter);
@@ -2238,7 +2237,7 @@ ixgb_restore_vlan(struct ixgb_adapter *adapter)if (adapter->vlgrp) {uint16_t vid;for (vid =0 ; vid <VLAN_GROUP_ARRAY_LEN ; vid++) { -if (!adapter->vlgrp->vlan_devices[vid]) +if (!vlan_group_get_device (adapter->vlgrp, vid))continue ;ixgb_vlan_rx_add_vid (adapter->netdev, vid); }
drivers/net/ns83820.c +1 -2
@@ -514,8 +514,7 @@ static void ns83820_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vidspin_lock_irq (&dev->misc_lock);spin_lock (&dev->tx_lock); -if (dev->vlgrp) - dev->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (dev->vlgrp, vid,NULL );spin_unlock (&dev->tx_lock);spin_unlock_irq (&dev->misc_lock); }
drivers/net/r8169.c +1 -2
@@ -890,8 +890,7 @@ static void rtl8169_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)unsigned long flags;spin_lock_irqsave (&tp->lock, flags); -if (tp->vlgrp) - tp->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (tp->vlgrp, vid,NULL );spin_unlock_irqrestore (&tp->lock, flags); }
drivers/net/s2io.c +1 -2
@@ -301,8 +301,7 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)unsigned long flags;spin_lock_irqsave (&nic->tx_lock, flags); -if (nic->vlgrp) - nic->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (nic->vlgrp, vid,NULL );spin_unlock_irqrestore (&nic->tx_lock, flags); }
drivers/net/sky2.c +1 -2
@@ -1000,8 +1000,7 @@ static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)sky2_write32 (hw,SK_REG (port,RX_GMF_CTRL_T ),RX_VLAN_STRIP_OFF );sky2_write32 (hw,SK_REG (port,TX_GMF_CTRL_T ),TX_VLAN_TAG_OFF ); -if (sky2->vlgrp) - sky2->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (sky2->vlgrp, vid,NULL );netif_tx_unlock_bh (dev); }
drivers/net/starfire.c +2 -3
@@ -677,8 +677,7 @@ static void netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)spin_lock (&np->lock);if (debug >1 )printk ("%s: removing vlanid %d from vlan filter\n" , dev->name, vid); -if (np->vlgrp) - np->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (np->vlgrp, vid,NULL );set_rx_mode (dev);spin_unlock (&np->lock); }
@@ -1738,7 +1737,7 @@ static void set_rx_mode(struct net_device *dev)int vlan_count =0 ;void __iomem *filter_addr = ioaddr + HashTable +8 ;for (i =0 ; i <VLAN_VID_MASK ; i++) { -if (np->vlgrp->vlan_devices[i]) { +if (vlan_group_get_device (np->vlgrp, i)) {if (vlan_count >=32 )break ;writew (cpu_to_be16 (i), filter_addr);
drivers/net/tg3.c +1 -2
@@ -9116,8 +9116,7 @@ static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)tg3_netif_stop (tp);tg3_full_lock (tp,0 ); -if (tp->vlgrp) - tp->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (tp->vlgrp, vid,NULL );tg3_full_unlock (tp);if (netif_running (dev))
drivers/net/typhoon.c +1 -2
@@ -746,8 +746,7 @@ typhoon_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) {struct typhoon *tp =netdev_priv (dev);spin_lock_bh (&tp->state_lock); -if (tp->vlgrp) - tp->vlgrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (tp->vlgrp, vid,NULL );spin_unlock_bh (&tp->state_lock); }
drivers/s390/net/qeth_main.c +13 -12
@@ -3654,7 +3654,7 @@ qeth_verify_vlan_dev(struct net_device *dev, struct qeth_card *card)return rc;for (i =0 ; i <VLAN_GROUP_ARRAY_LEN ; i++){ -if (vg->vlan_devices[i] == dev){ +if (vlan_group_get_device (vg, i) == dev){ rc =QETH_VLAN_CARD ;break ; }
@@ -5261,7 +5261,7 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid)QETH_DBF_TEXT (trace,4 ,"frvaddr4" );rcu_read_lock (); - in_dev =__in_dev_get_rcu (card->vlangrp->vlan_devices[vid]); + in_dev =__in_dev_get_rcu (vlan_group_get_device (card->vlangrp, vid));if (!in_dev) goto out;for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
@@ -5288,7 +5288,7 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid)QETH_DBF_TEXT (trace,4 ,"frvaddr6" ); - in6_dev =in6_dev_get (card->vlangrp->vlan_devices[vid]); + in6_dev =in6_dev_get (vlan_group_get_device (card->vlangrp, vid));if (!in6_dev)return ;for (ifa = in6_dev->addr_list; ifa; ifa = ifa->lst_next){
@@ -5360,7 +5360,7 @@ qeth_layer2_process_vlans(struct qeth_card *card, int clear)if (!card->vlangrp)return ;for (i =0 ; i <VLAN_GROUP_ARRAY_LEN ; i++) { -if (card->vlangrp->vlan_devices[i] ==NULL ) +if (vlan_group_get_device (card->vlangrp, i) ==NULL )continue ;if (clear)qeth_layer2_send_setdelvlan (card, i,IPA_CMD_DELVLAN );
@@ -5398,8 +5398,7 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)spin_lock_irqsave (&card->vlanlock, flags);/* unregister IP addresses of vlan device */ qeth_free_vlan_addresses (card, vid); -if (card->vlangrp) - card->vlangrp->vlan_devices[vid] =NULL ; +vlan_group_set_device (card->vlangrp, vid,NULL );spin_unlock_irqrestore (&card->vlanlock, flags);if (card->options.layer2)qeth_layer2_send_setdelvlan (card, vid,IPA_CMD_DELVLAN );
@@ -5662,10 +5661,11 @@ qeth_add_vlan_mc(struct qeth_card *card) vg = card->vlangrp;for (i =0 ; i <VLAN_GROUP_ARRAY_LEN ; i++) { -if (vg->vlan_devices[i] ==NULL || - !(vg->vlan_devices[i]->flags &IFF_UP )) +struct net_device *netdev =vlan_group_get_device (vg, i); +if (netdev ==NULL || + !(netdev->flags &IFF_UP ))continue ; - in_dev =in_dev_get (vg->vlan_devices[i]); + in_dev =in_dev_get (netdev);if (!in_dev)continue ;read_lock (&in_dev->mc_list_lock);
@@ -5749,10 +5749,11 @@ qeth_add_vlan_mc6(struct qeth_card *card) vg = card->vlangrp;for (i =0 ; i <VLAN_GROUP_ARRAY_LEN ; i++) { -if (vg->vlan_devices[i] ==NULL || - !(vg->vlan_devices[i]->flags &IFF_UP )) +struct net_device *netdev =vlan_group_get_device (vg, i); +if (netdev ==NULL || + !(netdev->flags &IFF_UP ))continue ; - in_dev =in6_dev_get (vg->vlan_devices[i]); + in_dev =in6_dev_get (netdev);if (!in_dev)continue ;read_lock (&in_dev->lock);
include/linux/if_vlan.h +22 -3
@@ -70,15 +70,34 @@ extern void vlan_ioctl_set(int (*hook)(void __user *));* depends on completely exhausting the VLAN identifier space. Thus * it gives constant time look-up, but in many cases it wastes memory. */ -#define VLAN_GROUP_ARRAY_LEN 4096 +#define VLAN_GROUP_ARRAY_LEN 4096 +#define VLAN_GROUP_ARRAY_SPLIT_PARTS 8 +#define VLAN_GROUP_ARRAY_PART_LEN (VLAN_GROUP_ARRAY_LEN/VLAN_GROUP_ARRAY_SPLIT_PARTS)struct vlan_group {int real_dev_ifindex;/* The ifindex of the ethernet(like) device the vlan is attached to. */ struct hlist_node hlist;/* linked list */ -struct net_device *vlan_devices[VLAN_GROUP_ARRAY_LEN ]; +struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS ];struct rcu_head rcu; }; +static inline struct net_device *vlan_group_get_device (struct vlan_group *vg,int vlan_id) +{ +struct net_device **array; + array = vg->vlan_devices_arrays[vlan_id /VLAN_GROUP_ARRAY_PART_LEN ]; +return array[vlan_id %VLAN_GROUP_ARRAY_PART_LEN ]; +} + +static inline void vlan_group_set_device (struct vlan_group *vg,int vlan_id, +struct net_device *dev) +{ +struct net_device **array; +if (!vg) +return ; + array = vg->vlan_devices_arrays[vlan_id /VLAN_GROUP_ARRAY_PART_LEN ]; + array[vlan_id %VLAN_GROUP_ARRAY_PART_LEN ] = dev; +} +struct vlan_priority_tci_mapping {unsigned long priority;unsigned short vlan_qos;/* This should be shifted when first set, so we only do it
@@ -160,7 +179,7 @@ static inline int __vlan_hwaccel_rx(struct sk_buff *skb,return NET_RX_DROP ; } - skb->dev = grp->vlan_devices[vlan_tag &VLAN_VID_MASK ]; + skb->dev =vlan_group_get_device (grp, vlan_tag &VLAN_VID_MASK );if (skb->dev ==NULL ) {dev_kfree_skb_any (skb);
net/8021q/vlan.c +32 -10
120 lines not on this page · raw message
Signature · 3 lines
Dan Aloni XIV LTD, http://www.xivstorage.com da-x (at) monatomic.org, dan (at) xiv.co.il
David Miller
maintainerFrom: Dan Aloni <[email protected]>
Date: Thu, 1 Mar 2007 12:02:17 +0200
Quoted 9 lines
This patch splits the
vlan_groupstruct into a multi-allocated struct. Onx86_64, the size of the original struct is a little more than 32KB, causing a 4-order allocation, which is prune to problems caused by buddy-system external fragmentation conditions.I couldn't just use
vmalloc()becausevfree()cannot be called in the softirq context of the RCU callback.Signed-off-by Dan Aloni <[email protected]>
No objections, this really needs to be fixed, applied.
Thank you.