Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma
[deliverable/linux.git] / net / batman-adv / bat_iv_ogm.c
index cb2d1b9b034058c454fa0b7c5c14e6491ed41b1d..ce2f203048d35a606487e9cd3a9acec3d72d85f6 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/kref.h>
+#include <linux/lockdep.h>
 #include <linux/netdevice.h>
 #include <linux/pkt_sched.h>
 #include <linux/printk.h>
@@ -156,10 +157,8 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node,
        orig_node->bat_iv.bcast_own = data_ptr;
 
        data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC);
-       if (!data_ptr) {
-               kfree(orig_node->bat_iv.bcast_own);
+       if (!data_ptr)
                goto unlock;
-       }
 
        memcpy(data_ptr, orig_node->bat_iv.bcast_own_sum,
               (max_if_num - 1) * sizeof(u8));
@@ -175,71 +174,107 @@ unlock:
 }
 
 /**
- * batadv_iv_ogm_orig_del_if - change the private structures of the orig_node to
- *  exclude the removed interface
+ * batadv_iv_ogm_drop_bcast_own_entry - drop section of bcast_own
  * @orig_node: the orig_node that has to be changed
  * @max_if_num: the current amount of interfaces
  * @del_if_num: the index of the interface being removed
- *
- * Return: 0 on success, a negative error code otherwise.
  */
-static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node,
-                                    int max_if_num, int del_if_num)
+static void
+batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node,
+                                  int max_if_num, int del_if_num)
 {
-       int ret = -ENOMEM;
-       size_t chunk_size, if_offset;
-       void *data_ptr = NULL;
-
-       spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
+       size_t chunk_size;
+       size_t if_offset;
+       void *data_ptr;
 
-       /* last interface was removed */
-       if (max_if_num == 0)
-               goto free_bcast_own;
+       lockdep_assert_held(&orig_node->bat_iv.ogm_cnt_lock);
 
        chunk_size = sizeof(unsigned long) * BATADV_NUM_WORDS;
        data_ptr = kmalloc_array(max_if_num, chunk_size, GFP_ATOMIC);
        if (!data_ptr)
-               goto unlock;
+               /* use old buffer when new one could not be allocated */
+               data_ptr = orig_node->bat_iv.bcast_own;
 
        /* copy first part */
-       memcpy(data_ptr, orig_node->bat_iv.bcast_own, del_if_num * chunk_size);
+       memmove(data_ptr, orig_node->bat_iv.bcast_own, del_if_num * chunk_size);
 
        /* copy second part */
        if_offset = (del_if_num + 1) * chunk_size;
-       memcpy((char *)data_ptr + del_if_num * chunk_size,
-              (uint8_t *)orig_node->bat_iv.bcast_own + if_offset,
-              (max_if_num - del_if_num) * chunk_size);
+       memmove((char *)data_ptr + del_if_num * chunk_size,
+               (uint8_t *)orig_node->bat_iv.bcast_own + if_offset,
+               (max_if_num - del_if_num) * chunk_size);
 
-free_bcast_own:
-       kfree(orig_node->bat_iv.bcast_own);
-       orig_node->bat_iv.bcast_own = data_ptr;
+       /* bcast_own was shrunk down in new buffer; free old one */
+       if (orig_node->bat_iv.bcast_own != data_ptr) {
+               kfree(orig_node->bat_iv.bcast_own);
+               orig_node->bat_iv.bcast_own = data_ptr;
+       }
+}
+
+/**
+ * batadv_iv_ogm_drop_bcast_own_sum_entry - drop section of bcast_own_sum
+ * @orig_node: the orig_node that has to be changed
+ * @max_if_num: the current amount of interfaces
+ * @del_if_num: the index of the interface being removed
+ */
+static void
+batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node,
+                                      int max_if_num, int del_if_num)
+{
+       size_t if_offset;
+       void *data_ptr;
 
-       if (max_if_num == 0)
-               goto free_own_sum;
+       lockdep_assert_held(&orig_node->bat_iv.ogm_cnt_lock);
 
        data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC);
-       if (!data_ptr) {
-               kfree(orig_node->bat_iv.bcast_own);
-               goto unlock;
-       }
+       if (!data_ptr)
+               /* use old buffer when new one could not be allocated */
+               data_ptr = orig_node->bat_iv.bcast_own_sum;
 
