Commit 57cdda7e authored by Chas Williams's avatar Chas Williams Committed by Hideaki Yoshifuji

[ATM]: seq_file conversion of /proc/net/atm [7/8]

seq_file support for /proc/net/atm/lec:
- lec_info(): seq_printf/seq_putc replaces sprintf;
- traversal of the lec structure needs to walk:
  -> the lec interfaces
     -> the tables of arp tables(lec_arp_tables);
        -> the arp tables themselves
     -> the misc tables (lec_arp_empty_ones/lec_no_forward/mcast_fwds)

  Sum up of the call tree:
  atm_lec_seq_start()/atm_lec_seq_next()
  -> atm_lec_get_idx()
     -> atm_lec_itf_walk() (responsible for dev_lec/dev_put handling)
        -> atm_lec_priv_walk() (responsible for lec_priv locking)
           -> atm_lec_arp_walk()
              -> atm_lec_tbl_walk()
           -> atm_lec_misc_walk()
              -> atm_lec_tbl_walk()

  Each of the dedicated functions follows the same convention: return NULL
  as long as the seq_file cursor hasn't been digested (i.e. until < 0).
  Locking is only done when an entry (i.e. a lec_arp_table) is referenced.
  atm_lec_seq_stop()/atm_lec_itf_walk()/atm_lec_priv_walk() are responsible
  for getting this point right.
- module refcounting is done in atm_lec_seq_open()/atm_lec_seq_release();
- atm_lec_info() is removed.

Chas's suggestions applied since last version:
- atm_seq_lec_fops renamed to lec_seq_fops;
- change in state handling: it wasn't correctly set to its reset value
  after a complete interface walk;
