|
@@ -546,15 +546,15 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
|
|
|
struct ipoib_neigh *neigh;
|
|
|
unsigned long flags;
|
|
|
|
|
|
+ spin_lock_irqsave(&priv->lock, flags);
|
|
|
neigh = ipoib_neigh_alloc(daddr, dev);
|
|
|
if (!neigh) {
|
|
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
++dev->stats.tx_dropped;
|
|
|
dev_kfree_skb_any(skb);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- spin_lock_irqsave(&priv->lock, flags);
|
|
|
-
|
|
|
path = __path_find(dev, daddr + 4);
|
|
|
if (!path) {
|
|
|
path = path_rec_create(dev, daddr + 4);
|
|
@@ -863,10 +863,10 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv)
|
|
|
if (test_bit(IPOIB_STOP_NEIGH_GC, &priv->flags))
|
|
|
return;
|
|
|
|
|
|
- write_lock_bh(&ntbl->rwlock);
|
|
|
+ spin_lock_irqsave(&priv->lock, flags);
|
|
|
|
|
|
htbl = rcu_dereference_protected(ntbl->htbl,
|
|
|
- lockdep_is_held(&ntbl->rwlock));
|
|
|
+ lockdep_is_held(&priv->lock));
|
|
|
|
|
|
if (!htbl)
|
|
|
goto out_unlock;
|
|
@@ -883,16 +883,14 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv)
|
|
|
struct ipoib_neigh __rcu **np = &htbl->buckets[i];
|
|
|
|
|
|
while ((neigh = rcu_dereference_protected(*np,
|
|
|
- lockdep_is_held(&ntbl->rwlock))) != NULL) {
|
|
|
+ lockdep_is_held(&priv->lock))) != NULL) {
|
|
|
/* was the neigh idle for two GC periods */
|
|
|
if (time_after(neigh_obsolete, neigh->alive)) {
|
|
|
rcu_assign_pointer(*np,
|
|
|
rcu_dereference_protected(neigh->hnext,
|
|
|
- lockdep_is_held(&ntbl->rwlock)));
|
|
|
+ lockdep_is_held(&priv->lock)));
|
|
|
/* remove from path/mc list */
|
|
|
- spin_lock_irqsave(&priv->lock, flags);
|
|
|
list_del(&neigh->list);
|
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
|
|
|
} else {
|
|
|
np = &neigh->hnext;
|
|
@@ -902,7 +900,7 @@ static void __ipoib_reap_neigh(struct ipoib_dev_priv *priv)
|
|
|
}
|
|
|
|
|
|
out_unlock:
|
|
|
- write_unlock_bh(&ntbl->rwlock);
|
|
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
}
|
|
|
|
|
|
static void ipoib_reap_neigh(struct work_struct *work)
|
|
@@ -947,10 +945,8 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr,
|
|
|
struct ipoib_neigh *neigh;
|
|
|
u32 hash_val;
|
|
|
|
|
|
- write_lock_bh(&ntbl->rwlock);
|
|
|
-
|
|
|
htbl = rcu_dereference_protected(ntbl->htbl,
|
|
|
- lockdep_is_held(&ntbl->rwlock));
|
|
|
+ lockdep_is_held(&priv->lock));
|
|
|
if (!htbl) {
|
|
|
neigh = NULL;
|
|
|
goto out_unlock;
|
|
@@ -961,10 +957,10 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr,
|
|
|
*/
|
|
|
hash_val = ipoib_addr_hash(htbl, daddr);
|
|
|
for (neigh = rcu_dereference_protected(htbl->buckets[hash_val],
|
|
|
- lockdep_is_held(&ntbl->rwlock));
|
|
|
+ lockdep_is_held(&priv->lock));
|
|
|
neigh != NULL;
|
|
|
neigh = rcu_dereference_protected(neigh->hnext,
|
|
|
- lockdep_is_held(&ntbl->rwlock))) {
|
|
|
+ lockdep_is_held(&priv->lock))) {
|
|
|
if (memcmp(daddr, neigh->daddr, INFINIBAND_ALEN) == 0) {
|
|
|
/* found, take one ref on behalf of the caller */
|
|
|
if (!atomic_inc_not_zero(&neigh->refcnt)) {
|
|
@@ -987,12 +983,11 @@ struct ipoib_neigh *ipoib_neigh_alloc(u8 *daddr,
|
|
|
/* put in hash */
|
|
|
rcu_assign_pointer(neigh->hnext,
|
|
|
rcu_dereference_protected(htbl->buckets[hash_val],
|
|
|
- lockdep_is_held(&ntbl->rwlock)));
|
|
|
+ lockdep_is_held(&priv->lock)));
|
|
|
rcu_assign_pointer(htbl->buckets[hash_val], neigh);
|
|
|
atomic_inc(&ntbl->entries);
|
|
|
|
|
|
out_unlock:
|
|
|
- write_unlock_bh(&ntbl->rwlock);
|
|
|
|
|
|
return neigh;
|
|
|
}
|
|
@@ -1040,35 +1035,29 @@ void ipoib_neigh_free(struct ipoib_neigh *neigh)
|
|
|
struct ipoib_neigh *n;
|
|
|
u32 hash_val;
|
|
|
|
|
|
- write_lock_bh(&ntbl->rwlock);
|
|
|
-
|
|
|
htbl = rcu_dereference_protected(ntbl->htbl,
|
|
|
- lockdep_is_held(&ntbl->rwlock));
|
|
|
+ lockdep_is_held(&priv->lock));
|
|
|
if (!htbl)
|
|
|
- goto out_unlock;
|
|
|
+ return;
|
|
|
|
|
|
hash_val = ipoib_addr_hash(htbl, neigh->daddr);
|
|
|
np = &htbl->buckets[hash_val];
|
|
|
for (n = rcu_dereference_protected(*np,
|
|
|
- lockdep_is_held(&ntbl->rwlock));
|
|
|
+ lockdep_is_held(&priv->lock));
|
|
|
n != NULL;
|
|
|
n = rcu_dereference_protected(*np,
|
|
|
- lockdep_is_held(&ntbl->rwlock))) {
|
|
|
+ lockdep_is_held(&priv->lock))) {
|
|
|
if (n == neigh) {
|
|
|
/* found */
|
|
|
rcu_assign_pointer(*np,
|
|
|
rcu_dereference_protected(neigh->hnext,
|
|
|
- lockdep_is_held(&ntbl->rwlock)));
|
|
|
+ lockdep_is_held(&priv->lock)));
|
|
|
call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
|
|
|
- goto out_unlock;
|
|
|
+ return;
|
|
|
} else {
|
|
|
np = &n->hnext;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-out_unlock:
|
|
|
- write_unlock_bh(&ntbl->rwlock);
|
|
|
-
|
|
|
}
|
|
|
|
|
|
static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv)
|
|
@@ -1080,7 +1069,6 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv)
|
|
|
|
|
|
clear_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags);
|
|
|
ntbl->htbl = NULL;
|
|
|
- rwlock_init(&ntbl->rwlock);
|
|
|
htbl = kzalloc(sizeof(*htbl), GFP_KERNEL);
|
|
|
if (!htbl)
|
|
|
return -ENOMEM;
|
|
@@ -1095,6 +1083,7 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv)
|
|
|
htbl->mask = (size - 1);
|
|
|
htbl->buckets = buckets;
|
|
|
ntbl->htbl = htbl;
|
|
|
+ htbl->ntbl = ntbl;
|
|
|
atomic_set(&ntbl->entries, 0);
|
|
|
|
|
|
/* start garbage collection */
|
|
@@ -1111,9 +1100,11 @@ static void neigh_hash_free_rcu(struct rcu_head *head)
|
|
|
struct ipoib_neigh_hash,
|
|
|
rcu);
|
|
|
struct ipoib_neigh __rcu **buckets = htbl->buckets;
|
|
|
+ struct ipoib_neigh_table *ntbl = htbl->ntbl;
|
|
|
|
|
|
kfree(buckets);
|
|
|
kfree(htbl);
|
|
|
+ complete(&ntbl->deleted);
|
|
|
}
|
|
|
|
|
|
void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid)
|
|
@@ -1125,10 +1116,10 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid)
|
|
|
int i;
|
|
|
|
|
|
/* remove all neigh connected to a given path or mcast */
|
|
|
- write_lock_bh(&ntbl->rwlock);
|
|
|
+ spin_lock_irqsave(&priv->lock, flags);
|
|
|
|
|
|
htbl = rcu_dereference_protected(ntbl->htbl,
|
|
|
- lockdep_is_held(&ntbl->rwlock));
|
|
|
+ lockdep_is_held(&priv->lock));
|
|
|
|
|
|
if (!htbl)
|
|
|
goto out_unlock;
|
|
@@ -1138,16 +1129,14 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid)
|
|
|
struct ipoib_neigh __rcu **np = &htbl->buckets[i];
|
|
|
|
|
|
while ((neigh = rcu_dereference_protected(*np,
|
|
|
- lockdep_is_held(&ntbl->rwlock))) != NULL) {
|
|
|
+ lockdep_is_held(&priv->lock))) != NULL) {
|
|
|
/* delete neighs belong to this parent */
|
|
|
if (!memcmp(gid, neigh->daddr + 4, sizeof (union ib_gid))) {
|
|
|
rcu_assign_pointer(*np,
|
|
|
rcu_dereference_protected(neigh->hnext,
|
|
|
- lockdep_is_held(&ntbl->rwlock)));
|
|
|
+ lockdep_is_held(&priv->lock)));
|
|
|
/* remove from parent list */
|
|
|
- spin_lock_irqsave(&priv->lock, flags);
|
|
|
list_del(&neigh->list);
|
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
|
|
|
} else {
|
|
|
np = &neigh->hnext;
|
|
@@ -1156,7 +1145,7 @@ void ipoib_del_neighs_by_gid(struct net_device *dev, u8 *gid)
|
|
|
}
|
|
|
}
|
|
|
out_unlock:
|
|
|
- write_unlock_bh(&ntbl->rwlock);
|
|
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
}
|
|
|
|
|
|
static void ipoib_flush_neighs(struct ipoib_dev_priv *priv)
|
|
@@ -1164,37 +1153,44 @@ static void ipoib_flush_neighs(struct ipoib_dev_priv *priv)
|
|
|
struct ipoib_neigh_table *ntbl = &priv->ntbl;
|
|
|
struct ipoib_neigh_hash *htbl;
|
|
|
unsigned long flags;
|
|
|
- int i;
|
|
|
+ int i, wait_flushed = 0;
|
|
|
|
|
|
- write_lock_bh(&ntbl->rwlock);
|
|
|
+ init_completion(&priv->ntbl.flushed);
|
|
|
+
|
|
|
+ spin_lock_irqsave(&priv->lock, flags);
|
|
|
|
|
|
htbl = rcu_dereference_protected(ntbl->htbl,
|
|
|
- lockdep_is_held(&ntbl->rwlock));
|
|
|
+ lockdep_is_held(&priv->lock));
|
|
|
if (!htbl)
|
|
|
goto out_unlock;
|
|
|
|
|
|
+ wait_flushed = atomic_read(&priv->ntbl.entries);
|
|
|
+ if (!wait_flushed)
|
|
|
+ goto free_htbl;
|
|
|
+
|
|
|
for (i = 0; i < htbl->size; i++) {
|
|
|
struct ipoib_neigh *neigh;
|
|
|
struct ipoib_neigh __rcu **np = &htbl->buckets[i];
|
|
|
|
|
|
while ((neigh = rcu_dereference_protected(*np,
|
|
|
- lockdep_is_held(&ntbl->rwlock))) != NULL) {
|
|
|
+ lockdep_is_held(&priv->lock))) != NULL) {
|
|
|
rcu_assign_pointer(*np,
|
|
|
rcu_dereference_protected(neigh->hnext,
|
|
|
- lockdep_is_held(&ntbl->rwlock)));
|
|
|
+ lockdep_is_held(&priv->lock)));
|
|
|
/* remove from path/mc list */
|
|
|
- spin_lock_irqsave(&priv->lock, flags);
|
|
|
list_del(&neigh->list);
|
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
call_rcu(&neigh->rcu, ipoib_neigh_reclaim);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+free_htbl:
|
|
|
rcu_assign_pointer(ntbl->htbl, NULL);
|
|
|
call_rcu(&htbl->rcu, neigh_hash_free_rcu);
|
|
|
|
|
|
out_unlock:
|
|
|
- write_unlock_bh(&ntbl->rwlock);
|
|
|
+ spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
+ if (wait_flushed)
|
|
|
+ wait_for_completion(&priv->ntbl.flushed);
|
|
|
}
|
|
|
|
|
|
static void ipoib_neigh_hash_uninit(struct net_device *dev)
|
|
@@ -1203,7 +1199,7 @@ static void ipoib_neigh_hash_uninit(struct net_device *dev)
|
|
|
int stopped;
|
|
|
|
|
|
ipoib_dbg(priv, "ipoib_neigh_hash_uninit\n");
|
|
|
- init_completion(&priv->ntbl.flushed);
|
|
|
+ init_completion(&priv->ntbl.deleted);
|
|
|
set_bit(IPOIB_NEIGH_TBL_FLUSH, &priv->flags);
|
|
|
|
|
|
/* Stop GC if called at init fail need to cancel work */
|
|
@@ -1211,10 +1207,9 @@ static void ipoib_neigh_hash_uninit(struct net_device *dev)
|
|
|
if (!stopped)
|
|
|
cancel_delayed_work(&priv->neigh_reap_task);
|
|
|
|
|
|
- if (atomic_read(&priv->ntbl.entries)) {
|
|
|
- ipoib_flush_neighs(priv);
|
|
|
- wait_for_completion(&priv->ntbl.flushed);
|
|
|
- }
|
|
|
+ ipoib_flush_neighs(priv);
|
|
|
+
|
|
|
+ wait_for_completion(&priv->ntbl.deleted);
|
|
|
}
|
|
|
|
|
|
|