-       memcpy(data_ptr, orig_node->bat_iv.bcast_own_sum,
-              del_if_num * sizeof(u8));
+       memmove(data_ptr, orig_node->bat_iv.bcast_own_sum,
+               del_if_num * sizeof(u8));
 
        if_offset = (del_if_num + 1) * sizeof(u8);
-       memcpy((char *)data_ptr + del_if_num * sizeof(u8),
-              orig_node->bat_iv.bcast_own_sum + if_offset,
-              (max_if_num - del_if_num) * sizeof(u8));
+       memmove((char *)data_ptr + del_if_num * sizeof(u8),
+               orig_node->bat_iv.bcast_own_sum + if_offset,
+               (max_if_num - del_if_num) * sizeof(u8));
+
+       /* bcast_own_sum was shrunk down in new buffer; free old one */
+       if (orig_node->bat_iv.bcast_own_sum != data_ptr) {
+               kfree(orig_node->bat_iv.bcast_own_sum);
+               orig_node->bat_iv.bcast_own_sum = data_ptr;
+       }
+}
 
-free_own_sum:
-       kfree(orig_node->bat_iv.bcast_own_sum);
-       orig_node->bat_iv.bcast_own_sum = data_ptr;
+/**
+ * batadv_iv_ogm_orig_del_if - change the private structures of the orig_node to
+ *  exclude the removed interface
+ * @orig_node: the orig_node that has to be changed
+ * @max_if_num: the current amount of interfaces
+ * @del_if_num: the index of the interface being removed
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node,
+                                    int max_if_num, int del_if_num)
+{
+       spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
+
+       if (max_if_num == 0) {
+               kfree(orig_node->bat_iv.bcast_own);
+               kfree(orig_node->bat_iv.bcast_own_sum);
+               orig_node->bat_iv.bcast_own = NULL;
+               orig_node->bat_iv.bcast_own_sum = NULL;
+       } else {
+               batadv_iv_ogm_drop_bcast_own_entry(orig_node, max_if_num,
+                                                  del_if_num);
+               batadv_iv_ogm_drop_bcast_own_sum_entry(orig_node, max_if_num,
+                                                      del_if_num);
+       }
 
-       ret = 0;
-unlock:
        spin_unlock_bh(&orig_node->bat_iv.ogm_cnt_lock);
 
-       return ret;
+       return 0;
 }
 
 /**
@@ -644,18 +679,12 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
        unsigned char *skb_buff;
        unsigned int skb_size;
 
-       if (!kref_get_unless_zero(&if_incoming->refcount))
-               return;
-
-       if (!kref_get_unless_zero(&if_outgoing->refcount))
-               goto out_free_incoming;
-
        /* own packet should always be scheduled */
        if (!own_packet) {
                if (!batadv_atomic_dec_not_zero(&bat_priv->batman_queue_left)) {
                        batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
                                   "batman packet queue full\n");
-                       goto out_free_outgoing;
+                       return;
                }
        }
 
@@ -681,6 +710,8 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
        forw_packet_aggr->packet_len = packet_len;
        memcpy(skb_buff, packet_buff, packet_len);
 
+       kref_get(&if_incoming->refcount);
+       kref_get(&if_outgoing->refcount);
        forw_packet_aggr->own = own_packet;
        forw_packet_aggr->if_incoming = if_incoming;
        forw_packet_aggr->if_outgoing = if_outgoing;
@@ -710,10 +741,6 @@ out_free_forw_packet:
 out_nomem:
        if (!own_packet)
                atomic_inc(&bat_priv->batman_queue_left);
-out_free_outgoing:
-       batadv_hardif_put(if_outgoing);
-out_free_incoming:
-       batadv_hardif_put(if_incoming);
 }
 
 /* aggregate a new packet into the existing ogm packet */