- lec_arp_get_status_string() bugfix.
parent c330a7d8
...@@ -335,54 +335,46 @@ static void svc_info(struct seq_file *seq, struct atm_vcc *vcc) ...@@ -335,54 +335,46 @@ static void svc_info(struct seq_file *seq, struct atm_vcc *vcc)
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
static char* static char* lec_arp_get_status_string(unsigned char status)
lec_arp_get_status_string(unsigned char status) {
{ static char *lec_arp_status_string[] = {
switch(status) { "ESI_UNKNOWN ",
case ESI_UNKNOWN: "ESI_ARP_PENDING ",
return "ESI_UNKNOWN "; "ESI_VC_PENDING ",
case ESI_ARP_PENDING: "<Unknown> ",
return "ESI_ARP_PENDING "; "ESI_FLUSH_PENDING ",
case ESI_VC_PENDING: "ESI_FORWARD_DIRECT",
return "ESI_VC_PENDING "; "<Undefined>"
case ESI_FLUSH_PENDING: };
return "ESI_FLUSH_PENDING ";
case ESI_FORWARD_DIRECT: if (status > ESI_FORWARD_DIRECT)
return "ESI_FORWARD_DIRECT"; status = ESI_FORWARD_DIRECT + 1;
default: return lec_arp_status_string[status];
return "<Unknown> ";
}
} }
static void static void lec_info(struct seq_file *seq, struct lec_arp_table *entry)
lec_info(struct lec_arp_table *entry, char *buf)
{ {
int j, offset=0; int i;
for(j=0;j<ETH_ALEN;j++) { for (i = 0; i < ETH_ALEN; i++)
offset+=sprintf(buf+offset,"%2.2x",0xff&entry->mac_addr[j]); seq_printf(seq, "%2.2x", entry->mac_addr[i] & 0xff);
} seq_printf(seq, " ");
offset+=sprintf(buf+offset, " "); for (i = 0; i < ATM_ESA_LEN; i++)
for(j=0;j<ATM_ESA_LEN;j++) { seq_printf(seq, "%2.2x", entry->atm_addr[i] & 0xff);
offset+=sprintf(buf+offset,"%2.2x",0xff&entry->atm_addr[j]); seq_printf(seq, " %s %4.4x", lec_arp_get_status_string(entry->status),
} entry->flags & 0xffff);
offset+=sprintf(buf+offset, " %s %4.4x", if (entry->vcc)
lec_arp_get_status_string(entry->status), seq_printf(seq, "%3d %3d ", entry->vcc->vpi, entry->vcc->vci);
entry->flags&0xffff); else
if (entry->vcc) { seq_printf(seq, " ");
offset+=sprintf(buf+offset, "%3d %3d ", entry->vcc->vpi,
entry->vcc->vci);
} else
offset+=sprintf(buf+offset, " ");
if (entry->recv_vcc) { if (entry->recv_vcc) {
offset+=sprintf(buf+offset, " %3d %3d", seq_printf(seq, " %3d %3d", entry->recv_vcc->vpi,
entry->recv_vcc->vpi, entry->recv_vcc->vci); entry->recv_vcc->vci);
} }
seq_putc(seq, '\n');
sprintf(buf+offset,"\n");
} }
#endif #endif /* CONFIG_ATM_LANE */
static int atm_dev_seq_show(struct seq_file *seq, void *v) static int atm_dev_seq_show(struct seq_file *seq, void *v)
{ {
...@@ -674,78 +666,216 @@ static struct file_operations arp_seq_fops = { ...@@ -674,78 +666,216 @@ static struct file_operations arp_seq_fops = {
#endif /* CONFIG_ATM_CLIP */ #endif /* CONFIG_ATM_CLIP */
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
static int atm_lec_info(loff_t pos,char *buf)
{ struct lec_state {
unsigned long flags; unsigned long flags;
struct lec_priv *priv; struct lec_priv *locked;
struct lec_arp_table *entry; struct lec_arp_table *entry;
int i, count, d, e;
struct net_device *dev; struct net_device *dev;
int itf;
int arp_table;
int misc_table;
};
if (!pos) { static void *lec_tbl_walk(struct lec_state *state, struct lec_arp_table *tbl,
return sprintf(buf,"Itf MAC ATM destination" loff_t *l)
" Status Flags " {
"VPI/VCI Recv VPI/VCI\n"); struct lec_arp_table *e = state->entry;
if (!e)
e = tbl;
if (e == (void *)1) {
e = tbl;
--*l;
} }
if (!try_atm_lane_ops()) for (; e; e = e->next) {
return 0; /* the lane module is not there yet */ if (--*l < 0)
break;
count = pos;
for(d = 0; d < MAX_LEC_ITF; d++) {
dev = atm_lane_ops->get_lec(d);
if (!dev || !(priv = (struct lec_priv *) dev->priv))
continue;
spin_lock_irqsave(&priv->lec_arp_lock, flags);
for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
for(entry = priv->lec_arp_tables[i]; entry; entry = entry->next) {
if (--count)
continue;
e = sprintf(buf,"%s ", dev->name);
lec_info(entry, buf+e);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
dev_put(dev);
module_put(atm_lane_ops->owner);
return strlen(buf);
} }
state->entry = e;
return (*l < 0) ? state : NULL;
}
static void *lec_arp_walk(struct lec_state *state, loff_t *l,
struct lec_priv *priv)
{
void *v = NULL;
int p;
for (p = state->arp_table; p < LEC_ARP_TABLE_SIZE; p++) {
v = lec_tbl_walk(state, priv->lec_arp_tables[p], l);
if (v)
break;
} }
for(entry = priv->lec_arp_empty_ones; entry; entry = entry->next) { state->arp_table = p;
if (--count) return v;
continue; }
e = sprintf(buf,"%s ", dev->name);
lec_info(entry, buf+e); static void *lec_misc_walk(struct lec_state *state, loff_t *l,
spin_unlock_irqrestore(&priv->lec_arp_lock, flags); struct lec_priv *priv)
dev_put(dev); {
module_put(atm_lane_ops->owner); struct lec_arp_table *lec_misc_tables[] = {
return strlen(buf); priv->lec_arp_empty_ones,
} priv->lec_no_forward,
for(entry = priv->lec_no_forward; entry; entry=entry->next) { priv->mcast_fwds
if (--count) };
continue; void *v = NULL;
e = sprintf(buf,"%s ", dev->name); int q;
lec_info(entry, buf+e);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags); for (q = state->misc_table; q < ARRAY_SIZE(lec_misc_tables); q++) {
dev_put(dev); v = lec_tbl_walk(state, lec_misc_tables[q], l);
module_put(atm_lane_ops->owner); if (v)
return strlen(buf); break;
} }
for(entry = priv->mcast_fwds; entry; entry = entry->next) { state->misc_table = q;
if (--count) return v;
continue; }
e = sprintf(buf,"%s ", dev->name);
lec_info(entry, buf+e); static void *lec_priv_walk(struct lec_state *state, loff_t *l,
spin_unlock_irqrestore(&priv->lec_arp_lock, flags); struct lec_priv *priv)
dev_put(dev); {
module_put(atm_lane_ops->owner); if (!state->locked) {
return strlen(buf); state->locked = priv;
spin_lock_irqsave(&priv->lec_arp_lock, state->flags);
} }
spin_unlock_irqrestore(&priv->lec_arp_lock, flags); if (!lec_arp_walk(state, l, priv) &&
!lec_misc_walk(state, l, priv)) {
spin_unlock_irqrestore(&priv->lec_arp_lock, state->flags);
state->locked = NULL;
/* Partial state reset for the next time we get called */
state->arp_table = state->misc_table = 0;
}
return state->locked;
}
static void *lec_itf_walk(struct lec_state *state, loff_t *l)
{
struct net_device *dev;
void *v;
dev = state->dev ? state->dev : atm_lane_ops->get_lec(state->itf);
v = (dev && dev->priv) ? lec_priv_walk(state, l, dev->priv) : NULL;
if (!v && dev) {
dev_put(dev); dev_put(dev);
/* Partial state reset for the next time we get called */
dev = NULL;
}
state->dev = dev;
return v;
}
static void *lec_get_idx(struct lec_state *state, loff_t l)
{
void *v = NULL;
for (; state->itf < MAX_LEC_ITF; state->itf++) {
v = lec_itf_walk(state, &l);
if (v)
break;
}
return v;
}
static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
{
struct lec_state *state = seq->private;
state->itf = 0;
state->dev = NULL;
state->locked = NULL;
state->arp_table = 0;
state->misc_table = 0;
state->entry = (void *)1;
return *pos ? lec_get_idx(state, *pos) : (void*)1;
}
static void lec_seq_stop(struct seq_file *seq, void *v)
{
struct lec_state *state = seq->private;
if (state->dev) {
spin_unlock_irqrestore(&state->locked->lec_arp_lock,
state->flags);
dev_put(state->dev);
}
}
static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct lec_state *state = seq->private;
v = lec_get_idx(state, 1);
*pos += !!PTR_ERR(v);
return v;
}
static int lec_seq_show(struct seq_file *seq, void *v)
{
static char lec_banner[] = "Itf MAC ATM destination"
" Status Flags "
"VPI/VCI Recv VPI/VCI\n";
if (v == (void *)1)
seq_puts(seq, lec_banner);
else {
struct lec_state *state = seq->private;
struct net_device *dev = state->dev;
seq_printf(seq, "%s ", dev->name);
lec_info(seq, state->entry);
} }
module_put(atm_lane_ops->owner);
return 0; return 0;
} }
#endif
static struct seq_operations lec_seq_ops = {
.start = lec_seq_start,
.next = lec_seq_next,
.stop = lec_seq_stop,
.show = lec_seq_show,
};
static int lec_seq_open(struct inode *inode, struct file *file)
{
struct lec_state *state;
struct seq_file *seq;
int rc = -EAGAIN;
if (!try_atm_lane_ops())
goto out;
state = kmalloc(sizeof(*state), GFP_KERNEL);
if (!state) {
rc = -ENOMEM;
goto out;
}
rc = seq_open(file, &lec_seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = state;
out:
return rc;
out_kfree:
kfree(state);
goto out;
}
static int lec_seq_release(struct inode *inode, struct file *file)
{
module_put(atm_lane_ops->owner);
return seq_release_private(inode, file);
}
static struct file_operations lec_seq_fops = {
.open = lec_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = lec_seq_release,
};
#endif /* CONFIG_ATM_LANE */
static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count, static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count,
loff_t *pos) loff_t *pos)
...@@ -890,7 +1020,7 @@ int __init atm_proc_init(void) ...@@ -890,7 +1020,7 @@ int __init atm_proc_init(void)
CREATE_SEQ_ENTRY(arp); CREATE_SEQ_ENTRY(arp);
#endif #endif
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
CREATE_ENTRY(lec); CREATE_SEQ_ENTRY(lec);
#endif #endif
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment