struct ping_table {
        struct hlist_nulls_head hash[PING_HTABLE_SIZE];
-       rwlock_t                lock;
+       spinlock_t              lock;
 };
 
 static struct ping_table ping_table;
        struct sock *sk2 = NULL;
 
        isk = inet_sk(sk);
-       write_lock_bh(&ping_table.lock);
+       spin_lock(&ping_table.lock);
        if (ident == 0) {
                u32 i;
                u16 result = ping_port_rover + 1;
        if (sk_unhashed(sk)) {
                pr_debug("was not hashed\n");
                sock_hold(sk);
-               hlist_nulls_add_head(&sk->sk_nulls_node, hlist);
+               sock_set_flag(sk, SOCK_RCU_FREE);
+               hlist_nulls_add_head_rcu(&sk->sk_nulls_node, hlist);
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
        }
-       write_unlock_bh(&ping_table.lock);
+       spin_unlock(&ping_table.lock);
        return 0;
 
 fail:
-       write_unlock_bh(&ping_table.lock);
+       spin_unlock(&ping_table.lock);
        return 1;
 }
 EXPORT_SYMBOL_GPL(ping_get_port);
        struct inet_sock *isk = inet_sk(sk);
 
        pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
-       write_lock_bh(&ping_table.lock);
+       spin_lock(&ping_table.lock);
        if (sk_hashed(sk)) {
-               hlist_nulls_del(&sk->sk_nulls_node);
-               sk_nulls_node_init(&sk->sk_nulls_node);
+               hlist_nulls_del_init_rcu(&sk->sk_nulls_node);
                sock_put(sk);
                isk->inet_num = 0;
                isk->inet_sport = 0;
                sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
        }
-       write_unlock_bh(&ping_table.lock);
+       spin_unlock(&ping_table.lock);
 }
 EXPORT_SYMBOL_GPL(ping_unhash);
 
+/* Called under rcu_read_lock() */
 static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
 {
        struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident);
                return NULL;
        }
 
-       read_lock_bh(&ping_table.lock);
-
        ping_portaddr_for_each_entry(sk, hnode, hslot) {
                isk = inet_sk(sk);
 
                    sk->sk_bound_dev_if != sdif)
                        continue;
 
-               sock_hold(sk);
                goto exit;
        }
 
        sk = NULL;
 exit:
-       read_unlock_bh(&ping_table.lock);
 
        return sk;
 }
        sk->sk_err = err;
        sk_error_report(sk);
 out:
-       sock_put(sk);
+       return;
 }
 EXPORT_SYMBOL_GPL(ping_err);
 
                        reason = __ping_queue_rcv_skb(sk, skb2);
                else
                        reason = SKB_DROP_REASON_NOMEM;
-               sock_put(sk);
        }
 
        if (reason)
 }
 
 void *ping_seq_start(struct seq_file *seq, loff_t *pos, sa_family_t family)
-       __acquires(ping_table.lock)
+       __acquires(RCU)
 {
        struct ping_iter_state *state = seq->private;
        state->bucket = 0;
        state->family = family;
 
-       read_lock_bh(&ping_table.lock);
+       rcu_read_lock();
 
        return *pos ? ping_get_idx(seq, *pos-1) : SEQ_START_TOKEN;
 }
 EXPORT_SYMBOL_GPL(ping_seq_next);
 
 void ping_seq_stop(struct seq_file *seq, void *v)
-       __releases(ping_table.lock)
+       __releases(RCU)
 {
-       read_unlock_bh(&ping_table.lock);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(ping_seq_stop);
 
 
        for (i = 0; i < PING_HTABLE_SIZE; i++)
                INIT_HLIST_NULLS_HEAD(&ping_table.hash[i], i);
-       rwlock_init(&ping_table.lock);
+       spin_lock_init(&ping_table.lock);
 }