loop: fix NULL dereference if mount fails
[safe/jmp/linux-2.6] / net / ipv4 / inet_diag.c
index da97695..a706a47 100644 (file)
@@ -1,8 +1,6 @@
 /*
  * inet_diag.c Module for monitoring INET transport protocols sockets.
  *
- * Version:    $Id: inet_diag.c,v 1.3 2002/02/01 22:01:04 davem Exp $
- *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
  *     This program is free software; you can redistribute it and/or
@@ -55,11 +53,9 @@ static DEFINE_MUTEX(inet_diag_table_mutex);
 
 static const struct inet_diag_handler *inet_diag_lock_handler(int type)
 {
-#ifdef CONFIG_KMOD
        if (!inet_diag_table[type])
                request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
                               NETLINK_INET_DIAG, type);
-#endif
 
        mutex_lock(&inet_diag_table_mutex);
        if (!inet_diag_table[type])
@@ -160,10 +156,10 @@ static int inet_csk_diag_fill(struct sock *sk,
        r->idiag_inode = sock_i_ino(sk);
 
        if (minfo) {
-               minfo->idiag_rmem = atomic_read(&sk->sk_rmem_alloc);
+               minfo->idiag_rmem = sk_rmem_alloc_get(sk);
                minfo->idiag_wmem = sk->sk_wmem_queued;
                minfo->idiag_fmem = sk->sk_forward_alloc;
-               minfo->idiag_tmem = atomic_read(&sk->sk_wmem_alloc);
+               minfo->idiag_tmem = sk_wmem_alloc_get(sk);
        }
 
        handler->idiag_get_info(sk, r, info);
@@ -202,8 +198,6 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
                tmo = 0;
 
        r->idiag_family       = tw->tw_family;
-       r->idiag_state        = tw->tw_state;
-       r->idiag_timer        = 0;
        r->idiag_retrans      = 0;
        r->id.idiag_if        = tw->tw_bound_dev_if;
        r->id.idiag_cookie[0] = (u32)(unsigned long)tw;
@@ -722,13 +716,15 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
                if (!(r->idiag_states & (TCPF_LISTEN | TCPF_SYN_RECV)))
                        goto skip_listen_ht;
 
-               inet_listen_lock(hashinfo);
                for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
                        struct sock *sk;
-                       struct hlist_node *node;
+                       struct hlist_nulls_node *node;
+                       struct inet_listen_hashbucket *ilb;
 
                        num = 0;
-                       sk_for_each(sk, node, &hashinfo->listening_hash[i]) {
+                       ilb = &hashinfo->listening_hash[i];
+                       spin_lock_bh(&ilb->lock);
+                       sk_nulls_for_each(sk, node, &ilb->head) {
                                struct inet_sock *inet = inet_sk(sk);
 
                                if (num < s_num) {
@@ -746,7 +742,7 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
                                        goto syn_recv;
 
                                if (inet_csk_diag_dump(sk, skb, cb) < 0) {
-                                       inet_listen_unlock(hashinfo);
+                                       spin_unlock_bh(&ilb->lock);
                                        goto done;
                                }
 
@@ -755,7 +751,7 @@ syn_recv:
                                        goto next_listen;
 
                                if (inet_diag_dump_reqs(skb, sk, cb) < 0) {
-                                       inet_listen_unlock(hashinfo);
+                                       spin_unlock_bh(&ilb->lock);
                                        goto done;
                                }
 
@@ -764,12 +760,12 @@ next_listen:
                                cb->args[4] = 0;
                                ++num;
                        }
+                       spin_unlock_bh(&ilb->lock);
 
                        s_num = 0;
                        cb->args[3] = 0;
                        cb->args[4] = 0;
                }
-               inet_listen_unlock(hashinfo);
 skip_listen_ht:
                cb->args[0] = 1;
                s_i = num = s_num = 0;
@@ -780,16 +776,21 @@ skip_listen_ht:
 
        for (i = s_i; i < hashinfo->ehash_size; i++) {
                struct inet_ehash_bucket *head = &hashinfo->ehash[i];
-               rwlock_t *lock = inet_ehash_lockp(hashinfo, i);
+               spinlock_t *lock = inet_ehash_lockp(hashinfo, i);
                struct sock *sk;
-               struct hlist_node *node;
+               struct hlist_nulls_node *node;
+
+               num = 0;
+
+               if (hlist_nulls_empty(&head->chain) &&
+                       hlist_nulls_empty(&head->twchain))
+                       continue;
 
                if (i > s_i)
                        s_num = 0;
 
-               read_lock_bh(lock);
-               num = 0;
-               sk_for_each(sk, node, &head->chain) {
+               spin_lock_bh(lock);
+               sk_nulls_for_each(sk, node, &head->chain) {
                        struct inet_sock *inet = inet_sk(sk);
 
                        if (num < s_num)
@@ -803,7 +804,7 @@ skip_listen_ht:
                            r->id.idiag_dport)
                                goto next_normal;
                        if (inet_csk_diag_dump(sk, skb, cb) < 0) {
-                               read_unlock_bh(lock);
+                               spin_unlock_bh(lock);
                                goto done;
                        }
 next_normal:
@@ -825,14 +826,14 @@ next_normal:
                                    r->id.idiag_dport)
                                        goto next_dying;
                                if (inet_twsk_diag_dump(tw, skb, cb) < 0) {
-                                       read_unlock_bh(lock);
+                                       spin_unlock_bh(lock);
                                        goto done;
                                }
 next_dying:
                                ++num;
                        }
                }
-               read_unlock_bh(lock);
+               spin_unlock_bh(lock);
        }
 
 done: