aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2010-04-22 21:59:15 -0400
committerAndy Grover <andy.grover@oracle.com>2010-09-08 18:12:28 -0700
commit764f2dd92f5cd308d1c4372b33fea2b265c093f5 (patch)
treef979329a2b5bfb0c92fc83e951d9ac7654c4ba78
parentrds: per-rm flush_wait waitq (diff)
downloadlinux-dev-764f2dd92f5cd308d1c4372b33fea2b265c093f5.tar.xz
linux-dev-764f2dd92f5cd308d1c4372b33fea2b265c093f5.zip
rds: rcu-ize rds_ib_get_device()
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>
-rw-r--r--net/rds/ib.c1
-rw-r--r--net/rds/ib_rdma.c24
2 files changed, 17 insertions, 8 deletions
diff --git a/net/rds/ib.c b/net/rds/ib.c
index 927c481b5245..7a2131d37dfb 100644
--- a/net/rds/ib.c
+++ b/net/rds/ib.c
@@ -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);
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
index 242231f09464..7240e583ee58 100644
--- a/net/rds/ib_rdma.c
+++ b/net/rds/ib_rdma.c
@@ -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)