The following commit has been merged in the master branch: commit 9c6bc16577171100e5efab0ea09ebf5884822ed6 Merge: 03746b0a02d25866a29cd8d7306d221c238d6397 af20b710479ae662829cf739b521390daa7fcbcb Author: David S. Miller davem@davemloft.net Date: Sun Apr 17 17:37:29 2011 -0700
Merge branch 'batman-adv/next' of git://git.open-mesh.org/ecsv/linux-merge
diff --combined net/batman-adv/soft-interface.c index 824e1f6,58ce440..1f6f756 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@@ -90,10 -90,51 +90,51 @@@ static void softif_neigh_free_ref(struc call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); }
+ static struct softif_neigh *softif_neigh_get_selected(struct bat_priv *bat_priv) + { + struct softif_neigh *neigh; + + rcu_read_lock(); + neigh = rcu_dereference(bat_priv->softif_neigh); + + if (neigh && !atomic_inc_not_zero(&neigh->refcount)) + neigh = NULL; + + rcu_read_unlock(); + return neigh; + } + + static void softif_neigh_select(struct bat_priv *bat_priv, + struct softif_neigh *new_neigh) + { + struct softif_neigh *curr_neigh; + + spin_lock_bh(&bat_priv->softif_neigh_lock); + + if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount)) + new_neigh = NULL; + + curr_neigh = bat_priv->softif_neigh; + rcu_assign_pointer(bat_priv->softif_neigh, new_neigh); + + if (curr_neigh) + softif_neigh_free_ref(curr_neigh); + + spin_unlock_bh(&bat_priv->softif_neigh_lock); + } + + static void softif_neigh_deselect(struct bat_priv *bat_priv) + { + softif_neigh_select(bat_priv, NULL); + } + void softif_neigh_purge(struct bat_priv *bat_priv) { - struct softif_neigh *softif_neigh, *softif_neigh_tmp; + struct softif_neigh *softif_neigh, *curr_softif_neigh; struct hlist_node *node, *node_tmp; + char do_deselect = 0; + + curr_softif_neigh = softif_neigh_get_selected(bat_priv);
spin_lock_bh(&bat_priv->softif_neigh_lock);
@@@ -105,22 -146,26 +146,26 @@@ (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) continue;
- hlist_del_rcu(&softif_neigh->list); - - if (bat_priv->softif_neigh == softif_neigh) { + if (curr_softif_neigh == softif_neigh) { bat_dbg(DBG_ROUTES, bat_priv, "Current mesh exit point '%pM' vanished " "(vid: %d).\n", softif_neigh->addr, softif_neigh->vid); - softif_neigh_tmp = bat_priv->softif_neigh; - bat_priv->softif_neigh = NULL; - softif_neigh_free_ref(softif_neigh_tmp); + do_deselect = 1; }
+ hlist_del_rcu(&softif_neigh->list); softif_neigh_free_ref(softif_neigh); }
spin_unlock_bh(&bat_priv->softif_neigh_lock); + + /* soft_neigh_deselect() needs to acquire the softif_neigh_lock */ + if (do_deselect) + softif_neigh_deselect(bat_priv); + + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); }
static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, @@@ -171,6 -216,7 +216,7 @@@ int softif_neigh_seq_print_text(struct struct bat_priv *bat_priv = netdev_priv(net_dev); struct softif_neigh *softif_neigh; struct hlist_node *node; + struct softif_neigh *curr_softif_neigh;
if (!bat_priv->primary_if) { return seq_printf(seq, "BATMAN mesh %s disabled - " @@@ -180,14 -226,17 +226,17 @@@
seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
+ curr_softif_neigh = softif_neigh_get_selected(bat_priv); rcu_read_lock(); hlist_for_each_entry_rcu(softif_neigh, node, &bat_priv->softif_neigh_list, list) seq_printf(seq, "%s %pM (vid: %d)\n", - bat_priv->softif_neigh == softif_neigh + curr_softif_neigh == softif_neigh ? "=>" : " ", softif_neigh->addr, softif_neigh->vid); rcu_read_unlock(); + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh);
return 0; } @@@ -198,7 -247,8 +247,8 @@@ static void softif_batman_recv(struct s struct bat_priv *bat_priv = netdev_priv(dev); struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct batman_packet *batman_packet; - struct softif_neigh *softif_neigh, *softif_neigh_tmp; + struct softif_neigh *softif_neigh; + struct softif_neigh *curr_softif_neigh = NULL;
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) batman_packet = (struct batman_packet *) @@@ -223,7 -273,8 +273,8 @@@ if (!softif_neigh) goto err;
- if (bat_priv->softif_neigh == softif_neigh) + curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if (curr_softif_neigh == softif_neigh) goto out;
/* we got a neighbor but its mac is 'bigger' than ours */ @@@ -232,38 -283,39 +283,39 @@@ goto out;
/* switch to new 'smallest neighbor' */ - if ((bat_priv->softif_neigh) && - (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, + if ((curr_softif_neigh) && + (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0)) { bat_dbg(DBG_ROUTES, bat_priv, "Changing mesh exit point from %pM (vid: %d) " "to %pM (vid: %d).\n", - bat_priv->softif_neigh->addr, - bat_priv->softif_neigh->vid, + curr_softif_neigh->addr, + curr_softif_neigh->vid, softif_neigh->addr, softif_neigh->vid); - softif_neigh_tmp = bat_priv->softif_neigh; - bat_priv->softif_neigh = softif_neigh; - softif_neigh_free_ref(softif_neigh_tmp); - /* we need to hold the additional reference */ - goto err; + + softif_neigh_select(bat_priv, softif_neigh); + goto out; }
/* close own batX device and use softif_neigh as exit node */ - if ((!bat_priv->softif_neigh) && + if ((!curr_softif_neigh) && (memcmp(softif_neigh->addr, bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { bat_dbg(DBG_ROUTES, bat_priv, "Setting mesh exit point to %pM (vid: %d).\n", softif_neigh->addr, softif_neigh->vid); - bat_priv->softif_neigh = softif_neigh; - /* we need to hold the additional reference */ - goto err; + + softif_neigh_select(bat_priv, softif_neigh); + goto out; }
out: softif_neigh_free_ref(softif_neigh); err: kfree_skb(skb); + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); + return; }
@@@ -321,6 -373,7 +373,7 @@@ int interface_tx(struct sk_buff *skb, s struct bat_priv *bat_priv = netdev_priv(soft_iface); struct bcast_packet *bcast_packet; struct vlan_ethhdr *vhdr; + struct softif_neigh *curr_softif_neigh = NULL; int data_len = skb->len, ret; short vid = -1; bool do_bcast = false; @@@ -348,7 -401,8 +401,8 @@@ * if we have a another chosen mesh exit node in range * it will transport the packets to the mesh */ - if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) + curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if ((curr_softif_neigh) && (curr_softif_neigh->vid == vid)) goto dropped;
/* TODO: check this for locks */ @@@ -410,6 -464,8 +464,8 @@@ dropped dropped_freed: bat_priv->stats.tx_dropped++; end: + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); return NETDEV_TX_OK; }
@@@ -421,6 -477,7 +477,7 @@@ void interface_rx(struct net_device *so struct unicast_packet *unicast_packet; struct ethhdr *ethhdr; struct vlan_ethhdr *vhdr; + struct softif_neigh *curr_softif_neigh = NULL; short vid = -1; int ret;
@@@ -450,7 -507,8 +507,8 @@@ * if we have a another chosen mesh exit node in range * it will transport the packets to the non-mesh network */ - if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { + curr_softif_neigh = softif_neigh_get_selected(bat_priv); + if (curr_softif_neigh && (curr_softif_neigh->vid == vid)) { skb_push(skb, hdr_size); unicast_packet = (struct unicast_packet *)skb->data;
@@@ -461,7 -519,7 +519,7 @@@ skb_reset_mac_header(skb);
memcpy(unicast_packet->dest, - bat_priv->softif_neigh->addr, ETH_ALEN); + curr_softif_neigh->addr, ETH_ALEN); ret = route_unicast_packet(skb, recv_if); if (ret == NET_RX_DROP) goto dropped; @@@ -474,7 -532,7 +532,7 @@@ goto dropped; skb->protocol = eth_type_trans(skb, soft_iface);
- /* should not be neccesary anymore as we use skb_pull_rcsum() + /* should not be necessary anymore as we use skb_pull_rcsum() * TODO: please verify this and remove this TODO * -- Dec 21st 2009, Simon Wunderlich */
@@@ -486,11 -544,13 +544,13 @@@ soft_iface->last_rx = jiffies;
netif_rx(skb); - return; + goto out;
dropped: kfree_skb(skb); out: + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); return; }
@@@ -524,6 -584,7 +584,7 @@@ static void interface_setup(struct net_ dev->hard_start_xmit = interface_tx; #endif dev->destructor = free_netdev; + dev->tx_queue_len = 0;
/** * can't call min_mtu, because the needed variables