Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6-block.git] / net / batman-adv / translation-table.c
index af1d24ce420f62cec02124ecdfbafe5cd2cef674..5c7fa02ea57bbea53032b1e392bbbeb9967a3b06 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2015 B.A.T.M.A.N. contributors:
+/* Copyright (C) 2007-201 B.A.T.M.A.N. contributors:
  *
  * Marek Lindner, Simon Wunderlich, Antonio Quartulli
  *
@@ -31,6 +31,7 @@
 #include <linux/jhash.h>
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
+#include <linux/kref.h>
 #include <linux/list.h>
 #include <linux/lockdep.h>
 #include <linux/netdevice.h>
@@ -69,9 +70,13 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv,
                                 bool roaming);
 
 /**
- * batadv_compare_tt
+ * batadv_compare_tt - check if two TT entries are the same
+ * @node: the list element pointer of the first TT entry
+ * @data2: pointer to the tt_common_entry of the second TT entry
  *
- * Return: 1 if they are the same mac addr and vid
+ * Compare the MAC address and the VLAN ID of the two TT entries and check if
+ * they are the same TT client.
+ * Return: 1 if the two TT clients are the same, 0 otherwise
  */
 static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
 {
@@ -137,7 +142,7 @@ batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr,
                if (tt->vid != vid)
                        continue;
 
-               if (!atomic_inc_not_zero(&tt->refcount))
+               if (!kref_get_unless_zero(&tt->refcount))
                        continue;
 
                tt_tmp = tt;
@@ -198,29 +203,64 @@ batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
        return tt_global_entry;
 }
 
+/**
+ * batadv_tt_local_entry_release - release tt_local_entry from lists and queue
+ *  for free after rcu grace period
+ * @ref: kref pointer of the nc_node
+ */
+static void batadv_tt_local_entry_release(struct kref *ref)
+{
+       struct batadv_tt_local_entry *tt_local_entry;
+
+       tt_local_entry = container_of(ref, struct batadv_tt_local_entry,
+                                     common.refcount);
+
+       kfree_rcu(tt_local_entry, common.rcu);
+}
+
+/**
+ * batadv_tt_local_entry_free_ref - decrement the tt_local_entry refcounter and
+ *  possibly release it
+ * @tt_local_entry: tt_local_entry to be free'd
+ */
 static void
 batadv_tt_local_entry_free_ref(struct batadv_tt_local_entry *tt_local_entry)
 {
-       if (atomic_dec_and_test(&tt_local_entry->common.refcount))
-               kfree_rcu(tt_local_entry, common.rcu);
+       kref_put(&tt_local_entry->common.refcount,
+                batadv_tt_local_entry_release);
 }
 
 /**
- * batadv_tt_global_entry_free_ref - decrement the refcounter for a
- *  tt_global_entry and possibly free it
- * @tt_global_entry: the object to free
+ * batadv_tt_global_entry_release - release tt_global_entry from lists and queue
+ *  for free after rcu grace period
+ * @ref: kref pointer of the nc_node
+ */
+static void batadv_tt_global_entry_release(struct kref *ref)
+{
+       struct batadv_tt_global_entry *tt_global_entry;
+
+       tt_global_entry = container_of(ref, struct batadv_tt_global_entry,
+                                      common.refcount);
+
+       batadv_tt_global_del_orig_list(tt_global_entry);
+       kfree_rcu(tt_global_entry, common.rcu);
+}
+
+/**
+ * batadv_tt_global_entry_free_ref - decrement the tt_global_entry refcounter
+ *  and possibly release it
+ * @tt_global_entry: tt_global_entry to be free'd
  */
 static void
 batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry)
 {
-       if (atomic_dec_and_test(&tt_global_entry->common.refcount)) {
-               batadv_tt_global_del_orig_list(tt_global_entry);
-               kfree_rcu(tt_global_entry, common.rcu);
-       }
+       kref_put(&tt_global_entry->common.refcount,
+                batadv_tt_global_entry_release);
 }
 
 /**
  * batadv_tt_global_hash_count - count the number of orig entries
+ * @bat_priv: the bat priv with all the soft interface information
  * @addr: the mac address of the client to count entries for
  * @vid: VLAN identifier
  *
@@ -289,8 +329,9 @@ static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv,
 }
 
 /**
- * batadv_tt_global_size_mod - change the size by v of the local table
- *  identified by vid
+ * batadv_tt_global_size_mod - change the size by v of the global table
+ *  for orig_node identified by vid
+ * @orig_node: the originator for which the table has to be modified
  * @vid: the VLAN identifier
  * @v: the amount to sum to the global table size
  */
@@ -305,9 +346,11 @@ static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node,
 
        if (atomic_add_return(v, &vlan->tt.num_entries) == 0) {
                spin_lock_bh(&orig_node->vlan_list_lock);
-               hlist_del_init_rcu(&vlan->list);
+               if (!hlist_unhashed(&vlan->list)) {
+                       hlist_del_init_rcu(&vlan->list);
+                       batadv_orig_node_vlan_free_ref(vlan);
+               }
                spin_unlock_bh(&orig_node->vlan_list_lock);
-               batadv_orig_node_vlan_free_ref(vlan);
        }
 
        batadv_orig_node_vlan_free_ref(vlan);
@@ -340,22 +383,28 @@ static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node,
 /**
  * batadv_tt_orig_list_entry_release - release tt orig entry from lists and
  *  queue for free after rcu grace period
- * @orig_entry: tt orig entry to be free'd
+ * @ref: kref pointer of the tt orig entry
  */
