rds: rcu-ize rds_ib_get_device()
authorChris Mason <chris.mason@oracle.com>
Fri, 23 Apr 2010 01:59:15 +0000 (21:59 -0400)
committerAndy Grover <andy.grover@oracle.com>
Thu, 9 Sep 2010 01:12:28 +0000 (18:12 -0700)
rds_ib_get_device is called very often as we turn an
ip address into a corresponding device structure.  It currently
take a global spinlock as it walks different lists to find active
devices.

This commit changes the lists over to RCU, which isn't very complex
because they are not updated very often at all.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
net/rds/ib.c
net/rds/ib_rdma.c

index 927c481b52452fed30f992ede510147dce8b33f3..7a2131d37dfbd19614ad116ab4907cb1cdc0aaa3 100644 (file)
@@ -137,6 +137,7 @@ void rds_ib_remove_one(struct ib_device *device)
        if (!rds_ibdev)
                return;
 
+       synchronize_rcu();
        list_for_each_entry_safe(i_ipaddr, i_next, &rds_ibdev->ipaddr_list, list) {
                list_del(&i_ipaddr->list);
                kfree(i_ipaddr);
index 242231f09464166fd3d9590952a2555c3fa654fc..7240e583ee58cb6daafa29e5317580437fbf055e 100644 (file)
@@ -32,6 +32,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/rculist.h>
 
 #include "rds.h"
 #include "ib.h"
@@ -83,14 +84,14 @@ static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
        struct rds_ib_ipaddr *i_ipaddr;
 
        list_for_each_entry(rds_ibdev, &rds_ib_devices, list) {
-               spin_lock_irq(&rds_ibdev->spinlock);
-               list_for_each_entry(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
+               rcu_read_lock();
+               list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
                        if (i_ipaddr->ipaddr == ipaddr) {
-                               spin_unlock_irq(&rds_ibdev->spinlock);
+                               rcu_read_unlock();
                                return rds_ibdev;
                        }
                }
-               spin_unlock_irq(&rds_ibdev->spinlock);
+               rcu_read_unlock();
        }
 
        return NULL;
@@ -107,7 +108,7 @@ static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
        i_ipaddr->ipaddr = ipaddr;
 
        spin_lock_irq(&rds_ibdev->spinlock);
-       list_add_tail(&i_ipaddr->list, &rds_ibdev->ipaddr_list);
+       list_add_tail_rcu(&i_ipaddr->list, &rds_ibdev->ipaddr_list);
        spin_unlock_irq(&rds_ibdev->spinlock);
 
        return 0;
@@ -116,16 +117,23 @@ static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
 static void rds_ib_remove_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
 {
        struct rds_ib_ipaddr *i_ipaddr, *next;
+       struct rds_ib_ipaddr *to_free = NULL;
+
 
        spin_lock_irq(&rds_ibdev->spinlock);
-       list_for_each_entry_safe(i_ipaddr, next, &rds_ibdev->ipaddr_list, list) {
+       list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
                if (i_ipaddr->ipaddr == ipaddr) {
-                       list_del(&i_ipaddr->list);
-                       kfree(i_ipaddr);
+                       list_del_rcu(&i_ipaddr->list);
+                       to_free = i_ipaddr;
                        break;
                }
        }
        spin_unlock_irq(&rds_ibdev->spinlock);
+
+       if (to_free) {
+               synchronize_rcu();
+               kfree(to_free);
+       }
 }
 
 int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)