]> git.neil.brown.name Git - history.git/commitdiff
[NET] convert /proc/net/igmp to seq_file
authorHideaki Yoshifuji <yoshfuji@linux-ipv6.org>
Wed, 2 Jul 2003 02:20:28 +0000 (12:20 +1000)
committerJames Morris <jmorris@kernel.bkbits.net>
Wed, 2 Jul 2003 02:20:28 +0000 (12:20 +1000)
include/net/ip.h
net/ipv4/igmp.c
net/ipv4/ip_output.c

index aa8dd8855dfacc137541e0b64866855337753df3..a3ec7ce911ed09f3def3b305b4c952721a38cd5b 100644 (file)
@@ -79,7 +79,7 @@ extern rwlock_t ip_ra_lock;
 
 extern void            ip_mc_dropsocket(struct sock *);
 extern void            ip_mc_dropdevice(struct net_device *dev);
-extern int             ip_mc_procinfo(char *, char **, off_t, int);
+extern int             igmp_mc_proc_init(void);
 extern int             ip_mcf_procinfo(char *, char **, off_t, int);
 
 /*
index 01674a93babe8313f88d70655517577c5b0b5af0..58a0662b43831447861969f74e85fe11d2632dce 100644 (file)
 #ifdef CONFIG_IP_MROUTE
 #include <linux/mroute.h>
 #endif
-
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#endif
 
 #define IP_MAX_MEMBERSHIPS 20
 
@@ -2090,65 +2093,162 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
        return rv;
 }
 
+#if defined(CONFIG_PROC_FS)
+struct igmp_mc_iter_state {
+       struct net_device *dev;
+       struct in_device *in_dev;
+};
+
+#define        igmp_mc_seq_private(seq)        ((struct igmp_mc_iter_state *)&seq->private)
 
-int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
+static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
 {
-       off_t pos=0, begin=0;
-       struct ip_mc_list *im;
-       int len=0;
-       struct net_device *dev;
+       struct ip_mc_list *im = NULL;
+       struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
+
+       for (state->dev = dev_base, state->in_dev = NULL;
+            state->dev; 
+            state->dev = state->dev->next) {
+               struct in_device *in_dev;
+               in_dev = in_dev_get(state->dev);
+               if (!in_dev)
+                       continue;
+               read_lock(&in_dev->lock);
+               im = in_dev->mc_list;
+               if (im) {
+                       state->in_dev = in_dev;
+                       break;
+               }
+               read_unlock(&in_dev->lock);
+       }
+       return im;
+}
+
+static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_list *im)
+{
+       struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
+       im = im->next;
+       while (!im) {
+               if (likely(state->in_dev != NULL)) {
+                       read_unlock(&state->in_dev->lock);
+                       in_dev_put(state->in_dev);
+               }
+               state->dev = state->dev->next;
+               if (!state->dev) {
+                       state->in_dev = NULL;
+                       break;
+               }
+               state->in_dev = in_dev_get(state->dev);
+               if (!state->in_dev)
+                       continue;
+               read_lock(&state->in_dev->lock);
+               im = state->in_dev->mc_list;
+       }
+       return im;
+}
 
-       len=sprintf(buffer,"Idx\tDevice    : Count Querier\tGroup    Users Timer\tReporter\n");  
+static struct ip_mc_list *igmp_mc_get_idx(struct seq_file *seq, loff_t pos)
+{
+       struct ip_mc_list *im = igmp_mc_get_first(seq);
+       if (im)
+               while (pos && (im = igmp_mc_get_next(seq, im)) != NULL)
+                       --pos;
+       return pos ? NULL : im;
+}
 
+static void *igmp_mc_seq_start(struct seq_file *seq, loff_t *pos)
+{
        read_lock(&dev_base_lock);
-       for(dev = dev_base; dev; dev = dev->next) {
-               struct in_device *in_dev = in_dev_get(dev);
-               char   *querier = "NONE";
+       return *pos ? igmp_mc_get_idx(seq, *pos) : (void *)1;
+}
 
-               if (in_dev == NULL)
-                       continue;
+static void *igmp_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct ip_mc_list *im;
+       if (v == (void *)1)
+               im = igmp_mc_get_first(seq);
+       else
+               im = igmp_mc_get_next(seq, v);
+       ++*pos;
+       return im;
+}
+
+static void igmp_mc_seq_stop(struct seq_file *seq, void *v)
+{
+       struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
+       if (likely(state->in_dev != NULL)) {
+               read_unlock(&state->in_dev->lock);
+               in_dev_put(state->in_dev);
+       }
+       read_unlock(&dev_base_lock);
+}
 
+static int igmp_mc_seq_show(struct seq_file *seq, void *v)
+{
+       if (v == (void *)1)
+               seq_printf(seq, 
+                          "Idx\tDevice    : Count Querier\tGroup    Users Timer\tReporter\n");
+       else {
+               struct ip_mc_list *im = (struct ip_mc_list *)v;
+               struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
+               char   *querier;
 #ifdef CONFIG_IP_MULTICAST
-               querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2";
+               querier = IGMP_V1_SEEN(state->in_dev) ? "V1" : "V2";
+#else
+               querier = "NONE";
 #endif
 
-               len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n",
-                            dev->ifindex, dev->name, dev->mc_count, querier);
-
-               read_lock(&in_dev->lock);
-               for (im = in_dev->mc_list; im; im = im->next) {
-                       len+=sprintf(buffer+len,
-                                    "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
-                                    im->multiaddr, im->users,
-                                    im->tm_running, im->timer.expires-jiffies, im->reporter);
-
-                       pos=begin+len;
-                       if(pos<offset)
-                       {
-                               len=0;
-                               begin=pos;
-                       }
-                       if(pos>offset+length) {
-                               read_unlock(&in_dev->lock);
-                               in_dev_put(in_dev);
-                               goto done;
-                       }
+               if (state->in_dev->mc_list == im) {
+                       seq_printf(seq, "%d\t%-10s: %5d %7s\n",
+                                  state->dev->ifindex, state->dev->name, state->dev->mc_count, querier);
                }
-               read_unlock(&in_dev->lock);
-               in_dev_put(in_dev);
+
+               seq_printf(seq,
+                          "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
+                          im->multiaddr, im->users,
+                          im->tm_running, im->timer.expires-jiffies, im->reporter);
        }
-done:
-       read_unlock(&dev_base_lock);
+       return 0;
+}
 
-       *start=buffer+(offset-begin);
-       len-=(offset-begin);
-       if(len>length)
-               len=length;
-       if(len<0)
-               len=0;
-       return len;
+static struct seq_operations igmp_mc_seq_ops = {
+       .start  =       igmp_mc_seq_start,
+       .next   =       igmp_mc_seq_next,
+       .stop   =       igmp_mc_seq_stop,
+       .show   =       igmp_mc_seq_show,
+};
+
+static int igmp_mc_seq_open(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq;
+       int rc = -ENOMEM;
+       struct igmp_mc_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+       if (!s)
+               goto out;
+       rc = seq_open(file, &igmp_mc_seq_ops);
+       if (rc)
+               goto out_kfree;
+
+       seq = file->private_data;
+       seq->private = s;
+       memset(s, 0, sizeof(*s));
+out:
+       return rc;
+out_kfree:
+       kfree(s);
+       goto out;
 }
 
+static struct file_operations igmp_mc_seq_fops = {
+       .owner          =       THIS_MODULE,
+       .open           =       igmp_mc_seq_open,
+       .read           =       seq_read,
+       .llseek         =       seq_lseek,
+       .release        =       seq_release_private,
+};
+#endif
+
 int ip_mcf_procinfo(char *buffer, char **start, off_t offset, int length)
 {
        off_t pos=0, begin=0;
@@ -2214,3 +2314,15 @@ done:
        return len;
 }
 
+#ifdef CONFIG_PROC_FS
+int __init igmp_mc_proc_init(void)
+{
+       struct proc_dir_entry *p;
+
+       p = create_proc_entry("igmp", S_IRUGO, proc_net);
+       if (p)
+               p->proc_fops = &igmp_mc_seq_fops;
+       return 0;
+}
+#endif
+
index 7a736073666eb558948f7c6ed6506a11fd10dbe2..32c54938669f5c46376a4ba76512e21e0c3aabc4 100644 (file)
@@ -1314,7 +1314,7 @@ void __init ip_init(void)
        inet_initpeers();
 
 #ifdef CONFIG_IP_MULTICAST
-       proc_net_create("igmp", 0, ip_mc_procinfo);
+       igmp_mc_proc_init();
 #endif
        proc_net_create("mcfilter", 0, ip_mcf_procinfo);
 }