-static void
-batadv_tt_orig_list_entry_release(struct batadv_tt_orig_list_entry *orig_entry)
+static void batadv_tt_orig_list_entry_release(struct kref *ref)
 {
+       struct batadv_tt_orig_list_entry *orig_entry;
+
+       orig_entry = container_of(ref, struct batadv_tt_orig_list_entry,
+                                 refcount);
+
        batadv_orig_node_free_ref(orig_entry->orig_node);
        kfree_rcu(orig_entry, rcu);
 }
 
+/**
+ * batadv_tt_orig_list_entry_free_ref - decrement the tt orig entry refcounter
+ *  and possibly release it
+ * @orig_entry: tt orig entry to be free'd
+ */
 static void
 batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry)
 {
-       if (!atomic_dec_and_test(&orig_entry->refcount))
-               return;
-
-       batadv_tt_orig_list_entry_release(orig_entry);
+       kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release);
 }
 
 /**
@@ -620,7 +669,8 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
        tt_local->common.vid = vid;
        if (batadv_is_wifi_netdev(in_dev))
                tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
-       atomic_set(&tt_local->common.refcount, 2);
+       kref_init(&tt_local->common.refcount);
+       kref_get(&tt_local->common.refcount);
        tt_local->last_seen = jiffies;
        tt_local->common.added_at = tt_local->last_seen;
 
@@ -721,7 +771,6 @@ out:
  *  function reserves the amount of space needed to send the entire global TT
  *  table. In case of success the value is updated with the real amount of
  *  reserved bytes
-
  * Allocate the needed amount of memory for the entire TT TVLV and write its
  * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
  * objects, one per active VLAN served by the originator node.
@@ -1243,9 +1292,12 @@ static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)
 }
 
 /**
- * batadv_tt_global_orig_entry_find
+ * batadv_tt_global_orig_entry_find - find a TT orig_list_entry
+ * @entry: the TT global entry where the orig_list_entry has to be
+ *  extracted from
+ * @orig_node: the originator for which the orig_list_entry has to be found
  *
- * retrieves the orig_tt_list_entry belonging to orig_node from the
+ * retrieve the orig_tt_list_entry belonging to orig_node from the
  * batadv_tt_global_entry list
  *
  * Return: it with an increased refcounter, NULL if not found
@@ -1262,7 +1314,7 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
        hlist_for_each_entry_rcu(tmp_orig_entry, head, list) {
                if (tmp_orig_entry->orig_node != orig_node)
                        continue;
-               if (!atomic_inc_not_zero(&tmp_orig_entry->refcount))
+               if (!kref_get_unless_zero(&tmp_orig_entry->refcount))
                        continue;
 
                orig_entry = tmp_orig_entry;
@@ -1274,7 +1326,10 @@ batadv_tt_global_orig_entry_find(const struct batadv_tt_global_entry *entry,
 }
 
 /**
- * batadv_tt_global_entry_has_orig
+ * batadv_tt_global_entry_has_orig - check if a TT global entry is also handled
+ *  by a given originator
+ * @entry: the TT global entry to check
+ * @orig_node: the originator to search in the list
  *
  * find out if an orig_node is already in the list of a tt_global_entry.
  *
@@ -1316,11 +1371,12 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
                goto out;
 
        INIT_HLIST_NODE(&orig_entry->list);
-       atomic_inc(&orig_node->refcount);
+       kref_get(&orig_node->refcount);
        batadv_tt_global_size_inc(orig_node, tt_global->common.vid);
        orig_entry->orig_node = orig_node;
        orig_entry->ttvn = ttvn;
-       atomic_set(&orig_entry->refcount, 2);
+       kref_init(&orig_entry->refcount);
+       kref_get(&orig_entry->refcount);
 
        spin_lock_bh(&tt_global->list_lock);
        hlist_add_head_rcu(&orig_entry->list,
@@ -1396,7 +1452,8 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
                 */
                if (flags & BATADV_TT_CLIENT_ROAM)
                        tt_global_entry->roam_at = jiffies;
-               atomic_set(&common->refcount, 2);
+               kref_init(&common->refcount);
+               kref_get(&common->refcount);
                common->added_at = jiffies;
 
                INIT_HLIST_HEAD(&tt_global_entry->orig_list);
@@ -2078,7 +2135,7 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
        /* found anything? */
        if (best_entry)
                orig_node = best_entry->orig_node;
-       if (orig_node && !atomic_inc_not_zero(&orig_node->refcount))
+       if (orig_node && !kref_get_unless_zero(&orig_node->refcount))
                orig_node = NULL;
        rcu_read_unlock();
 
@@ -2519,6 +2576,8 @@ static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv,
  * @num_vlan: number of tvlv VLAN entries
  * @full_table: ask for the entire translation table if true, while only for the
  *  last TT diff otherwise
+ *
+ * Return: true if the TT Request was sent, false otherwise
  */
 static int batadv_send_tt_request(struct batadv_priv *bat_priv,
                                  struct batadv_orig_node *dst_orig_node,
@@ -3062,7 +3121,9 @@ static void batadv_tt_roam_purge(struct batadv_priv *bat_priv)
 }
 
 /**
- * batadv_tt_check_roam_count
+ * batadv_tt_check_roam_count - check if a client has roamed too frequently
+ * @bat_priv: the bat priv with all the soft interface information
+ * @client: mac address of the roaming client
  *
  * This function checks whether the client already reached the
  * maximum number of possible roaming phases. In this case the ROAMING_ADV