diff options
author | Zach Brown <zach.brown@oracle.com> | 2010-07-15 15:34:33 -0400 |
---|---|---|
committer | Andy Grover <andy.grover@oracle.com> | 2010-09-08 21:16:44 -0400 |
commit | ea819867b788728aca60717e4fdacb3df771f670 (patch) | |
tree | 68952e283e4b119622c6e8244d96e41c623ae4b0 /net/rds/ib_rdma.c | |
parent | 1bde04a63d532c2540d6fdee0a661530a62b1686 (diff) |
RDS/IB: protect the list of IB devices
The RDS IB device list wasn't protected by any locking. Traversal in
both the get_mr and FMR flushing paths could race with additon and
removal.
List manipulation is done with RCU primatives and is protected by the
write side of a rwsem. The list traversal in the get_mr fast path is
protected by a rcu read critical section. The FMR list traversal is
more problematic because it can block while traversing the list. We
protect this with the read side of the rwsem.
Signed-off-by: Zach Brown <zach.brown@oracle.com>
Diffstat (limited to 'net/rds/ib_rdma.c')
-rw-r--r-- | net/rds/ib_rdma.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index 0017964f2fcf..8f6e221c9f78 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c | |||
@@ -94,8 +94,8 @@ static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) | |||
94 | struct rds_ib_device *rds_ibdev; | 94 | struct rds_ib_device *rds_ibdev; |
95 | struct rds_ib_ipaddr *i_ipaddr; | 95 | struct rds_ib_ipaddr *i_ipaddr; |
96 | 96 | ||
97 | list_for_each_entry(rds_ibdev, &rds_ib_devices, list) { | 97 | rcu_read_lock(); |
98 | rcu_read_lock(); | 98 | list_for_each_entry_rcu(rds_ibdev, &rds_ib_devices, list) { |
99 | list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) { | 99 | list_for_each_entry_rcu(i_ipaddr, &rds_ibdev->ipaddr_list, list) { |
100 | if (i_ipaddr->ipaddr == ipaddr) { | 100 | if (i_ipaddr->ipaddr == ipaddr) { |
101 | atomic_inc(&rds_ibdev->refcount); | 101 | atomic_inc(&rds_ibdev->refcount); |
@@ -103,8 +103,8 @@ static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr) | |||
103 | return rds_ibdev; | 103 | return rds_ibdev; |
104 | } | 104 | } |
105 | } | 105 | } |
106 | rcu_read_unlock(); | ||
107 | } | 106 | } |
107 | rcu_read_unlock(); | ||
108 | 108 | ||
109 | return NULL; | 109 | return NULL; |
110 | } | 110 | } |
@@ -761,12 +761,14 @@ void rds_ib_flush_mrs(void) | |||
761 | { | 761 | { |
762 | struct rds_ib_device *rds_ibdev; | 762 | struct rds_ib_device *rds_ibdev; |
763 | 763 | ||
764 | down_read(&rds_ib_devices_lock); | ||
764 | list_for_each_entry(rds_ibdev, &rds_ib_devices, list) { | 765 | list_for_each_entry(rds_ibdev, &rds_ib_devices, list) { |
765 | struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool; | 766 | struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool; |
766 | 767 | ||
767 | if (pool) | 768 | if (pool) |
768 | rds_ib_flush_mr_pool(pool, 0, NULL); | 769 | rds_ib_flush_mr_pool(pool, 0, NULL); |
769 | } | 770 | } |
771 | up_read(&rds_ib_devices_lock); | ||
770 | } | 772 | } |
771 | 773 | ||
772 | void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents, | 774 | void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents, |