batman-adv: Directly print to seq_file in vis
authorSven Eckelmann <sven@narfation.org>
Wed, 16 May 2012 18:23:23 +0000 (20:23 +0200)
committerAntonio Quartulli <ordex@autistici.org>
Thu, 28 Jun 2012 06:44:49 +0000 (08:44 +0200)
The vis output doesn't need to be buffered in an character buffer before it can
be send to the userspace program that reads from the vis debug file.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
net/batman-adv/vis.c

index 6b7a1c05e45e1af9a50ffb9558957217ea93c54b..3095c41a67ad30d289612b11e807e5caf96d9cc4 100644 (file)
@@ -140,72 +140,117 @@ static void batadv_vis_data_insert_interface(const uint8_t *interface,
        hlist_add_head(&entry->list, if_list);
 }
 
-static ssize_t batadv_vis_prim_sec(char *buff, const struct hlist_head *if_list)
+static void batadv_vis_data_read_prim_sec(struct seq_file *seq,
+                                         const struct hlist_head *if_list)
 {
        struct if_list_entry *entry;
        struct hlist_node *pos;
-       size_t len = 0;
 
        hlist_for_each_entry(entry, pos, if_list, list) {
                if (entry->primary)
-                       len += sprintf(buff + len, "PRIMARY, ");
+                       seq_printf(seq, "PRIMARY, ");
                else
-                       len += sprintf(buff + len,  "SEC %pM, ", entry->addr);
+                       seq_printf(seq,  "SEC %pM, ", entry->addr);
        }
+}
+
+/* read an entry  */
+static ssize_t batadv_vis_data_read_entry(struct seq_file *seq,
+                                         const struct vis_info_entry *entry,
+                                         const uint8_t *src, bool primary)
+{
+       if (primary && entry->quality == 0)
+               return seq_printf(seq, "TT %pM, ", entry->dest);
+       else if (batadv_compare_eth(entry->src, src))
+               return seq_printf(seq, "TQ %pM %d, ", entry->dest,
+                                 entry->quality);
+
+       return 0;
+}
+
+static void batadv_vis_data_insert_interfaces(struct hlist_head *list,
+                                             struct vis_packet *packet,
+                                             struct vis_info_entry *entries)
+{
+       int i;
+
+       for (i = 0; i < packet->entries; i++) {
+               if (entries[i].quality == 0)
+                       continue;
 
-       return len;
+               if (batadv_compare_eth(entries[i].src, packet->vis_orig))
+                       continue;
+
+               batadv_vis_data_insert_interface(entries[i].src, list, false);
+       }
 }
 
-static size_t batadv_vis_cnt_prim_sec(struct hlist_head *if_list)
+static void batadv_vis_data_read_entries(struct seq_file *seq,
+                                        struct hlist_head *list,
+                                        struct vis_packet *packet,
+                                        struct vis_info_entry *entries)
 {
+       int i;
        struct if_list_entry *entry;
        struct hlist_node *pos;
-       size_t count = 0;
 
-       hlist_for_each_entry(entry, pos, if_list, list) {
-               if (entry->primary)
-                       count += 9;
-               else
-                       count += 23;
-       }
+       hlist_for_each_entry(entry, pos, list, list) {
+               seq_printf(seq, "%pM,", entry->addr);
+
+               for (i = 0; i < packet->entries; i++)
+                       batadv_vis_data_read_entry(seq, &entries[i],
+                                                  entry->addr, entry->primary);
 
-       return count;
+               /* add primary/secondary records */
+               if (batadv_compare_eth(entry->addr, packet->vis_orig))
+                       batadv_vis_data_read_prim_sec(seq, list);
+
+               seq_printf(seq, "\n");
+       }
 }
 
