]> git.neil.brown.name Git - history.git/commitdiff
[NET] convert /proc/net/anycast6 to seq_file
authorHideaki Yoshifuji <yoshfuji@linux-ipv6.org>
Wed, 2 Jul 2003 02:23:52 +0000 (12:23 +1000)
committerJames Morris <jmorris@kernel.bkbits.net>
Wed, 2 Jul 2003 02:23:52 +0000 (12:23 +1000)
net/ipv6/af_inet6.c
net/ipv6/anycast.c

index faa34b2ff842422720c057c45408f2feddd6292b..aaed34eba0a7dfb5d0ce8b371c62f4256eede9ea 100644 (file)
@@ -85,7 +85,8 @@ extern int udp6_proc_init(void);
 extern void udp6_proc_exit(void);
 extern int ipv6_misc_proc_init(void);
 extern void ipv6_misc_proc_exit(void);
-extern int anycast6_get_info(char *, char **, off_t, int);
+extern int ac6_proc_init(void);
+extern void ac6_proc_exit(void);
 extern int if6_proc_init(void);
 extern void if6_proc_exit(void);
 #endif
@@ -799,7 +800,7 @@ static int __init inet6_init(void)
        if (ipv6_misc_proc_init())
                goto proc_misc6_fail;
 
-       if (!proc_net_create("anycast6", 0, anycast6_get_info))
+       if (ac6_proc_init())
                goto proc_anycast6_fail;
        if (if6_proc_init())
                goto proc_if6_fail;
@@ -825,7 +826,7 @@ static int __init inet6_init(void)
 
 #ifdef CONFIG_PROC_FS
 proc_if6_fail:
-       proc_net_remove("anycast6");
+       ac6_proc_exit();
 proc_anycast6_fail:
        ipv6_misc_proc_exit();
 proc_misc6_fail:
@@ -863,7 +864,7 @@ static void inet6_exit(void)
        sock_unregister(PF_INET6);
 #ifdef CONFIG_PROC_FS
        if6_proc_exit();
-       proc_net_remove("anycast6");
+       ac6_proc_exit();
        ipv6_misc_proc_exit();
        udp6_proc_exit();
        tcp6_proc_exit();
index 5dcfcf8a121f74adf94e4b9185df6022ccf13927..ff77920a52c332fe7d41958bfbe0ab5ade130187 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/route.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 #include <net/sock.h>
 #include <net/snmp.h>
@@ -435,56 +436,159 @@ int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr)
 
 
 #ifdef CONFIG_PROC_FS
