Files which represent more than a single attribute aren't allowed in sysfs. As we have some files which aren't essential and are lists or tables aggregated from data from different places inside batman-adv, we must place them in a filesystem without such a restriction.
Signed-off-by: Sven Eckelmann sven.eckelmann@gmx.de --- I've adjusted the output of transtable_global, vis_data and transtable_global to use an extra buffer inside the spin_lock_irqsave and do the actual printing outside the spinlock. Even if it is not the perfect solution, it should be good enough for now - aka doesn't create a deadlock on file reads.
batman-adv-kernelland/bat_debugfs.c | 79 +++++++++++++++ batman-adv-kernelland/bat_sysfs.c | 91 ----------------- batman-adv-kernelland/gateway_client.c | 64 ++++--------- batman-adv-kernelland/gateway_client.h | 3 +- batman-adv-kernelland/main.h | 1 + batman-adv-kernelland/originator.c | 61 ++++-------- batman-adv-kernelland/originator.h | 3 +- batman-adv-kernelland/translation-table.c | 151 +++++++++++++++-------------- batman-adv-kernelland/translation-table.h | 6 +- batman-adv-kernelland/vis.c | 111 +++++++++++++++------ batman-adv-kernelland/vis.h | 3 +- 11 files changed, 278 insertions(+), 295 deletions(-)
diff --git a/batman-adv-kernelland/bat_debugfs.c b/batman-adv-kernelland/bat_debugfs.c index 19e7bee..9113601 100644 --- a/batman-adv-kernelland/bat_debugfs.c +++ b/batman-adv-kernelland/bat_debugfs.c @@ -34,6 +34,68 @@
static struct dentry *bat_debugfs;
+static int originators_open(struct inode *inode, struct file *file) +{ + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, orig_seq_print_text, net_dev); +} + +static int gateways_open(struct inode *inode, struct file *file) +{ + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, gw_client_seq_print_text, net_dev); +} + +static int transtable_global_open(struct inode *inode, struct file *file) +{ + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, hna_global_seq_print_text, net_dev); +} + +static int transtable_local_open(struct inode *inode, struct file *file) +{ + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, hna_local_seq_print_text, net_dev); +} + +static int vis_data_open(struct inode *inode, struct file *file) +{ + struct net_device *net_dev = (struct net_device *)inode->i_private; + return single_open(file, vis_seq_print_text, net_dev); +} + +struct bat_debuginfo { + struct attribute attr; + const struct file_operations fops; +}; + +#define BAT_DEBUGINFO(_name, _mode, _open) \ +struct bat_debuginfo bat_debuginfo_##_name = { \ + .attr = { .name = __stringify(_name), \ + .mode = _mode, }, \ + .fops = { .owner = THIS_MODULE, \ + .open = _open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + } \ +}; + +static BAT_DEBUGINFO(originators, S_IRUGO, originators_open); +static BAT_DEBUGINFO(gateways, S_IRUGO, gateways_open); +static BAT_DEBUGINFO(transtable_global, S_IRUGO, transtable_global_open); +static BAT_DEBUGINFO(transtable_local, S_IRUGO, transtable_local_open); +static BAT_DEBUGINFO(vis_data, S_IRUGO, vis_data_open); + +static struct bat_debuginfo *mesh_debuginfos[] = { + &bat_debuginfo_originators, + &bat_debuginfo_gateways, + &bat_debuginfo_transtable_global, + &bat_debuginfo_transtable_local, + &bat_debuginfo_vis_data, + NULL, +}; + void debugfs_init(void) { bat_debugfs = debugfs_create_dir(DEBUGFS_BAT_SUBDIR, NULL); @@ -50,6 +112,8 @@ void debugfs_destroy(void) int debugfs_add_meshif(struct net_device *dev) { struct bat_priv *bat_priv = netdev_priv(dev); + struct bat_debuginfo **bat_debug; + struct dentry *file;
if (!bat_debugfs) goto out; @@ -60,7 +124,22 @@ int debugfs_add_meshif(struct net_device *dev)
bat_socket_setup(bat_priv);
+ for (bat_debug = mesh_debuginfos; *bat_debug; ++bat_debug) { + file = debugfs_create_file(((*bat_debug)->attr).name, + S_IFREG | ((*bat_debug)->attr).mode, + bat_priv->debug_dir, + dev, &(*bat_debug)->fops); + if (!file) { + printk(KERN_ERR "batman-adv:Can't add debugfs file: " + "%s/%s\n", dev->name, ((*bat_debug)->attr).name); + goto rem_attr; + } + } + return 0; +rem_attr: + debugfs_remove_recursive(bat_priv->debug_dir); + bat_priv->debug_dir = NULL; out: return -ENOMEM; } diff --git a/batman-adv-kernelland/bat_sysfs.c b/batman-adv-kernelland/bat_sysfs.c index 7690368..a689aec 100644 --- a/batman-adv-kernelland/bat_sysfs.c +++ b/batman-adv-kernelland/bat_sysfs.c @@ -39,14 +39,6 @@ struct bat_attribute bat_attr_##_name = { \ .store = _store, \ };
-#define BAT_BIN_ATTR(_name, _mode, _read, _write) \ -struct bin_attribute bat_attr_##_name = { \ - .attr = { .name = __stringify(_name), \ - .mode = _mode, }, \ - .read = _read, \ - .write = _write, \ -}; - static ssize_t show_aggr_ogm(struct kobject *kobj, struct attribute *attr, char *buff) { @@ -305,77 +297,11 @@ static struct bat_attribute *mesh_attrs[] = { NULL, };
-static ssize_t transtable_local_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buff, loff_t off, size_t count) -{ - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - - return hna_local_fill_buffer_text(net_dev, buff, count, off); -} - -static ssize_t transtable_global_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buff, loff_t off, size_t count) -{ - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - - return hna_global_fill_buffer_text(net_dev, buff, count, off); -} - -static ssize_t originators_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buff, loff_t off, size_t count) -{ - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - - return orig_fill_buffer_text(net_dev, buff, count, off); -} - -static ssize_t gateways_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buff, loff_t off, size_t count) -{ - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - - return gw_client_fill_buffer_text(net_dev, buff, count, off); -} - -static ssize_t vis_data_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buff, loff_t off, size_t count) -{ - struct device *dev = to_dev(kobj->parent); - struct net_device *net_dev = to_net_dev(dev); - - return vis_fill_buffer_text(net_dev, buff, count, off); -} - -static BAT_BIN_ATTR(transtable_local, S_IRUGO, transtable_local_read, NULL); -static BAT_BIN_ATTR(transtable_global, S_IRUGO, transtable_global_read, NULL); -static BAT_BIN_ATTR(originators, S_IRUGO, originators_read, NULL); -static BAT_BIN_ATTR(gateways, S_IRUGO, gateways_read, NULL); -static BAT_BIN_ATTR(vis_data, S_IRUGO, vis_data_read, NULL); - -static struct bin_attribute *mesh_bin_attrs[] = { - &bat_attr_transtable_local, - &bat_attr_transtable_global, - &bat_attr_originators, - &bat_attr_gateways, - &bat_attr_vis_data, - NULL, -}; - int sysfs_add_meshif(struct net_device *dev) { struct kobject *batif_kobject = &dev->dev.kobj; struct bat_priv *bat_priv = netdev_priv(dev); struct bat_attribute **bat_attr; - struct bin_attribute **bin_attr; int err;
/* FIXME: should be done in the general mesh setup @@ -411,21 +337,8 @@ int sysfs_add_meshif(struct net_device *dev) } }
- for (bin_attr = mesh_bin_attrs; *bin_attr; ++bin_attr) { - err = sysfs_create_bin_file(bat_priv->mesh_obj, (*bin_attr)); - if (err) { - printk(KERN_ERR "batman-adv:Can't add sysfs file: %s/%s/%s\n", - dev->name, SYSFS_IF_MESH_SUBDIR, - ((*bin_attr)->attr).name); - goto rem_bin_attr; - } - } - return 0;
-rem_bin_attr: - for (bin_attr = mesh_bin_attrs; *bin_attr; ++bin_attr) - sysfs_remove_bin_file(bat_priv->mesh_obj, (*bin_attr)); rem_attr: for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); @@ -440,10 +353,6 @@ void sysfs_del_meshif(struct net_device *dev) { struct bat_priv *bat_priv = netdev_priv(dev); struct bat_attribute **bat_attr; - struct bin_attribute **bin_attr; - - for (bin_attr = mesh_bin_attrs; *bin_attr; ++bin_attr) - sysfs_remove_bin_file(bat_priv->mesh_obj, (*bin_attr));
for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); diff --git a/batman-adv-kernelland/gateway_client.c b/batman-adv-kernelland/gateway_client.c index a5e4f5f..552ef6f 100644 --- a/batman-adv-kernelland/gateway_client.c +++ b/batman-adv-kernelland/gateway_client.c @@ -317,8 +317,7 @@ void gw_node_list_free(void) spin_unlock(&gw_list_lock); }
-static int _write_buffer_text(unsigned char *buff, int bytes_written, - struct gw_node *gw_node) +static int _write_buffer_text(struct seq_file *seq, struct gw_node *gw_node) { int down, up; char gw_str[ETH_STR_LEN], router_str[ETH_STR_LEN]; @@ -327,8 +326,7 @@ static int _write_buffer_text(unsigned char *buff, int bytes_written, addr_to_string(router_str, gw_node->orig_node->router->addr); gw_srv_class_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
- return sprintf(buff + bytes_written, - "%s %-17s (%3i) %17s [%10s]: %3i - %i%s/%i%s\n", + return seq_printf(seq, "%s %-17s (%3i) %17s [%10s]: %3i - %i%s/%i%s\n", (curr_gateway == gw_node ? "=>" : " "), gw_str, gw_node->orig_node->router->tq_avg, @@ -341,51 +339,38 @@ static int _write_buffer_text(unsigned char *buff, int bytes_written, (up > 2048 ? "MBit" : "KBit")); }
-int gw_client_fill_buffer_text(struct net_device *net_dev, char *buff, - size_t count, loff_t off) +int gw_client_seq_print_text(struct seq_file *seq, void *offset) { + struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); struct gw_node *gw_node; - size_t hdr_len, tmp_len; - int bytes_written = 0, gw_count = 0; + int gw_count = 0;
rcu_read_lock(); if (!bat_priv->primary_if) { rcu_read_unlock();
- if (off == 0) - return sprintf(buff, - "BATMAN mesh %s disabled - please " - "specify interfaces to enable it\n", - net_dev->name); - - return 0; + return seq_printf(seq, "BATMAN mesh %s disabled - please " + "specify interfaces to enable it\n", + net_dev->name); }
if (bat_priv->primary_if->if_status != IF_ACTIVE) { rcu_read_unlock();
- if (off == 0) - return sprintf(buff, - "BATMAN mesh %s disabled - " + return seq_printf(seq, "BATMAN mesh %s disabled - " "primary interface not active\n", net_dev->name); - - return 0; }
- hdr_len = sprintf(buff, " %-12s (%s/%i) %17s [%10s]: gw_class ... " - "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s (%s)]\n", - "Gateway", "#", TQ_MAX_VALUE, "Nexthop", - "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, - bat_priv->primary_if->dev, - bat_priv->primary_if->addr_str, - net_dev->name); + seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " + "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s (%s)]\n", + "Gateway", "#", TQ_MAX_VALUE, "Nexthop", + "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, + bat_priv->primary_if->dev, bat_priv->primary_if->addr_str, + net_dev->name); rcu_read_unlock();
- if (off < hdr_len) - bytes_written = hdr_len; - rcu_read_lock(); list_for_each_entry_rcu(gw_node, &gw_list, list) { if (gw_node->deleted) @@ -394,26 +379,15 @@ int gw_client_fill_buffer_text(struct net_device *net_dev, char *buff, if (!gw_node->orig_node->router) continue;
- if (count < bytes_written + (2 * ETH_STR_LEN) + 30) - break; - - tmp_len = _write_buffer_text(buff, bytes_written, gw_node); + _write_buffer_text(seq, gw_node); gw_count++; - - hdr_len += tmp_len; - - if (off >= hdr_len) - continue; - - bytes_written += tmp_len; } rcu_read_unlock();
- if ((gw_count == 0) && (off == 0)) - bytes_written += sprintf(buff + bytes_written, - "No gateways in range ...\n"); + if (gw_count == 0) + seq_printf(seq, "No gateways in range ...\n");
- return bytes_written; + return 0; }
bool gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) diff --git a/batman-adv-kernelland/gateway_client.h b/batman-adv-kernelland/gateway_client.h index 38dc142..6a71cee 100644 --- a/batman-adv-kernelland/gateway_client.h +++ b/batman-adv-kernelland/gateway_client.h @@ -27,6 +27,5 @@ void gw_node_update(struct orig_node *orig_node, uint8_t new_gwflags); void gw_node_delete(struct orig_node *orig_node); void gw_node_purge_deleted(void); void gw_node_list_free(void); -int gw_client_fill_buffer_text(struct net_device *net_dev, char *buff, - size_t count, loff_t off); +int gw_client_seq_print_text(struct seq_file *seq, void *offset); bool gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb); diff --git a/batman-adv-kernelland/main.h b/batman-adv-kernelland/main.h index 730343e..ef2cbfd 100644 --- a/batman-adv-kernelland/main.h +++ b/batman-adv-kernelland/main.h @@ -123,6 +123,7 @@ extern int bat_debug_type(int type); #include <linux/workqueue.h> /* workqueue */ #include <net/sock.h> /* struct sock */ #include <linux/jiffies.h> +#include <linux/seq_file.h> #include "types.h"
#ifndef REVISION_VERSION diff --git a/batman-adv-kernelland/originator.c b/batman-adv-kernelland/originator.c index 2c84f0d..28e35b6 100644 --- a/batman-adv-kernelland/originator.c +++ b/batman-adv-kernelland/originator.c @@ -284,38 +284,31 @@ void purge_orig(struct work_struct *work) start_purge_timer(); }
-ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff, - size_t count, loff_t off) +int orig_seq_print_text(struct seq_file *seq, void *offset) { HASHIT(hashit); + struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); struct orig_node *orig_node; struct neigh_node *neigh_node; - size_t hdr_len, tmp_len; - int batman_count = 0, bytes_written = 0; + int batman_count = 0; unsigned long flags; char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
if ((!bat_priv->primary_if) || (bat_priv->primary_if->if_status != IF_ACTIVE)) { - if (off > 0) - return 0; - if (!bat_priv->primary_if) - return sprintf(buff, - "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + return seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name);
- return sprintf(buff, - "BATMAN mesh %s " - "disabled - primary interface not active\n", - net_dev->name); + return seq_printf(seq, "BATMAN mesh %s " + "disabled - primary interface not active\n", + net_dev->name); }
rcu_read_lock(); - hdr_len = sprintf(buff, - " %-14s (%s/%i) %17s [%10s]: %20s " + seq_printf(seq, " %-14s (%s/%i) %17s [%10s]: %20s " "... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s (%s)]\n", "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Potential nexthops", SOURCE_VERSION, REVISION_VERSION_STR, @@ -323,9 +316,6 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff, net_dev->name); rcu_read_unlock();
- if (off < hdr_len) - bytes_written = hdr_len; - spin_lock_irqsave(&orig_hash_lock, flags);
while (hash_iterate(orig_hash, &hashit)) { @@ -338,44 +328,29 @@ ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff, if (orig_node->router->tq_avg == 0) continue;
- /* estimated line length */ - if (count < bytes_written + 200) - break; - addr_to_string(orig_str, orig_node->orig); addr_to_string(router_str, orig_node->router->addr);
- tmp_len = sprintf(buff + bytes_written, - "%-17s (%3i) %17s [%10s]:", - orig_str, orig_node->router->tq_avg, - router_str, - orig_node->router->if_incoming->dev); + seq_printf(seq, "%-17s (%3i) %17s [%10s]:", + orig_str, orig_node->router->tq_avg, router_str, + orig_node->router->if_incoming->dev);
list_for_each_entry(neigh_node, &orig_node->neigh_list, list) { addr_to_string(orig_str, neigh_node->addr); - tmp_len += sprintf(buff + bytes_written + tmp_len, - " %17s (%3i)", orig_str, + seq_printf(seq, " %17s (%3i)", orig_str, neigh_node->tq_avg); }
- tmp_len += sprintf(buff + bytes_written + tmp_len, "\n"); - + seq_printf(seq, "\n"); batman_count++; - hdr_len += tmp_len; - - if (off >= hdr_len) - continue; - - bytes_written += tmp_len; }
spin_unlock_irqrestore(&orig_hash_lock, flags);
- if ((batman_count == 0) && (off == 0)) - bytes_written += sprintf(buff + bytes_written, - "No batman nodes in range ...\n"); + if ((batman_count == 0)) + seq_printf(seq, "No batman nodes in range ...\n");
- return bytes_written; + return 0; }
static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) diff --git a/batman-adv-kernelland/originator.h b/batman-adv-kernelland/originator.h index afbc7c0..e91e8a1 100644 --- a/batman-adv-kernelland/originator.h +++ b/batman-adv-kernelland/originator.h @@ -28,7 +28,6 @@ struct orig_node *get_orig_node(uint8_t *addr); struct neigh_node * create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint8_t *neigh, struct batman_if *if_incoming); -ssize_t orig_fill_buffer_text(struct net_device *net_dev, char *buff, - size_t count, loff_t off); +int orig_seq_print_text(struct seq_file *seq, void *offset); int orig_hash_add_if(struct batman_if *batman_if, int max_if_num); int orig_hash_del_if(struct batman_if *batman_if, int max_if_num); diff --git a/batman-adv-kernelland/translation-table.c b/batman-adv-kernelland/translation-table.c index 12880d5..009789e 100644 --- a/batman-adv-kernelland/translation-table.c +++ b/batman-adv-kernelland/translation-table.c @@ -161,59 +161,59 @@ int hna_local_fill_buffer(unsigned char *buff, int buff_len) return i; }
-int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff, - size_t count, loff_t off) +int hna_local_seq_print_text(struct seq_file *seq, void *offset) { + struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); struct hna_local_entry *hna_local_entry; HASHIT(hashit); - int bytes_written = 0; + HASHIT(hashit_count); unsigned long flags; - size_t hdr_len; + size_t buf_size, pos; + char *buff;
if (!bat_priv->primary_if) { - if (off == 0) - return sprintf(buff, - "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); - - return 0; + return seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); }
- hdr_len = sprintf(buff, - "Locally retrieved addresses (from %s) " - "announced via HNA:\n", - net_dev->name); - - if (off < hdr_len) - bytes_written = hdr_len; + seq_printf(seq, "Locally retrieved addresses (from %s) " + "announced via HNA:\n", + net_dev->name);
spin_lock_irqsave(&hna_local_hash_lock, flags);
+ buf_size = 1; + /* Estimate length for: " * xx:xx:xx:xx:xx:xx\n" */ + while (hash_iterate(hna_local_hash, &hashit_count)) + buf_size += 21; + + buff = kmalloc(buf_size, GFP_ATOMIC); + if (!buff) { + spin_unlock_irqrestore(&hna_local_hash_lock, flags); + return -ENOMEM; + } + buff[0] = '\0'; + pos = 0; + while (hash_iterate(hna_local_hash, &hashit)) { - hdr_len += 21; - - if (count < bytes_written + 22) - break; - - if (off >= hdr_len) - continue; - hna_local_entry = hashit.bucket->data;
- bytes_written += snprintf(buff + bytes_written, 22, - " * " MAC_FMT "\n", - hna_local_entry->addr[0], - hna_local_entry->addr[1], - hna_local_entry->addr[2], - hna_local_entry->addr[3], - hna_local_entry->addr[4], - hna_local_entry->addr[5]); + pos += snprintf(buff + pos, 22, " * " MAC_FMT "\n", + hna_local_entry->addr[0], + hna_local_entry->addr[1], + hna_local_entry->addr[2], + hna_local_entry->addr[3], + hna_local_entry->addr[4], + hna_local_entry->addr[5]); }
spin_unlock_irqrestore(&hna_local_hash_lock, flags); - return bytes_written; + + seq_printf(seq, "%s", buff); + kfree(buff); + return 0; }
static void _hna_local_del(void *data) @@ -379,64 +379,65 @@ void hna_global_add_orig(struct orig_node *orig_node, spin_unlock_irqrestore(&hna_global_hash_lock, flags); }
-int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff, - size_t count, loff_t off) +int hna_global_seq_print_text(struct seq_file *seq, void *offset) { + struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); struct hna_global_entry *hna_global_entry; HASHIT(hashit); - int bytes_written = 0; + HASHIT(hashit_count); unsigned long flags; - size_t hdr_len; + size_t buf_size, pos; + char *buff;
if (!bat_priv->primary_if) { - if (off == 0) - return sprintf(buff, - "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); - - return 0; + return seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); }
- hdr_len = sprintf(buff, - "Globally announced HNAs received via the mesh %s\n", - net_dev->name); - - if (off < hdr_len) - bytes_written = hdr_len; + seq_printf(seq, "Globally announced HNAs received via the mesh %s\n", + net_dev->name);
spin_lock_irqsave(&hna_global_hash_lock, flags);
+ buf_size = 1; + /* Estimate length for: " * xx:xx:xx:xx:xx:xx via xx:xx:xx:xx:xx:xx\n"*/ + while (hash_iterate(hna_global_hash, &hashit_count)) + buf_size += 43; + + buff = kmalloc(buf_size, GFP_ATOMIC); + if (!buff) { + spin_unlock_irqrestore(&hna_global_hash_lock, flags); + return -ENOMEM; + } + buff[0] = '\0'; + pos = 0; + while (hash_iterate(hna_global_hash, &hashit)) { - hdr_len += 43; - - if (count < bytes_written + 44) - break; - - if (off >= hdr_len) - continue; - hna_global_entry = hashit.bucket->data;
- bytes_written += snprintf(buff + bytes_written, 44, - " * " MAC_FMT " via " MAC_FMT "\n", - hna_global_entry->addr[0], - hna_global_entry->addr[1], - hna_global_entry->addr[2], - hna_global_entry->addr[3], - hna_global_entry->addr[4], - hna_global_entry->addr[5], - hna_global_entry->orig_node->orig[0], - hna_global_entry->orig_node->orig[1], - hna_global_entry->orig_node->orig[2], - hna_global_entry->orig_node->orig[3], - hna_global_entry->orig_node->orig[4], - hna_global_entry->orig_node->orig[5]); + pos += snprintf(buff + pos, 44, + " * " MAC_FMT " via " MAC_FMT "\n", + hna_global_entry->addr[0], + hna_global_entry->addr[1], + hna_global_entry->addr[2], + hna_global_entry->addr[3], + hna_global_entry->addr[4], + hna_global_entry->addr[5], + hna_global_entry->orig_node->orig[0], + hna_global_entry->orig_node->orig[1], + hna_global_entry->orig_node->orig[2], + hna_global_entry->orig_node->orig[3], + hna_global_entry->orig_node->orig[4], + hna_global_entry->orig_node->orig[5]); }
spin_unlock_irqrestore(&hna_global_hash_lock, flags); - return bytes_written; + + seq_printf(seq, "%s", buff); + kfree(buff); + return 0; }
void _hna_global_del_orig(struct hna_global_entry *hna_global_entry, diff --git a/batman-adv-kernelland/translation-table.h b/batman-adv-kernelland/translation-table.h index 8f412fc..8b3429e 100644 --- a/batman-adv-kernelland/translation-table.h +++ b/batman-adv-kernelland/translation-table.h @@ -25,15 +25,13 @@ int hna_local_init(void); void hna_local_add(uint8_t *addr); void hna_local_remove(uint8_t *addr, char *message); int hna_local_fill_buffer(unsigned char *buff, int buff_len); -int hna_local_fill_buffer_text(struct net_device *net_dev, char *buff, - size_t count, loff_t off); +int hna_local_seq_print_text(struct seq_file *seq, void *offset); void hna_local_purge(struct work_struct *work); void hna_local_free(void); int hna_global_init(void); void hna_global_add_orig(struct orig_node *orig_node, unsigned char *hna_buff, int hna_buff_len); -int hna_global_fill_buffer_text(struct net_device *net_dev, char *buff, - size_t count, loff_t off); +int hna_global_seq_print_text(struct seq_file *seq, void *offset); void _hna_global_del_orig(struct hna_global_entry *hna_global_entry, char *orig_str); void hna_global_del_orig(struct orig_node *orig_node, char *message); diff --git a/batman-adv-kernelland/vis.c b/batman-adv-kernelland/vis.c index 6b719bd..68ee903 100644 --- a/batman-adv-kernelland/vis.c +++ b/batman-adv-kernelland/vis.c @@ -116,7 +116,7 @@ static void vis_data_insert_interface(const uint8_t *interface, }
/* its a new address, add it to the list */ - entry = kmalloc(sizeof(*entry), GFP_KERNEL); + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) return; memcpy(entry->addr, interface, ETH_ALEN); @@ -143,12 +143,29 @@ static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list) return len; }
+static size_t vis_data_count_prim_sec(struct hlist_head *if_list) +{ + 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; + } + + return count; +} + /* read an entry */ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, uint8_t *src, bool primary) { - char to[40]; + char to[18];
+ /* maximal length: max(4+17+2, 3+17+1+3+2) == 26 */ addr_to_string(to, entry->dest); if (primary && entry->quality == 0) return sprintf(buff, "HNA %s, ", to); @@ -158,38 +175,74 @@ static ssize_t vis_data_read_entry(char *buff, struct vis_info_entry *entry, return 0; }
-ssize_t vis_fill_buffer_text(struct net_device *net_dev, char *buff, - size_t count, loff_t off) +int vis_seq_print_text(struct seq_file *seq, void *offset) { HASHIT(hashit); + HASHIT(hashit_count); struct vis_info *info; struct vis_info_entry *entries; + struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); HLIST_HEAD(vis_if_list); struct if_list_entry *entry; struct hlist_node *pos, *n; - size_t hdr_len, tmp_len; - int i, bytes_written = 0; + int i; char tmp_addr_str[ETH_STR_LEN]; unsigned long flags; int vis_server = atomic_read(&bat_priv->vis_mode); + size_t buff_pos, buf_size; + char *buff;
if ((!bat_priv->primary_if) || (vis_server == VIS_TYPE_CLIENT_UPDATE)) return 0;
- hdr_len = 0; - + buf_size = 1; + /* Estimate length */ spin_lock_irqsave(&vis_hash_lock, flags); + while (hash_iterate(vis_hash, &hashit_count)) { + info = hashit_count.bucket->data; + entries = (struct vis_info_entry *) + ((char *)info + sizeof(struct vis_info)); + + for (i = 0; i < info->packet.entries; i++) { + if (entries[i].quality == 0) + continue; + vis_data_insert_interface(entries[i].src, &vis_if_list, + compare_orig(entries[i].src, + info->packet.vis_orig)); + } + + hlist_for_each_entry(entry, pos, &vis_if_list, list) { + buf_size += 18 + 26 * info->packet.entries; + + /* add primary/secondary records */ + if (compare_orig(entry->addr, info->packet.vis_orig)) + buf_size += + vis_data_count_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); + } + } + + buff = kmalloc(buf_size, GFP_ATOMIC); + if (!buff) { + spin_unlock_irqrestore(&vis_hash_lock, flags); + return -ENOMEM; + } + buff[0] = '\0'; + buff_pos = 0; + while (hash_iterate(vis_hash, &hashit)) { info = hashit.bucket->data; entries = (struct vis_info_entry *) ((char *)info + sizeof(struct vis_info));
- /* estimated line length */ - if (count < bytes_written + 200) - break; - for (i = 0; i < info->packet.entries; i++) { if (entries[i].quality == 0) continue; @@ -200,30 +253,22 @@ ssize_t vis_fill_buffer_text(struct net_device *net_dev, char *buff,
hlist_for_each_entry(entry, pos, &vis_if_list, list) { addr_to_string(tmp_addr_str, entry->addr); - tmp_len = sprintf(buff + bytes_written, - "%s,", tmp_addr_str); + buff_pos += sprintf(buff + buff_pos, "%s,", + tmp_addr_str);
for (i = 0; i < info->packet.entries; i++) - tmp_len += vis_data_read_entry( - buff + bytes_written + tmp_len, - &entries[i], entry->addr, - entry->primary); + buff_pos += vis_data_read_entry(buff + buff_pos, + &entries[i], + entry->addr, + entry->primary);
/* add primary/secondary records */ if (compare_orig(entry->addr, info->packet.vis_orig)) - tmp_len += vis_data_read_prim_sec( - buff + bytes_written + tmp_len, - &vis_if_list); + buff_pos += + vis_data_read_prim_sec(buff + buff_pos, + &vis_if_list);
- tmp_len += sprintf(buff + bytes_written + tmp_len, - "\n"); - - hdr_len += tmp_len; - - if (off >= hdr_len) - continue; - - bytes_written += tmp_len; + buff_pos += sprintf(buff + buff_pos, "\n"); }
hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) { @@ -231,9 +276,13 @@ ssize_t vis_fill_buffer_text(struct net_device *net_dev, char *buff, kfree(entry); } } + spin_unlock_irqrestore(&vis_hash_lock, flags);
- return bytes_written; + seq_printf(seq, "%s", buff); + kfree(buff); + + return 0; }
/* add the info packet to the send list, if it was not diff --git a/batman-adv-kernelland/vis.h b/batman-adv-kernelland/vis.h index 9c1fd77..5dd6521 100644 --- a/batman-adv-kernelland/vis.h +++ b/batman-adv-kernelland/vis.h @@ -47,8 +47,7 @@ struct recvlist_node { extern struct hashtable_t *vis_hash; extern spinlock_t vis_hash_lock;
-ssize_t vis_fill_buffer_text(struct net_device *net_dev, char *buff, - size_t count, loff_t off); +int vis_seq_print_text(struct seq_file *seq, void *offset); void receive_server_sync_packet(struct bat_priv *bat_priv, struct vis_packet *vis_packet, int vis_info_len);