aboutsummaryrefslogtreecommitdiffstats
path: root/net/rds/ib_rdma.c
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 21:12:28 -0400
commit764f2dd92f5cd308d1c4372b33fea2b265c093f5 (patch)
treef979329a2b5bfb0c92fc83e951d9ac7654c4ba78 /net/rds/ib_rdma.c
parentc83188dcd76b1f0c17c31b4bbd8de57c634b19f8 (diff)
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>
Diffstat (limited to 'net/rds/ib_rdma.c')
-rw-r--r--net/rds/ib_rdma.c24
1 files changed, 16 insertions, 8 deletions
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 @@
32 */ 32 */
33#include <linux/kernel.h> 33#include <linux/kernel.h>
34#include <linux/slab.h> 34#include <linux/slab.h>
35#include <linux/rculist.h>
35 36
36#include "rds.h" 37#include "rds.h"
37#include "ib.h" 38#include "ib.h"
@@ -83,14 +84,14 @@ static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
83 struct rds_ib_ipaddr *i_ipaddr; 84 struct rds_ib_ipaddr *i_ipaddr;
84 85
85 list_for_each_entry(rds_ibdev, &rds_ib_devices, list) { 86 list_for_each_entry(rds_ibdev, &rds_ib_devices, list) {
86 spin_lock_irq(&rds_ibdev->spinlock); 87 rcu_read_lock();
87 list_for_each_entry(i_ipaddr, &rds_ibdev->ipaddr_list, list) { 88 list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
88 if (i_ipaddr->ipaddr == ipaddr) { 89 if (i_ipaddr->ipaddr == ipaddr) {
89 spin_unlock_irq(&rds_ibdev->spinlock); 90 rcu_read_unlock();
90 return rds_ibdev; 91 return rds_ibdev;
91 } 92 }
92 } 93 }
93 spin_unlock_irq(&rds_ibdev->spinlock); 94 rcu_read_unlock();
94 } 95 }
95 96
96 return NULL; 97 return NULL;
@@ -107,7 +108,7 @@ static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
107 i_ipaddr->ipaddr = ipaddr; 108 i_ipaddr->ipaddr = ipaddr;
108 109
109 spin_lock_irq(&rds_ibdev->spinlock); 110 spin_lock_irq(&rds_ibdev->spinlock);
110 list_add_tail(&i_ipaddr->list, &rds_ibdev->ipaddr_list); 111 list_add_tail_rcu(&i_ipaddr->list, &rds_ibdev->ipaddr_list);
111 spin_unlock_irq(&rds_ibdev->spinlock); 112 spin_unlock_irq(&rds_ibdev->spinlock);
112 113
113 return 0; 114 return 0;
@@ -116,16 +117,23 @@ static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
116static void rds_ib_remove_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr) 117static void rds_ib_remove_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
117{ 118{
118 struct rds_ib_ipaddr *i_ipaddr, *next; 119 struct rds_ib_ipaddr *i_ipaddr, *next;
120 struct rds_ib_ipaddr *to_free = NULL;
121
119 122
120 spin_lock_irq(&rds_ibdev->spinlock); 123 spin_lock_irq(&rds_ibdev->spinlock);
121 list_for_each_entry_safe(i_ipaddr, next, &rds_ibdev->ipaddr_list, list) { 124 list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
122 if (i_ipaddr->ipaddr == ipaddr) { 125 if (i_ipaddr->ipaddr == ipaddr) {
123 list_del(&i_ipaddr->list); 126 list_del_rcu(&i_ipaddr->list);
124 kfree(i_ipaddr); 127 to_free = i_ipaddr;
125 break; 128 break;
126 } 129 }
127 } 130 }
128 spin_unlock_irq(&rds_ibdev->spinlock); 131 spin_unlock_irq(&rds_ibdev->spinlock);
132
133 if (to_free) {
134 synchronize_rcu();
135 kfree(to_free);
136 }
129} 137}
130 138
131int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr) 139int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)