diff options
author | Chas Williams <chas@cmf.nrl.navy.mil> | 2006-09-29 17:16:48 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-09-29 17:16:48 -0700 |
commit | 33a9c2d4b758279c5077fc15d221b385a574ae0b (patch) | |
tree | adcaad67bd057b2d8200bae2219710c920c586f5 /net/atm | |
parent | 987e46bdf314c55e060570ff46723d770e461f0e (diff) | |
download | blackbird-op-linux-33a9c2d4b758279c5077fc15d221b385a574ae0b.tar.gz blackbird-op-linux-33a9c2d4b758279c5077fc15d221b385a574ae0b.zip |
[ATM]: [lec] add reference counting to lec_arp entries
Signed-off-by: Chas Williams <chas@cmf.nrl.navy.mil>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/atm')
-rw-r--r-- | net/atm/lec.c | 42 | ||||
-rw-r--r-- | net/atm/lec_arpc.h | 1 |
2 files changed, 29 insertions, 14 deletions
diff --git a/net/atm/lec.c b/net/atm/lec.c index 29acfb0e6d04..c5d1f9e9a647 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -107,6 +107,19 @@ static void lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, struct sk_buff *skb)); static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc); +/* must be done under lec_arp_lock */ +static inline void lec_arp_hold(struct lec_arp_table *entry) +{ + atomic_inc(&entry->usage); +} + +static inline void lec_arp_put(struct lec_arp_table *entry) +{ + if (atomic_dec_and_test(&entry->usage)) + kfree(entry); +} + + static struct lane2_ops lane2_ops = { lane2_resolve, /* resolve, spec 3.1.3 */ lane2_associate_req, /* associate_req, spec 3.1.4 */ @@ -795,7 +808,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) entry = lec_arp_find(priv, src); if (entry && entry->vcc != vcc) { lec_arp_remove(priv, entry); - kfree(entry); + lec_arp_put(entry); } } spin_unlock_irqrestore(&priv->lec_arp_lock, flags); @@ -1726,7 +1739,7 @@ static void lec_arp_destroy(struct lec_priv *priv) for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) { lec_arp_remove(priv, entry); - kfree(entry); + lec_arp_put(entry); } INIT_HLIST_HEAD(&priv->lec_arp_tables[i]); } @@ -1735,7 +1748,7 @@ static void lec_arp_destroy(struct lec_priv *priv) del_timer_sync(&entry->timer); lec_arp_clear_vccs(entry); hlist_del(&entry->next); - kfree(entry); + lec_arp_put(entry); } INIT_HLIST_HEAD(&priv->lec_arp_empty_ones); @@ -1743,7 +1756,7 @@ static void lec_arp_destroy(struct lec_priv *priv) del_timer_sync(&entry->timer); lec_arp_clear_vccs(entry); hlist_del(&entry->next); - kfree(entry); + lec_arp_put(entry); } INIT_HLIST_HEAD(&priv->lec_no_forward); @@ -1751,7 +1764,7 @@ static void lec_arp_destroy(struct lec_priv *priv) /* No timer, LANEv2 7.1.20 and 2.3.5.3 */ lec_arp_clear_vccs(entry); hlist_del(&entry->next); - kfree(entry); + lec_arp_put(entry); } INIT_HLIST_HEAD(&priv->mcast_fwds); priv->mcast_vcc = NULL; @@ -1799,6 +1812,7 @@ static struct lec_arp_table *make_entry(struct lec_priv *priv, to_return->last_used = jiffies; to_return->priv = priv; skb_queue_head_init(&to_return->tx_wait); + atomic_set(&to_return->usage, 1); return to_return; } @@ -1843,7 +1857,7 @@ static void lec_arp_expire_vcc(unsigned long data) spin_unlock_irqrestore(&priv->lec_arp_lock, flags); lec_arp_clear_vccs(to_remove); - kfree(to_remove); + lec_arp_put(to_remove); } /* @@ -1891,7 +1905,7 @@ static void lec_arp_check_expire(void *data) /* Remove entry */ DPRINTK("LEC:Entry timed out\n"); lec_arp_remove(priv, entry); - kfree(entry); + lec_arp_put(entry); } else { /* Something else */ if ((entry->status == ESI_VC_PENDING || @@ -2045,7 +2059,7 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, && (permanent || !(entry->flags & LEC_PERMANENT_FLAG))) { lec_arp_remove(priv, entry); - kfree(entry); + lec_arp_put(entry); } spin_unlock_irqrestore(&priv->lec_arp_lock, flags); return 0; @@ -2094,7 +2108,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, tmp->old_push = entry->old_push; tmp->last_used = jiffies; del_timer(&entry->timer); - kfree(entry); + lec_arp_put(entry); entry = tmp; } else { entry->status = ESI_FORWARD_DIRECT; @@ -2414,7 +2428,7 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) { if (vcc == entry->vcc) { lec_arp_remove(priv, entry); - kfree(entry); + lec_arp_put(entry); if (priv->mcast_vcc == vcc) { priv->mcast_vcc = NULL; } @@ -2427,7 +2441,7 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) lec_arp_clear_vccs(entry); del_timer(&entry->timer); hlist_del(&entry->next); - kfree(entry); + lec_arp_put(entry); } } @@ -2436,7 +2450,7 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) lec_arp_clear_vccs(entry); del_timer(&entry->timer); hlist_del(&entry->next); - kfree(entry); + lec_arp_put(entry); } } @@ -2445,7 +2459,7 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) lec_arp_clear_vccs(entry); /* No timer, LANEv2 7.1.20 and 2.3.5.3 */ hlist_del(&entry->next); - kfree(entry); + lec_arp_put(entry); } } @@ -2481,7 +2495,7 @@ lec_arp_check_empties(struct lec_priv *priv, /* We might have got an entry */ if ((tmp = lec_arp_find(priv, src))) { lec_arp_remove(priv, tmp); - kfree(tmp); + lec_arp_put(tmp); } hlist_del(&entry->next); lec_arp_add(priv, entry); diff --git a/net/atm/lec_arpc.h b/net/atm/lec_arpc.h index 125df36d33b8..ec67435a40a6 100644 --- a/net/atm/lec_arpc.h +++ b/net/atm/lec_arpc.h @@ -47,6 +47,7 @@ struct lec_arp_table { * the length of the tlvs array */ struct sk_buff_head tx_wait; /* wait queue for outgoing packets */ + atomic_t usage; /* usage count */ }; /* |