ip: Router Alert RCU conversion
authorEric Dumazet <eric.dumazet@gmail.com>
Mon, 7 Jun 2010 03:12:08 +0000 (03:12 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 8 Jun 2010 04:25:21 +0000 (21:25 -0700)
Straightforward conversion to RCU.

One rwlock becomes a spinlock, and is static.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip.h
net/ipv4/ip_input.c
net/ipv4/ip_sockglue.c

index 452f229c380aea77f0adc5e018ef2972d7fcd368..9982c97f0bdcaf4c09c13cb5f2dc07e2ab2953eb 100644 (file)
@@ -62,10 +62,10 @@ struct ip_ra_chain {
        struct ip_ra_chain      *next;
        struct sock             *sk;
        void                    (*destructor)(struct sock *);
+       struct rcu_head         rcu;
 };
 
 extern struct ip_ra_chain *ip_ra_chain;
-extern rwlock_t ip_ra_lock;
 
 /* IP flags. */
 #define IP_CE          0x8000          /* Flag: "Congestion"           */
index d52c9da644cfaa0c6bd2b474794d49f051da9c7b..d274078b16650009248d3971077c1b3f8bf28f2b 100644 (file)
 #include <linux/netlink.h>
 
 /*
- *     Process Router Attention IP option
+ *     Process Router Attention IP option (RFC 2113)
  */
 int ip_call_ra_chain(struct sk_buff *skb)
 {
@@ -155,8 +155,7 @@ int ip_call_ra_chain(struct sk_buff *skb)
        struct sock *last = NULL;
        struct net_device *dev = skb->dev;
 
-       read_lock(&ip_ra_lock);
-       for (ra = ip_ra_chain; ra; ra = ra->next) {
+       for (ra = rcu_dereference(ip_ra_chain); ra; ra = rcu_dereference(ra->next)) {
                struct sock *sk = ra->sk;
 
                /* If socket is bound to an interface, only report
@@ -167,10 +166,8 @@ int ip_call_ra_chain(struct sk_buff *skb)
                     sk->sk_bound_dev_if == dev->ifindex) &&
                    net_eq(sock_net(sk), dev_net(dev))) {
                        if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
-                               if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) {
-                                       read_unlock(&ip_ra_lock);
+                               if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN))
                                        return 1;
-                               }
                        }
                        if (last) {
                                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
@@ -183,10 +180,8 @@ int ip_call_ra_chain(struct sk_buff *skb)
 
        if (last) {
                raw_rcv(last, skb);
-               read_unlock(&ip_ra_lock);
                return 1;
        }
-       read_unlock(&ip_ra_lock);
        return 0;
 }
 
index ce231780a2b14ef4e15a33baad4b0c887e96df16..08b9519a24f430a7750d91080f2b8f979f290cbc 100644 (file)
@@ -239,7 +239,12 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
    sent to multicast group to reach destination designated router.
  */
 struct ip_ra_chain *ip_ra_chain;
-DEFINE_RWLOCK(ip_ra_lock);
+static DEFINE_SPINLOCK(ip_ra_lock);
+
+static void ip_ra_free_rcu(struct rcu_head *head)
+{
+       kfree(container_of(head, struct ip_ra_chain, rcu));
+}
 
 int ip_ra_control(struct sock *sk, unsigned char on,
                  void (*destructor)(struct sock *))
@@ -251,35 +256,35 @@ int ip_ra_control(struct sock *sk, unsigned char on,
 
        new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
 
-       write_lock_bh(&ip_ra_lock);
+       spin_lock_bh(&ip_ra_lock);
        for (rap = &ip_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
                if (ra->sk == sk) {
                        if (on) {
-                               write_unlock_bh(&ip_ra_lock);
+                               spin_unlock_bh(&ip_ra_lock);
                                kfree(new_ra);
                                return -EADDRINUSE;
                        }
-                       *rap = ra->next;
-                       write_unlock_bh(&ip_ra_lock);
+                       rcu_assign_pointer(*rap, ra->next);
+                       spin_unlock_bh(&ip_ra_lock);
 
                        if (ra->destructor)
                                ra->destructor(sk);
                        sock_put(sk);
-                       kfree(ra);
+                       call_rcu(&ra->rcu, ip_ra_free_rcu);
                        return 0;
                }
        }
        if (new_ra == NULL) {
-               write_unlock_bh(&ip_ra_lock);
+               spin_unlock_bh(&ip_ra_lock);
                return -ENOBUFS;
        }
        new_ra->sk = sk;
        new_ra->destructor = destructor;
 
        new_ra->next = ra;
-       *rap = new_ra;
+       rcu_assign_pointer(*rap, new_ra);
        sock_hold(sk);
-       write_unlock_bh(&ip_ra_lock);
+       spin_unlock_bh(&ip_ra_lock);
 
        return 0;
 }