-/* read an entry  */
-static ssize_t batadv_vis_data_read_entry(char *buff,
-                                         const struct vis_info_entry *entry,
-                                         const uint8_t *src, bool primary)
+static void batadv_vis_seq_print_text_bucket(struct seq_file *seq,
+                                            const struct hlist_head *head)
 {
-       /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */
-       if (primary && entry->quality == 0)
-               return sprintf(buff, "TT %pM, ", entry->dest);
-       else if (batadv_compare_eth(entry->src, src))
-               return sprintf(buff, "TQ %pM %d, ", entry->dest,
-                              entry->quality);
+       struct hlist_node *node;
+       struct vis_info *info;
+       struct vis_packet *packet;
+       uint8_t *entries_pos;
+       struct vis_info_entry *entries;
+       struct if_list_entry *entry;
+       struct hlist_node *pos, *n;
 
-       return 0;
+       HLIST_HEAD(vis_if_list);
+
+       hlist_for_each_entry_rcu(info, node, head, hash_entry) {
+               packet = (struct vis_packet *)info->skb_packet->data;
+               entries_pos = (uint8_t *)packet + sizeof(*packet);
+               entries = (struct vis_info_entry *)entries_pos;
+
+               batadv_vis_data_insert_interface(packet->vis_orig, &vis_if_list,
+                                                true);
+               batadv_vis_data_insert_interfaces(&vis_if_list, packet,
+                                                 entries);
+               batadv_vis_data_read_entries(seq, &vis_if_list, packet,
+                                            entries);
+
+               hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) {
+                       hlist_del(&entry->list);
+                       kfree(entry);
+               }
+       }
 }
 
 int batadv_vis_seq_print_text(struct seq_file *seq, void *offset)
 {
        struct hard_iface *primary_if;
-       struct hlist_node *node;
        struct hlist_head *head;
-       struct vis_info *info;
-       struct vis_packet *packet;
-       struct vis_info_entry *entries;
        struct net_device *net_dev = (struct net_device *)seq->private;
        struct bat_priv *bat_priv = netdev_priv(net_dev);
        struct hashtable_t *hash = bat_priv->vis_hash;
-       HLIST_HEAD(vis_if_list);
-       struct if_list_entry *entry;
-       struct hlist_node *pos, *n;
        uint32_t i;
-       int j, ret = 0;
+       int ret = 0;
        int vis_server = atomic_read(&bat_priv->vis_mode);
-       size_t buff_pos, buf_size;
-       char *buff;
 
        primary_if = batadv_primary_if_get_selected(bat_priv);
        if (!primary_if)
@@ -214,120 +259,13 @@ int batadv_vis_seq_print_text(struct seq_file *seq, void *offset)
        if (vis_server == VIS_TYPE_CLIENT_UPDATE)
                goto out;
 
-       buf_size = 1;
-       /* Estimate length */
        spin_lock_bh(&bat_priv->vis_hash_lock);
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
-
-               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(*packet));
-
-                       batadv_vis_data_insert_interface(packet->vis_orig,
-                                                        &vis_if_list, true);
-
-                       for (j = 0; j < packet->entries; j++) {
-                               if (entries[j].quality == 0)
-                                       continue;
-                               if (batadv_compare_eth(entries[j].src,
-                                                      packet->vis_orig))
-                                       continue;
-                               batadv_vis_data_insert_interface(entries[j].src,
-                                                                &vis_if_list,
-                                                                false);
-                       }
-
-                       hlist_for_each_entry(entry, pos, &vis_if_list, list) {
-                               buf_size += 18 + 26 * packet->entries;
-
-                               /* add primary/secondary records */
-                               if (batadv_compare_eth(entry->addr,
-                                                      packet->vis_orig))
-                                       buf_size +=
-                                         batadv_vis_cnt_prim_sec(&vis_if_list);
-
-                               buf_size += 1;
-                       }
-
-                       hlist_for_each_entry_safe(entry, pos, n, &vis_if_list,
-                                                 list) {
-                               hlist_del(&entry->list);
-                               kfree(entry);
-                       }
-               }
-               rcu_read_unlock();
+               batadv_vis_seq_print_text_bucket(seq, head);
        }
-
-       buff = kmalloc(buf_size, GFP_ATOMIC);
-       if (!buff) {
-               spin_unlock_bh(&bat_priv->vis_hash_lock);
-               ret = -ENOMEM;
-               goto out;
-       }
-       buff[0] = '\0';
-       buff_pos = 0;
-
-       for (i = 0; i < hash->size; i++) {
-               head = &hash->table[i];
-
-               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(*packet));
-
-                       batadv_vis_data_insert_interface(packet->vis_orig,
-                                                        &vis_if_list, true);
-
-                       for (j = 0; j < packet->entries; j++) {
-                               if (entries[j].quality == 0)
-                                       continue;
-                               if (batadv_compare_eth(entries[j].src,
-                                                      packet->vis_orig))
-                                       continue;
-                               batadv_vis_data_insert_interface(entries[j].src,
-                                                                &vis_if_list,
-                                                                false);
-                       }
-
-                       hlist_for_each_entry(entry, pos, &vis_if_list, list) {
-                               buff_pos += sprintf(buff + buff_pos, "%pM,",
-                                               entry->addr);
-
-                               for (j = 0; j < packet->entries; j++)
-                                       buff_pos += batadv_vis_data_read_entry(
-                                                       buff + buff_pos,
-                                                       &entries[j],
-                                                       entry->addr,
-                                                       entry->primary);
-
-                               /* add primary/secondary records */
-                               if (batadv_compare_eth(entry->addr,
-                                                      packet->vis_orig))
-                                       buff_pos +=
-                                        batadv_vis_prim_sec(buff + buff_pos,
-                                                            &vis_if_list);
-
-                               buff_pos += sprintf(buff + buff_pos, "\n");
-                       }
-
-                       hlist_for_each_entry_safe(entry, pos, n, &vis_if_list,
-                                                 list) {
-                               hlist_del(&entry->list);
-                               kfree(entry);
-                       }
-               }
-               rcu_read_unlock();
-       }
-
        spin_unlock_bh(&bat_priv->vis_hash_lock);
 
-       seq_printf(seq, "%s", buff);
-       kfree(buff);
-
 out:
        if (primary_if)
                batadv_hardif_free_ref(primary_if);