[PATCH] seq_file conversion 1/5: /proc/net/igmp
From: YOSHIFUJI Hideaki / 吉藤英明 <hidden>
Date: 2003-07-01 05:48:47
1/5: convert /proc/net/igmp to seq_file Index: linux-2.5/include/net/ip.h =================================================================== RCS file: /home/cvs/linux-2.5/include/net/ip.h,v retrieving revision 1.20 diff -u -r1.20 ip.h
--- linux-2.5/include/net/ip.h 7 Jun 2003 00:22:34 -0000 1.20
+++ linux-2.5/include/net/ip.h 30 Jun 2003 15:28:13 -0000@@ -79,7 +79,7 @@ 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: linux-2.5/net/ipv4/igmp.c =================================================================== RCS file: /home/cvs/linux-2.5/net/ipv4/igmp.c,v retrieving revision 1.28 diff -u -r1.28 igmp.c
--- linux-2.5/net/ipv4/igmp.c 26 Jun 2003 03:45:59 -0000 1.28
+++ linux-2.5/net/ipv4/igmp.c 30 Jun 2003 15:28:13 -0000@@ -99,7 +99,10 @@ #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 @@ return rv; } - -int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length) -{ - off_t pos=0, begin=0; - struct ip_mc_list *im; - int len=0; +#if defined(CONFIG_PROC_FS) +struct igmp_mc_iter_state { struct net_device *dev; + struct in_device *in_dev; +}; - len=sprintf(buffer,"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n"); +#define igmp_mc_seq_private(seq) ((struct igmp_mc_iter_state *)&seq->private) - 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"; +static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) +{ + struct ip_mc_list *im = NULL; + struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); - if (in_dev == NULL) + 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; - -#ifdef CONFIG_IP_MULTICAST - querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2"; -#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; - } + im = in_dev->mc_list; + if (im) { + state->in_dev = in_dev; + break; } read_unlock(&in_dev->lock); - in_dev_put(in_dev); } -done: + 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; +} + +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); + return *pos ? igmp_mc_get_idx(seq, *pos) : (void *)1; +} + +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); +} - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - if(len<0) - len=0; - return len; +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(state->in_dev) ? "V1" : "V2"; +#else + querier = "NONE"; +#endif + + 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); + } + + 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); + } + return 0; +} + +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;
@@ -2213,4 +2313,16 @@ len=0; 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: linux-2.5/net/ipv4/ip_output.c =================================================================== RCS file: /home/cvs/linux-2.5/net/ipv4/ip_output.c,v retrieving revision 1.34 diff -u -r1.34 ip_output.c
--- linux-2.5/net/ipv4/ip_output.c 21 Jun 2003 16:20:41 -0000 1.34
+++ linux-2.5/net/ipv4/ip_output.c 30 Jun 2003 15:28:13 -0000@@ -1314,7 +1314,7 @@ 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); }
--
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA