The following commit has been merged in the master branch: commit b8cec4a415e807a2f8679efa89558a040a7003de Merge: 5e2b61f78411be25f0b84f97d5b5d312f184dfd1 e44d8fe2b5c27ecc230f886d4cc49fcbd86f87a0 Author: David S. Miller davem@davemloft.net Date: Mon Mar 7 00:37:13 2011 -0800
Merge branch 'batman-adv/next' of git://git.open-mesh.org/ecsv/linux-merge
diff --combined net/batman-adv/unicast.c index 121b11d,7238f04..19f84bd --- a/net/batman-adv/unicast.c +++ b/net/batman-adv/unicast.c @@@ -50,12 -50,12 +50,12 @@@ static struct sk_buff *frag_merge_packe skb = tfp->skb; }
+ if (skb_linearize(skb) < 0 || skb_linearize(tmp_skb) < 0) + goto err; + skb_pull(tmp_skb, sizeof(struct unicast_frag_packet)); - if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0) { - /* free buffered skb, skb will be freed later */ - kfree_skb(tfp->skb); - return NULL; - } + if (pskb_expand_head(skb, 0, tmp_skb->len, GFP_ATOMIC) < 0) + goto err;
/* move free entry to end */ tfp->skb = NULL; @@@ -70,11 -70,6 +70,11 @@@ unicast_packet->packet_type = BAT_UNICAST;
return skb; + +err: + /* free buffered skb, skb will be freed later */ + kfree_skb(tfp->skb); + return NULL; }
static void frag_create_entry(struct list_head *head, struct sk_buff *skb) @@@ -183,15 -178,10 +183,10 @@@ int frag_reassemble_skb(struct sk_buff (struct unicast_frag_packet *)skb->data;
*new_skb = NULL; - spin_lock_bh(&bat_priv->orig_hash_lock); - orig_node = ((struct orig_node *) - hash_find(bat_priv->orig_hash, compare_orig, choose_orig, - unicast_packet->orig));
- if (!orig_node) { - pr_debug("couldn't find originator in orig_hash\n"); + orig_node = orig_hash_find(bat_priv, unicast_packet->orig); + if (!orig_node) goto out; - }
orig_node->last_frag_packet = jiffies;
@@@ -215,14 -205,15 +210,15 @@@ /* if not, merge failed */ if (*new_skb) ret = NET_RX_SUCCESS; - out: - spin_unlock_bh(&bat_priv->orig_hash_lock);
+ out: + if (orig_node) + orig_node_free_ref(orig_node); return ret; }
int frag_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv, - struct batman_if *batman_if, uint8_t dstaddr[]) + struct hard_iface *hard_iface, uint8_t dstaddr[]) { struct unicast_packet tmp_uc, *unicast_packet; struct sk_buff *frag_skb; @@@ -267,12 -258,12 +263,12 @@@ frag1->flags = UNI_FRAG_HEAD | large_tail; frag2->flags = large_tail;
- seqno = atomic_add_return(2, &batman_if->frag_seqno); + seqno = atomic_add_return(2, &hard_iface->frag_seqno); frag1->seqno = htons(seqno - 1); frag2->seqno = htons(seqno);
- send_skb_packet(skb, batman_if, dstaddr); - send_skb_packet(frag_skb, batman_if, dstaddr); + send_skb_packet(skb, hard_iface, dstaddr); + send_skb_packet(frag_skb, hard_iface, dstaddr); return NET_RX_SUCCESS;
drop_frag: @@@ -286,40 -277,37 +282,37 @@@ int unicast_send_skb(struct sk_buff *sk { struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct unicast_packet *unicast_packet; - struct orig_node *orig_node = NULL; - struct batman_if *batman_if; - struct neigh_node *router; + struct orig_node *orig_node; + struct neigh_node *neigh_node; int data_len = skb->len; - uint8_t dstaddr[6]; - - spin_lock_bh(&bat_priv->orig_hash_lock); + int ret = 1;
/* get routing information */ - if (is_multicast_ether_addr(ethhdr->h_dest)) + if (is_multicast_ether_addr(ethhdr->h_dest)) { orig_node = (struct orig_node *)gw_get_selected(bat_priv); + if (orig_node) + goto find_router; + }
- /* check for hna host */ - if (!orig_node) - orig_node = transtable_search(bat_priv, ethhdr->h_dest); - - router = find_router(bat_priv, orig_node, NULL); - - if (!router) - goto unlock; - - /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ + /* check for hna host - increases orig_node refcount */ + orig_node = transtable_search(bat_priv, ethhdr->h_dest);
- batman_if = router->if_incoming; - memcpy(dstaddr, router->addr, ETH_ALEN); + find_router: + /** + * find_router(): + * - if orig_node is NULL it returns NULL + * - increases neigh_nodes refcount if found. + */ + neigh_node = find_router(bat_priv, orig_node, NULL);
- spin_unlock_bh(&bat_priv->orig_hash_lock); + if (!neigh_node) + goto out;
- if (batman_if->if_status != IF_ACTIVE) - goto dropped; + if (neigh_node->if_incoming->if_status != IF_ACTIVE) + goto out;
if (my_skb_head_push(skb, sizeof(struct unicast_packet)) < 0) - goto dropped; + goto out;
unicast_packet = (struct unicast_packet *)skb->data;
@@@ -333,18 -321,24 +326,24 @@@
if (atomic_read(&bat_priv->fragmentation) && data_len + sizeof(struct unicast_packet) > - batman_if->net_dev->mtu) { + neigh_node->if_incoming->net_dev->mtu) { /* send frag skb decreases ttl */ unicast_packet->ttl++; - return frag_send_skb(skb, bat_priv, batman_if, - dstaddr); + ret = frag_send_skb(skb, bat_priv, + neigh_node->if_incoming, neigh_node->addr); + goto out; } - send_skb_packet(skb, batman_if, dstaddr); - return 0;
- unlock: - spin_unlock_bh(&bat_priv->orig_hash_lock); - dropped: - kfree_skb(skb); - return 1; + send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr); + ret = 0; + goto out; + + out: + if (neigh_node) + neigh_node_free_ref(neigh_node); + if (orig_node) + orig_node_free_ref(orig_node); + if (ret == 1) + kfree_skb(skb); + return ret; } diff --combined net/batman-adv/vis.c index 7db9ad8,3da499b..f90212f --- a/net/batman-adv/vis.c +++ b/net/batman-adv/vis.c @@@ -64,19 -64,19 +64,20 @@@ static void free_info(struct kref *ref
spin_unlock_bh(&bat_priv->vis_list_lock); kfree_skb(info->skb_packet); + kfree(info); }
/* Compare two vis packets, used by the hashing algorithm */ - static int vis_info_cmp(void *data1, void *data2) + static int vis_info_cmp(struct hlist_node *node, void *data2) { struct vis_info *d1, *d2; struct vis_packet *p1, *p2; - d1 = data1; + + d1 = container_of(node, struct vis_info, hash_entry); d2 = data2; p1 = (struct vis_packet *)d1->skb_packet->data; p2 = (struct vis_packet *)d2->skb_packet->data; - return compare_orig(p1->vis_orig, p2->vis_orig); + return compare_eth(p1->vis_orig, p2->vis_orig); }
/* hash function to choose an entry in a hash table of given size */ @@@ -104,6 -104,34 +105,34 @@@ static int vis_info_choose(void *data, return hash % size; }
+ static struct vis_info *vis_hash_find(struct bat_priv *bat_priv, + void *data) + { + struct hashtable_t *hash = bat_priv->vis_hash; + struct hlist_head *head; + struct hlist_node *node; + struct vis_info *vis_info, *vis_info_tmp = NULL; + int index; + + if (!hash) + return NULL; + + index = vis_info_choose(data, hash->size); + head = &hash->table[index]; + + rcu_read_lock(); + hlist_for_each_entry_rcu(vis_info, node, head, hash_entry) { + if (!vis_info_cmp(node, data)) + continue; + + vis_info_tmp = vis_info; + break; + } + rcu_read_unlock(); + + return vis_info_tmp; + } + /* insert interface to the list of interfaces of one originator, if it * does not already exist in the list */ static void vis_data_insert_interface(const uint8_t *interface, @@@ -114,7 -142,7 +143,7 @@@ struct hlist_node *pos;
hlist_for_each_entry(entry, pos, if_list, list) { - if (compare_orig(entry->addr, (void *)interface)) + if (compare_eth(entry->addr, (void *)interface)) return; }
@@@ -166,7 -194,7 +195,7 @@@ static ssize_t vis_data_read_entry(cha /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */ if (primary && entry->quality == 0) return sprintf(buff, "HNA %pM, ", entry->dest); - else if (compare_orig(entry->src, src)) + else if (compare_eth(entry->src, src)) return sprintf(buff, "TQ %pM %d, ", entry->dest, entry->quality);
@@@ -175,9 -203,8 +204,8 @@@
int vis_seq_print_text(struct seq_file *seq, void *offset) { - struct hlist_node *walk; + struct hlist_node *node; struct hlist_head *head; - struct element_t *bucket; struct vis_info *info; struct vis_packet *packet; struct vis_info_entry *entries; @@@ -203,8 -230,8 +231,8 @@@ for (i = 0; i < hash->size; i++) { head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) { - info = bucket->data; + rcu_read_lock(); + hlist_for_each_entry_rcu(info, node, head, hash_entry) { packet = (struct vis_packet *)info->skb_packet->data; entries = (struct vis_info_entry *) ((char *)packet + sizeof(struct vis_packet)); @@@ -213,7 -240,7 +241,7 @@@ if (entries[j].quality == 0) continue; compare = - compare_orig(entries[j].src, packet->vis_orig); + compare_eth(entries[j].src, packet->vis_orig); vis_data_insert_interface(entries[j].src, &vis_if_list, compare); @@@ -223,7 -250,7 +251,7 @@@ buf_size += 18 + 26 * packet->entries;
/* add primary/secondary records */ - if (compare_orig(entry->addr, packet->vis_orig)) + if (compare_eth(entry->addr, packet->vis_orig)) buf_size += vis_data_count_prim_sec(&vis_if_list);
@@@ -236,6 -263,7 +264,7 @@@ kfree(entry); } } + rcu_read_unlock(); }
buff = kmalloc(buf_size, GFP_ATOMIC); @@@ -249,8 -277,8 +278,8 @@@ for (i = 0; i < hash->size; i++) { head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) { - info = bucket->data; + rcu_read_lock(); + hlist_for_each_entry_rcu(info, node, head, hash_entry) { packet = (struct vis_packet *)info->skb_packet->data; entries = (struct vis_info_entry *) ((char *)packet + sizeof(struct vis_packet)); @@@ -259,7 -287,7 +288,7 @@@ if (entries[j].quality == 0) continue; compare = - compare_orig(entries[j].src, packet->vis_orig); + compare_eth(entries[j].src, packet->vis_orig); vis_data_insert_interface(entries[j].src, &vis_if_list, compare); @@@ -269,15 -297,15 +298,15 @@@ buff_pos += sprintf(buff + buff_pos, "%pM,", entry->addr);
- for (i = 0; i < packet->entries; i++) + for (j = 0; j < packet->entries; j++) buff_pos += vis_data_read_entry( buff + buff_pos, - &entries[i], + &entries[j], entry->addr, entry->primary);
/* add primary/secondary records */ - if (compare_orig(entry->addr, packet->vis_orig)) + if (compare_eth(entry->addr, packet->vis_orig)) buff_pos += vis_data_read_prim_sec(buff + buff_pos, &vis_if_list); @@@ -291,6 -319,7 +320,7 @@@ kfree(entry); } } + rcu_read_unlock(); }
spin_unlock_bh(&bat_priv->vis_hash_lock); @@@ -345,7 -374,7 +375,7 @@@ static int recv_list_is_in(struct bat_p
spin_lock_bh(&bat_priv->vis_list_lock); list_for_each_entry(entry, recv_list, list) { - if (memcmp(entry->mac, mac, ETH_ALEN) == 0) { + if (compare_eth(entry->mac, mac)) { spin_unlock_bh(&bat_priv->vis_list_lock); return 1; } @@@ -381,8 -410,7 +411,7 @@@ static struct vis_info *add_packet(stru sizeof(struct vis_packet));
memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN); - old_info = hash_find(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, - &search_elem); + old_info = vis_hash_find(bat_priv, &search_elem); kfree_skb(search_elem.skb_packet);
if (old_info) { @@@ -442,10 -470,10 +471,10 @@@
/* try to add it */ hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, - info); + info, &info->hash_entry); if (hash_added < 0) { /* did not work (for some reason) */ - kref_put(&old_info->refcount, free_info); + kref_put(&info->refcount, free_info); info = NULL; }
@@@ -529,9 -557,8 +558,8 @@@ static int find_best_vis_server(struct struct vis_info *info) { struct hashtable_t *hash = bat_priv->orig_hash; - struct hlist_node *walk; + struct hlist_node *node; struct hlist_head *head; - struct element_t *bucket; struct orig_node *orig_node; struct vis_packet *packet; int best_tq = -1, i; @@@ -541,16 -568,17 +569,17 @@@ for (i = 0; i < hash->size; i++) { head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) { - orig_node = bucket->data; + rcu_read_lock(); + hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { if ((orig_node) && (orig_node->router) && - (orig_node->flags & VIS_SERVER) && - (orig_node->router->tq_avg > best_tq)) { + (orig_node->flags & VIS_SERVER) && + (orig_node->router->tq_avg > best_tq)) { best_tq = orig_node->router->tq_avg; memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); } } + rcu_read_unlock(); }
return best_tq; @@@ -573,9 -601,8 +602,8 @@@ static bool vis_packet_full(struct vis_ static int generate_vis_packet(struct bat_priv *bat_priv) { struct hashtable_t *hash = bat_priv->orig_hash; - struct hlist_node *walk; + struct hlist_node *node; struct hlist_head *head; - struct element_t *bucket; struct orig_node *orig_node; struct neigh_node *neigh_node; struct vis_info *info = (struct vis_info *)bat_priv->my_vis_info; @@@ -587,7 -614,6 +615,6 @@@ info->first_seen = jiffies; packet->vis_type = atomic_read(&bat_priv->vis_mode);
- spin_lock_bh(&bat_priv->orig_hash_lock); memcpy(packet->target_orig, broadcast_addr, ETH_ALEN); packet->ttl = TTL; packet->seqno = htonl(ntohl(packet->seqno) + 1); @@@ -597,23 -623,21 +624,21 @@@ if (packet->vis_type == VIS_TYPE_CLIENT_UPDATE) { best_tq = find_best_vis_server(bat_priv, info);
- if (best_tq < 0) { - spin_unlock_bh(&bat_priv->orig_hash_lock); + if (best_tq < 0) return -1; - } }
for (i = 0; i < hash->size; i++) { head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) { - orig_node = bucket->data; + rcu_read_lock(); + hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { neigh_node = orig_node->router;
if (!neigh_node) continue;
- if (!compare_orig(neigh_node->addr, orig_node->orig)) + if (!compare_eth(neigh_node->addr, orig_node->orig)) continue;
if (neigh_node->if_incoming->if_status != IF_ACTIVE) @@@ -632,23 -656,19 +657,19 @@@ entry->quality = neigh_node->tq_avg; packet->entries++;
- if (vis_packet_full(info)) { - spin_unlock_bh(&bat_priv->orig_hash_lock); - return 0; - } + if (vis_packet_full(info)) + goto unlock; } + rcu_read_unlock(); }
- spin_unlock_bh(&bat_priv->orig_hash_lock); - hash = bat_priv->hna_local_hash;
spin_lock_bh(&bat_priv->hna_lhash_lock); for (i = 0; i < hash->size; i++) { head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) { - hna_local_entry = bucket->data; + hlist_for_each_entry(hna_local_entry, node, head, hash_entry) { entry = (struct vis_info_entry *) skb_put(info->skb_packet, sizeof(*entry)); @@@ -666,6 -686,10 +687,10 @@@
spin_unlock_bh(&bat_priv->hna_lhash_lock); return 0; + + unlock: + rcu_read_unlock(); + return 0; }
/* free old vis packets. Must be called with this vis_hash_lock @@@ -674,25 -698,22 +699,22 @@@ static void purge_vis_packets(struct ba { int i; struct hashtable_t *hash = bat_priv->vis_hash; - struct hlist_node *walk, *safe; + struct hlist_node *node, *node_tmp; struct hlist_head *head; - struct element_t *bucket; struct vis_info *info;
for (i = 0; i < hash->size; i++) { head = &hash->table[i];
- hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) { - info = bucket->data; - + hlist_for_each_entry_safe(info, node, node_tmp, + head, hash_entry) { /* never purge own data. */ if (info == bat_priv->my_vis_info) continue;
if (time_after(jiffies, info->first_seen + VIS_TIMEOUT * HZ)) { - hlist_del(walk); - kfree(bucket); + hlist_del(node); send_list_del(info); kref_put(&info->refcount, free_info); } @@@ -704,27 -725,24 +726,24 @@@ static void broadcast_vis_packet(struc struct vis_info *info) { struct hashtable_t *hash = bat_priv->orig_hash; - struct hlist_node *walk; + struct hlist_node *node; struct hlist_head *head; struct orig_node *orig_node; struct vis_packet *packet; struct sk_buff *skb; - struct batman_if *batman_if; + struct hard_iface *hard_iface; uint8_t dstaddr[ETH_ALEN]; int i;
- spin_lock_bh(&bat_priv->orig_hash_lock); packet = (struct vis_packet *)info->skb_packet->data;
/* send to all routers in range. */ for (i = 0; i < hash->size; i++) { head = &hash->table[i];
- hlist_for_each_entry(bucket, walk, head, hlist) { - orig_node = bucket->data; - + rcu_read_lock(); + hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { /* if it's a vis server and reachable, send it. */ if ((!orig_node) || (!orig_node->router)) continue; @@@ -737,54 -755,61 +756,61 @@@ continue;
memcpy(packet->target_orig, orig_node->orig, ETH_ALEN); - batman_if = orig_node->router->if_incoming; + hard_iface = orig_node->router->if_incoming; memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);
skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) - send_skb_packet(skb, batman_if, dstaddr); + send_skb_packet(skb, hard_iface, dstaddr);
- spin_lock_bh(&bat_priv->orig_hash_lock); } - + rcu_read_unlock(); } - - spin_unlock_bh(&bat_priv->orig_hash_lock); }
static void unicast_vis_packet(struct bat_priv *bat_priv, struct vis_info *info) { struct orig_node *orig_node; + struct neigh_node *neigh_node = NULL; struct sk_buff *skb; struct vis_packet *packet; - struct batman_if *batman_if; - uint8_t dstaddr[ETH_ALEN];
- spin_lock_bh(&bat_priv->orig_hash_lock); packet = (struct vis_packet *)info->skb_packet->data; - orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash, - compare_orig, choose_orig, - packet->target_orig));
- if ((!orig_node) || (!orig_node->router)) - goto out; + rcu_read_lock(); + orig_node = orig_hash_find(bat_priv, packet->target_orig);
- /* don't lock while sending the packets ... we therefore - * copy the required data before sending */ - batman_if = orig_node->router->if_incoming; - memcpy(dstaddr, orig_node->router->addr, ETH_ALEN); - spin_unlock_bh(&bat_priv->orig_hash_lock); + if (!orig_node) + goto unlock; + + neigh_node = orig_node->router; + + if (!neigh_node) + goto unlock; + + if (!atomic_inc_not_zero(&neigh_node->refcount)) { + neigh_node = NULL; + goto unlock; + } + + rcu_read_unlock();
skb = skb_clone(info->skb_packet, GFP_ATOMIC); if (skb) - send_skb_packet(skb, batman_if, dstaddr); + send_skb_packet(skb, neigh_node->if_incoming, + neigh_node->addr);
- return; + goto out;
+ unlock: + rcu_read_unlock(); out: - spin_unlock_bh(&bat_priv->orig_hash_lock); + if (neigh_node) + neigh_node_free_ref(neigh_node); + if (orig_node) + orig_node_free_ref(orig_node); + return; }
/* only send one vis packet. called from send_vis_packets() */ @@@ -816,7 -841,7 +842,7 @@@ static void send_vis_packets(struct wor container_of(work, struct delayed_work, work); struct bat_priv *bat_priv = container_of(delayed_work, struct bat_priv, vis_work); - struct vis_info *info, *temp; + struct vis_info *info;
spin_lock_bh(&bat_priv->vis_hash_lock); purge_vis_packets(bat_priv); @@@ -826,9 -851,8 +852,9 @@@ send_list_add(bat_priv, bat_priv->my_vis_info); }
- list_for_each_entry_safe(info, temp, &bat_priv->vis_send_list, - send_list) { + while (!list_empty(&bat_priv->vis_send_list)) { + info = list_first_entry(&bat_priv->vis_send_list, + typeof(*info), send_list);
kref_get(&info->refcount); spin_unlock_bh(&bat_priv->vis_hash_lock); @@@ -896,7 -920,8 +922,8 @@@ int vis_init(struct bat_priv *bat_priv INIT_LIST_HEAD(&bat_priv->vis_send_list);
hash_added = hash_add(bat_priv->vis_hash, vis_info_cmp, vis_info_choose, - bat_priv->my_vis_info); + bat_priv->my_vis_info, + &bat_priv->my_vis_info->hash_entry); if (hash_added < 0) { pr_err("Can't add own vis packet into hash\n"); /* not in hash, need to remove it manually. */ @@@ -918,10 -943,11 +945,11 @@@ err }
/* Decrease the reference count on a hash item info */ - static void free_info_ref(void *data, void *arg) + static void free_info_ref(struct hlist_node *node, void *arg) { - struct vis_info *info = data; + struct vis_info *info;
+ info = container_of(node, struct vis_info, hash_entry); send_list_del(info); kref_put(&info->refcount, free_info); }