@@ -950,9 +977,15 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
        list_for_each_entry_rcu(tmp_hard_iface, &batadv_hardif_list, list) {
                if (tmp_hard_iface->soft_iface != hard_iface->soft_iface)
                        continue;
+
+               if (!kref_get_unless_zero(&tmp_hard_iface->refcount))
+                       continue;
+
                batadv_iv_ogm_queue_add(bat_priv, *ogm_buff,
                                        *ogm_buff_len, hard_iface,
                                        tmp_hard_iface, 1, send_time);
+
+               batadv_hardif_put(tmp_hard_iface);
        }
        rcu_read_unlock();
 
@@ -1133,13 +1166,13 @@ out:
  * @if_incoming: interface where the packet was received
  * @if_outgoing: interface for which the retransmission should be considered
  *
- * Return: 1 if the link can be considered bidirectional, 0 otherwise
+ * Return: true if the link can be considered bidirectional, false otherwise
  */
-static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
-                                struct batadv_orig_node *orig_neigh_node,
-                                struct batadv_ogm_packet *batadv_ogm_packet,
-                                struct batadv_hard_iface *if_incoming,
-                                struct batadv_hard_iface *if_outgoing)
+static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
+                                 struct batadv_orig_node *orig_neigh_node,
+                                 struct batadv_ogm_packet *batadv_ogm_packet,
+                                 struct batadv_hard_iface *if_incoming,
+                                 struct batadv_hard_iface *if_outgoing)
 {
        struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
        struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node;
@@ -1147,9 +1180,11 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
        u8 total_count;
        u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own;
        unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
-       int tq_asym_penalty, inv_asym_penalty, if_num, ret = 0;
+       int if_num;
+       unsigned int tq_asym_penalty, inv_asym_penalty;
        unsigned int combined_tq;
-       int tq_iface_penalty;
+       unsigned int tq_iface_penalty;
+       bool ret = false;
 
        /* find corresponding one hop neighbor */
        rcu_read_lock();
@@ -1261,7 +1296,7 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
         * consider it bidirectional
         */
        if (batadv_ogm_packet->tq >= BATADV_TQ_TOTAL_BIDRECT_LIMIT)
-               ret = 1;
+               ret = true;
 
 out:
        if (neigh_node)
@@ -1290,9 +1325,9 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
        struct batadv_orig_ifinfo *orig_ifinfo = NULL;
        struct batadv_neigh_node *neigh_node;
        struct batadv_neigh_ifinfo *neigh_ifinfo;
-       int is_dup;
+       bool is_dup;
        s32 seq_diff;
-       int need_update = 0;
+       bool need_update = false;
        int set_mark;
        enum batadv_dup_status ret = BATADV_NO_DUP;
        u32 seqno = ntohl(batadv_ogm_packet->seqno);
@@ -1402,7 +1437,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset,
        struct sk_buff *skb_priv;
        struct ethhdr *ethhdr;
        u8 *prev_sender;
-       int is_bidirect;
+       bool is_bidirect;
 
        /* create a private copy of the skb, as some functions change tq value
         * and/or flags.
@@ -1730,8 +1765,13 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
                if (hard_iface->soft_iface != bat_priv->soft_iface)
                        continue;
 
+               if (!kref_get_unless_zero(&hard_iface->refcount))
+                       continue;
+
                batadv_iv_ogm_process_per_outif(skb, ogm_offset, orig_node,
                                                if_incoming, hard_iface);
+
+               batadv_hardif_put(hard_iface);
        }
        rcu_read_unlock();
 
@@ -1829,9 +1869,8 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv,
        int batman_count = 0;
        u32 i;
 
-       seq_printf(seq, "  %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
-                  "Originator", "last-seen", "#", BATADV_TQ_MAX_VALUE,
-                  "Nexthop", "outgoingIF", "Potential nexthops");
+       seq_puts(seq,
+                "  Originator      last-seen (#/255)           Nexthop [outgoingIF]:   Potential nexthops ...\n");
 
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
@@ -1911,8 +1950,7 @@ static void batadv_iv_neigh_print(struct batadv_priv *bat_priv,
        struct batadv_hard_iface *hard_iface;
        int batman_count = 0;
 
-       seq_printf(seq, "   %10s        %-13s %s\n",
-                  "IF", "Neighbor", "last-seen");
+       seq_puts(seq, "           IF        Neighbor      last-seen\n");
 
        rcu_read_lock();
        list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
This page took 0.101714 seconds and 5 git commands to generate.