static void __neigh_notify(struct neighbour *n, int type, int flags,
                           u32 pid);
 static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid);
-static void pneigh_ifdown_and_unlock(struct neigh_table *tbl,
-                                    struct net_device *dev,
-                                    bool skip_perm);
+static void pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
+                         bool skip_perm);
 
 #ifdef CONFIG_PROC_FS
 static const struct seq_operations neigh_stat_seq_ops;
 {
        write_lock_bh(&tbl->lock);
        neigh_flush_dev(tbl, dev, skip_perm);
-       pneigh_ifdown_and_unlock(tbl, dev, skip_perm);
+       write_unlock_bh(&tbl->lock);
+
+       pneigh_ifdown(tbl, dev, skip_perm);
        pneigh_queue_purge(&tbl->proxy_queue, dev ? dev_net(dev) : NULL,
                           tbl->family);
        if (skb_queue_empty_lockless(&tbl->proxy_queue))
        key_len = tbl->key_len;
        hash_val = pneigh_hash(pkey, key_len);
        n = rcu_dereference_check(tbl->phash_buckets[hash_val],
-                                 lockdep_is_held(&tbl->lock));
+                                 lockdep_is_held(&tbl->phash_lock));
 
        while (n) {
                if (!memcmp(n->key, pkey, key_len) &&
                    (n->dev == dev || !n->dev))
                        return n;
 
-               n = rcu_dereference_check(n->next, lockdep_is_held(&tbl->lock));
+               n = rcu_dereference_check(n->next, lockdep_is_held(&tbl->phash_lock));
        }
 
        return NULL;
        unsigned int key_len;
        u32 hash_val;
 
-       ASSERT_RTNL();
+       mutex_lock(&tbl->phash_lock);
 
-       read_lock_bh(&tbl->lock);
        n = pneigh_lookup(tbl, net, pkey, dev);
-       read_unlock_bh(&tbl->lock);
        if (n)
                goto out;
 
        }
 
        hash_val = pneigh_hash(pkey, key_len);
-       write_lock_bh(&tbl->lock);
        n->next = tbl->phash_buckets[hash_val];
        rcu_assign_pointer(tbl->phash_buckets[hash_val], n);
-       write_unlock_bh(&tbl->lock);
 out:
+       mutex_unlock(&tbl->phash_lock);
        return n;
 }
 
        key_len = tbl->key_len;
        hash_val = pneigh_hash(pkey, key_len);
 
-       write_lock_bh(&tbl->lock);
+       mutex_lock(&tbl->phash_lock);
+
        for (np = &tbl->phash_buckets[hash_val];
             (n = rcu_dereference_protected(*np, 1)) != NULL;
             np = &n->next) {
                if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
                    net_eq(pneigh_net(n), net)) {
                        rcu_assign_pointer(*np, n->next);
-                       write_unlock_bh(&tbl->lock);
+
+                       mutex_unlock(&tbl->phash_lock);
 
                        if (tbl->pdestructor)
                                tbl->pdestructor(n);
                        return 0;
                }
        }
-       write_unlock_bh(&tbl->lock);
+
+       mutex_unlock(&tbl->phash_lock);
        return -ENOENT;
 }
 
-static void pneigh_ifdown_and_unlock(struct neigh_table *tbl,
-                                    struct net_device *dev,
-                                    bool skip_perm)
+static void pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev,
+                         bool skip_perm)
 {
        struct pneigh_entry *n, __rcu **np;
        LIST_HEAD(head);
        u32 h;
 
+       mutex_lock(&tbl->phash_lock);
+
        for (h = 0; h <= PNEIGH_HASHMASK; h++) {
                np = &tbl->phash_buckets[h];
                while ((n = rcu_dereference_protected(*np, 1)) != NULL) {
                }
        }
 
-       write_unlock_bh(&tbl->lock);
+       mutex_unlock(&tbl->phash_lock);
 
        while (!list_empty(&head)) {
                n = list_first_entry(&head, typeof(*n), free_node);
                WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN);
 
        rwlock_init(&tbl->lock);
+       mutex_init(&tbl->phash_lock);
 
        INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work);
        queue_delayed_work(system_power_efficient_wq, &tbl->gc_work,