[linux-next] LinuxNextTracking branch, master, updated. next-20110624

batman at open-mesh.org batman at open-mesh.org
Fri Jun 24 16:09:13 CEST 2011


The following commit has been merged in the master branch:
commit b8cec4a415e807a2f8679efa89558a040a7003de
Merge: 5e2b61f78411be25f0b84f97d5b5d312f184dfd1 e44d8fe2b5c27ecc230f886d4cc49fcbd86f87a0
Author: David S. Miller <davem at 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);
  }

-- 
LinuxNextTracking


More information about the linux-merge mailing list