-int anycast6_get_info(char *buffer, char **start, off_t offset, int length)
-{
-       off_t pos=0, begin=0;
-       struct ifacaddr6 *im;
-       int len=0;
+struct ac6_iter_state {
        struct net_device *dev;
-       
-       read_lock(&dev_base_lock);
-       for (dev = dev_base; dev; dev = dev->next) {
-               struct inet6_dev *idev;
+       struct inet6_dev *idev;
+};
 
-               if ((idev = in6_dev_get(dev)) == NULL)
-                       continue;
+#define ac6_seq_private(seq)   ((struct ac6_iter_state *)&seq->private)
 
+static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
+{
+       struct ifacaddr6 *im = NULL;
+       struct ac6_iter_state *state = ac6_seq_private(seq);
+
+       for (state->dev = dev_base, state->idev = NULL;
+            state->dev;
+            state->dev = state->dev->next) {
+               struct inet6_dev *idev;
+               idev = in6_dev_get(state->dev);
+               if (!idev)
+                       continue;
                read_lock_bh(&idev->lock);
-               for (im = idev->ac_list; im; im = im->aca_next) {
-                       int i;
-
-                       len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name);
-
-                       for (i=0; i<16; i++)
-                               len += sprintf(buffer+len, "%02x", im->aca_addr.s6_addr[i]);
-
-                       len += sprintf(buffer+len, " %5d\n", im->aca_users);
-
-                       pos=begin+len;
-                       if (pos < offset) {
-                               len=0;
-                               begin=pos;
-                       }
-                       if (pos > offset+length) {
-                               read_unlock_bh(&idev->lock);
-                               in6_dev_put(idev);
-                               goto done;
-                       }
+               im = idev->ac_list;
+               if (im) {
+                       state->idev = idev;
+                       break;
                }
                read_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
        }
+       return im;
+}
+
+static struct ifacaddr6 *ac6_get_next(struct seq_file *seq, struct ifacaddr6 *im)
+{
+       struct ac6_iter_state *state = ac6_seq_private(seq);
+
+       im = im->aca_next;
+       while (!im) {
+               if (likely(state->idev != NULL)) {
+                       read_unlock_bh(&state->idev->lock);
+                       in6_dev_put(state->idev);
+               }
+               state->dev = state->dev->next;
+               if (!state->dev) {
+                       state->idev = NULL;
+                       break;
+               }
+               state->idev = in6_dev_get(state->dev);
+               if (!state->idev)
+                       continue;
+               read_lock_bh(&state->idev->lock);
+               im = state->idev->ac_list;
+       }
+       return im;
+}
+
+static struct ifacaddr6 *ac6_get_idx(struct seq_file *seq, loff_t pos)
+{
+       struct ifacaddr6 *im = ac6_get_first(seq);
+       if (im)
+               while (pos && (im = ac6_get_next(seq, im)) != NULL)
+                       --pos;
+       return pos ? NULL : im;
+}
 
-done:
+static void *ac6_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       read_lock(&dev_base_lock);
+       return *pos ? ac6_get_idx(seq, *pos) : ac6_get_first(seq);
+}
+
+static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct ifacaddr6 *im;
+       im = ac6_get_next(seq, v);
+       ++*pos;
+       return im;
+}
+
+static void ac6_seq_stop(struct seq_file *seq, void *v)
+{
+       struct ac6_iter_state *state = ac6_seq_private(seq);
+       if (likely(state->idev != NULL)) {
+               read_unlock_bh(&state->idev->lock);
+               in6_dev_put(state->idev);
+       }
        read_unlock(&dev_base_lock);
+}
 
-       *start=buffer+(offset-begin);
-       len-=(offset-begin);
-       if(len>length)
-               len=length;
-       if (len<0)
-               len=0;
-       return len;
+static int ac6_seq_show(struct seq_file *seq, void *v)
+{
+       struct ifacaddr6 *im = (struct ifacaddr6 *)v;
+       struct ac6_iter_state *state = ac6_seq_private(seq);
+
+       seq_printf(seq,
+                  "%-4d %-15s "
+                  "%04x%04x%04x%04x%04x%04x%04x%04x "
+                  "%5d\n",
+                  state->dev->ifindex, state->dev->name,
+                  NIP6(im->aca_addr),
+                  im->aca_users);
+       return 0;
 }
 
+static struct seq_operations ac6_seq_ops = {
+       .start  =       ac6_seq_start,
+       .next   =       ac6_seq_next,
+       .stop   =       ac6_seq_stop,
+       .show   =       ac6_seq_show,
+};
+
+static int ac6_seq_open(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq;
+       int rc = -ENOMEM;
+       struct ac6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+       if (!s)
+               goto out;
+
+       rc = seq_open(file, &ac6_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 ac6_seq_fops = {
+       .owner          =       THIS_MODULE,
+       .open           =       ac6_seq_open,
+       .read           =       seq_read,
+       .llseek         =       seq_lseek,
+       .release        =       seq_release_private,
+};
+
+int __init ac6_proc_init(void)
+{
+       struct proc_dir_entry *p;
+
+       p = create_proc_entry("anycast6", S_IRUGO, proc_net);
+       if (p)
+               p->proc_fops = &ac6_seq_fops;
+       return 0;
+}
+
+void ac6_proc_exit(void)
+{
+       proc_net_remove("anycast6");
+}
 #endif
+