]> err.no Git - linux-2.6/blobdiff - net/netlink/af_netlink.c
[NET]: Transform skb_queue_len() binary tests into skb_queue_empty()
[linux-2.6] / net / netlink / af_netlink.c
index b40c9a976969e287f26c83ccd00485ff0744a9ad..3405fdf41b93ab1950f739673614499b06b0ad3f 100644 (file)
@@ -315,8 +315,8 @@ err:
 static void netlink_remove(struct sock *sk)
 {
        netlink_table_grab();
-       nl_table[sk->sk_protocol].hash.entries--;
-       sk_del_node_init(sk);
+       if (sk_del_node_init(sk))
+               nl_table[sk->sk_protocol].hash.entries--;
        if (nlk_sk(sk)->groups)
                __sk_del_bind_node(sk);
        netlink_table_ungrab();
@@ -429,7 +429,12 @@ retry:
        err = netlink_insert(sk, pid);
        if (err == -EADDRINUSE)
                goto retry;
-       return 0;
+
+       /* If 2 threads race to autobind, that is fine.  */
+       if (err == -EBUSY)
+               err = 0;
+
+       return err;
 }
 
 static inline int netlink_capable(struct socket *sock, unsigned int flag) 
@@ -697,7 +702,6 @@ static __inline__ int netlink_broadcast_deliver(struct sock *sk, struct sk_buff
 
        if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
            !test_bit(0, &nlk->state)) {
-               skb_orphan(skb);
                skb_set_owner_r(skb, sk);
                skb_queue_tail(&sk->sk_receive_queue, skb);
                sk->sk_data_ready(sk, skb->len);
@@ -736,11 +740,15 @@ static inline int do_one_broadcast(struct sock *sk,
 
        sock_hold(sk);
        if (p->skb2 == NULL) {
-               if (atomic_read(&p->skb->users) != 1) {
+               if (skb_shared(p->skb)) {
                        p->skb2 = skb_clone(p->skb, p->allocation);
                } else {
-                       p->skb2 = p->skb;
-                       atomic_inc(&p->skb->users);
+                       p->skb2 = skb_get(p->skb);
+                       /*
+                        * skb ownership may have been set when
+                        * delivered to a previous socket.
+                        */
+                       skb_orphan(p->skb2);
                }
        }
        if (p->skb2 == NULL) {
@@ -786,11 +794,12 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
        sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list)
                do_one_broadcast(sk, &info);
 
+       kfree_skb(skb);
+
        netlink_unlock_table();
 
        if (info.skb2)
                kfree_skb(info.skb2);
-       kfree_skb(skb);
 
        if (info.delivered) {
                if (info.congested && (allocation & __GFP_WAIT))
@@ -849,7 +858,7 @@ static inline void netlink_rcv_wake(struct sock *sk)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
 
-       if (!skb_queue_len(&sk->sk_receive_queue))
+       if (skb_queue_empty(&sk->sk_receive_queue))
                clear_bit(0, &nlk->state);
        if (!test_bit(0, &nlk->state))
                wake_up_interruptible(&nlk->wait);
@@ -1091,8 +1100,7 @@ static int netlink_dump(struct sock *sk)
                return 0;
        }
 
-       nlh = __nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLMSG_DONE, sizeof(int));
-       nlh->nlmsg_flags |= NLM_F_MULTI;
+       nlh = NLMSG_NEW_ANSWER(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI);
        memcpy(NLMSG_DATA(nlh), &len, sizeof(len));
        skb_queue_tail(&sk->sk_receive_queue, skb);
        sk->sk_data_ready(sk, skb->len);
@@ -1103,6 +1111,9 @@ static int netlink_dump(struct sock *sk)
 
        netlink_destroy_callback(cb);
        return 0;
+
+nlmsg_failure:
+       return -ENOBUFS;
 }
 
 int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
@@ -1174,7 +1185,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
        }
 
        rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
-                         NLMSG_ERROR, sizeof(struct nlmsgerr));
+                         NLMSG_ERROR, sizeof(struct nlmsgerr), 0);
        errmsg = NLMSG_DATA(rep);
        errmsg->error = err;
        memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(struct nlmsghdr));