diff options
author | Andy Grover <andy.grover@oracle.com> | 2009-04-01 04:20:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-04-02 03:52:22 -0400 |
commit | 745cbccac3fe8cead529a1b3358e1e86a1505bfa (patch) | |
tree | 6c865b19881dbdd64556cc1827f6966d8a646a38 /net | |
parent | f1cffcbfcc53b825da7d1d26244aabd8dccb24aa (diff) |
RDS: Rewrite connection cleanup, fixing oops on rmmod
This fixes a bug where a connection was unexpectedly
not on *any* list while being destroyed. It also
cleans up some code duplication and regularizes some
function names.
* Grab appropriate lock in conn_free() and explain in comment
* Ensure via locking that a conn is never not on either
a dev's list or the nodev list
* Add rds_xx_remove_conn() to match rds_xx_add_conn()
* Make rds_xx_add_conn() return void
* Rename remove_{,nodev_}conns() to
destroy_{,nodev_}conns() and unify their implementation
in a helper function
* Document lock ordering as nodev conn_lock before
dev_conn_lock
Reported-by: Yosef Etigin <yosefe@voltaire.com>
Signed-off-by: Andy Grover <andy.grover@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/rds/ib.c | 5 | ||||
-rw-r--r-- | net/rds/ib.h | 14 | ||||
-rw-r--r-- | net/rds/ib_cm.c | 34 | ||||
-rw-r--r-- | net/rds/ib_rdma.c | 43 | ||||
-rw-r--r-- | net/rds/iw.c | 5 | ||||
-rw-r--r-- | net/rds/iw.h | 14 | ||||
-rw-r--r-- | net/rds/iw_cm.c | 35 | ||||
-rw-r--r-- | net/rds/iw_rdma.c | 44 |
8 files changed, 109 insertions, 85 deletions
diff --git a/net/rds/ib.c b/net/rds/ib.c index 06a7b798d9a7..4933b380985e 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c | |||
@@ -51,6 +51,7 @@ MODULE_PARM_DESC(fmr_message_size, " Max size of a RDMA transfer"); | |||
51 | 51 | ||
52 | struct list_head rds_ib_devices; | 52 | struct list_head rds_ib_devices; |
53 | 53 | ||
54 | /* NOTE: if also grabbing ibdev lock, grab this first */ | ||
54 | DEFINE_SPINLOCK(ib_nodev_conns_lock); | 55 | DEFINE_SPINLOCK(ib_nodev_conns_lock); |
55 | LIST_HEAD(ib_nodev_conns); | 56 | LIST_HEAD(ib_nodev_conns); |
56 | 57 | ||
@@ -137,7 +138,7 @@ void rds_ib_remove_one(struct ib_device *device) | |||
137 | kfree(i_ipaddr); | 138 | kfree(i_ipaddr); |
138 | } | 139 | } |
139 | 140 | ||
140 | rds_ib_remove_conns(rds_ibdev); | 141 | rds_ib_destroy_conns(rds_ibdev); |
141 | 142 | ||
142 | if (rds_ibdev->mr_pool) | 143 | if (rds_ibdev->mr_pool) |
143 | rds_ib_destroy_mr_pool(rds_ibdev->mr_pool); | 144 | rds_ib_destroy_mr_pool(rds_ibdev->mr_pool); |
@@ -249,7 +250,7 @@ static int rds_ib_laddr_check(__be32 addr) | |||
249 | void rds_ib_exit(void) | 250 | void rds_ib_exit(void) |
250 | { | 251 | { |
251 | rds_info_deregister_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info); | 252 | rds_info_deregister_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info); |
252 | rds_ib_remove_nodev_conns(); | 253 | rds_ib_destroy_nodev_conns(); |
253 | ib_unregister_client(&rds_ib_client); | 254 | ib_unregister_client(&rds_ib_client); |
254 | rds_ib_sysctl_exit(); | 255 | rds_ib_sysctl_exit(); |
255 | rds_ib_recv_exit(); | 256 | rds_ib_recv_exit(); |
diff --git a/net/rds/ib.h b/net/rds/ib.h index 8be563a1363a..c08ffffb3164 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h | |||
@@ -267,9 +267,17 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, | |||
267 | 267 | ||
268 | /* ib_rdma.c */ | 268 | /* ib_rdma.c */ |
269 | int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr); | 269 | int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr); |
270 | int rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); | 270 | void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); |
271 | void rds_ib_remove_nodev_conns(void); | 271 | void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn); |
272 | void rds_ib_remove_conns(struct rds_ib_device *rds_ibdev); | 272 | void __rds_ib_destroy_conns(struct list_head *list, spinlock_t *list_lock); |
273 | static inline void rds_ib_destroy_nodev_conns(void) | ||
274 | { | ||
275 | __rds_ib_destroy_conns(&ib_nodev_conns, &ib_nodev_conns_lock); | ||
276 | } | ||
277 | static inline void rds_ib_destroy_conns(struct rds_ib_device *rds_ibdev) | ||
278 | { | ||
279 | __rds_ib_destroy_conns(&rds_ibdev->conn_list, &rds_ibdev->spinlock); | ||
280 | } | ||
273 | struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *); | 281 | struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *); |
274 | void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo); | 282 | void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo); |
275 | void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *); | 283 | void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *); |
diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 0532237bd128..889ab0441359 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c | |||
@@ -126,9 +126,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even | |||
126 | err = rds_ib_update_ipaddr(rds_ibdev, conn->c_laddr); | 126 | err = rds_ib_update_ipaddr(rds_ibdev, conn->c_laddr); |
127 | if (err) | 127 | if (err) |
128 | printk(KERN_ERR "rds_ib_update_ipaddr failed (%d)\n", err); | 128 | printk(KERN_ERR "rds_ib_update_ipaddr failed (%d)\n", err); |
129 | err = rds_ib_add_conn(rds_ibdev, conn); | 129 | rds_ib_add_conn(rds_ibdev, conn); |
130 | if (err) | ||
131 | printk(KERN_ERR "rds_ib_add_conn failed (%d)\n", err); | ||
132 | 130 | ||
133 | /* If the peer gave us the last packet it saw, process this as if | 131 | /* If the peer gave us the last packet it saw, process this as if |
134 | * we had received a regular ACK. */ | 132 | * we had received a regular ACK. */ |
@@ -616,18 +614,8 @@ void rds_ib_conn_shutdown(struct rds_connection *conn) | |||
616 | /* | 614 | /* |
617 | * Move connection back to the nodev list. | 615 | * Move connection back to the nodev list. |
618 | */ | 616 | */ |
619 | if (ic->rds_ibdev) { | 617 | if (ic->rds_ibdev) |
620 | 618 | rds_ib_remove_conn(ic->rds_ibdev, conn); | |
621 | spin_lock_irq(&ic->rds_ibdev->spinlock); | ||
622 | BUG_ON(list_empty(&ic->ib_node)); | ||
623 | list_del(&ic->ib_node); | ||
624 | spin_unlock_irq(&ic->rds_ibdev->spinlock); | ||
625 | |||
626 | spin_lock_irq(&ib_nodev_conns_lock); | ||
627 | list_add_tail(&ic->ib_node, &ib_nodev_conns); | ||
628 | spin_unlock_irq(&ib_nodev_conns_lock); | ||
629 | ic->rds_ibdev = NULL; | ||
630 | } | ||
631 | 619 | ||
632 | ic->i_cm_id = NULL; | 620 | ic->i_cm_id = NULL; |
633 | ic->i_pd = NULL; | 621 | ic->i_pd = NULL; |
@@ -701,11 +689,27 @@ int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp) | |||
701 | return 0; | 689 | return 0; |
702 | } | 690 | } |
703 | 691 | ||
692 | /* | ||
693 | * Free a connection. Connection must be shut down and not set for reconnect. | ||
694 | */ | ||
704 | void rds_ib_conn_free(void *arg) | 695 | void rds_ib_conn_free(void *arg) |
705 | { | 696 | { |
706 | struct rds_ib_connection *ic = arg; | 697 | struct rds_ib_connection *ic = arg; |
698 | spinlock_t *lock_ptr; | ||
699 | |||
707 | rdsdebug("ic %p\n", ic); | 700 | rdsdebug("ic %p\n", ic); |
701 | |||
702 | /* | ||
703 | * Conn is either on a dev's list or on the nodev list. | ||
704 | * A race with shutdown() or connect() would cause problems | ||
705 | * (since rds_ibdev would change) but that should never happen. | ||
706 | */ | ||
707 | lock_ptr = ic->rds_ibdev ? &ic->rds_ibdev->spinlock : &ib_nodev_conns_lock; | ||
708 | |||
709 | spin_lock_irq(lock_ptr); | ||
708 | list_del(&ic->ib_node); | 710 | list_del(&ic->ib_node); |
711 | spin_unlock_irq(lock_ptr); | ||
712 | |||
709 | kfree(ic); | 713 | kfree(ic); |
710 | } | 714 | } |
711 | 715 | ||
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index 69a6289ed672..81033af93020 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c | |||
@@ -139,7 +139,7 @@ int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr) | |||
139 | return rds_ib_add_ipaddr(rds_ibdev, ipaddr); | 139 | return rds_ib_add_ipaddr(rds_ibdev, ipaddr); |
140 | } | 140 | } |
141 | 141 | ||
142 | int rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn) | 142 | void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn) |
143 | { | 143 | { |
144 | struct rds_ib_connection *ic = conn->c_transport_data; | 144 | struct rds_ib_connection *ic = conn->c_transport_data; |
145 | 145 | ||
@@ -148,45 +148,44 @@ int rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn | |||
148 | BUG_ON(list_empty(&ib_nodev_conns)); | 148 | BUG_ON(list_empty(&ib_nodev_conns)); |
149 | BUG_ON(list_empty(&ic->ib_node)); | 149 | BUG_ON(list_empty(&ic->ib_node)); |
150 | list_del(&ic->ib_node); | 150 | list_del(&ic->ib_node); |
151 | spin_unlock_irq(&ib_nodev_conns_lock); | ||
152 | 151 | ||
153 | spin_lock_irq(&rds_ibdev->spinlock); | 152 | spin_lock_irq(&rds_ibdev->spinlock); |
154 | list_add_tail(&ic->ib_node, &rds_ibdev->conn_list); | 153 | list_add_tail(&ic->ib_node, &rds_ibdev->conn_list); |
155 | spin_unlock_irq(&rds_ibdev->spinlock); | 154 | spin_unlock_irq(&rds_ibdev->spinlock); |
155 | spin_unlock_irq(&ib_nodev_conns_lock); | ||
156 | 156 | ||
157 | ic->rds_ibdev = rds_ibdev; | 157 | ic->rds_ibdev = rds_ibdev; |
158 | |||
159 | return 0; | ||
160 | } | 158 | } |
161 | 159 | ||
162 | void rds_ib_remove_nodev_conns(void) | 160 | void rds_ib_remove_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn) |
163 | { | 161 | { |
164 | struct rds_ib_connection *ic, *_ic; | 162 | struct rds_ib_connection *ic = conn->c_transport_data; |
165 | LIST_HEAD(tmp_list); | ||
166 | 163 | ||
167 | /* avoid calling conn_destroy with irqs off */ | 164 | /* place conn on nodev_conns_list */ |
168 | spin_lock_irq(&ib_nodev_conns_lock); | 165 | spin_lock(&ib_nodev_conns_lock); |
169 | list_splice(&ib_nodev_conns, &tmp_list); | ||
170 | INIT_LIST_HEAD(&ib_nodev_conns); | ||
171 | spin_unlock_irq(&ib_nodev_conns_lock); | ||
172 | 166 | ||
173 | list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node) { | 167 | spin_lock_irq(&rds_ibdev->spinlock); |
174 | if (ic->conn->c_passive) | 168 | BUG_ON(list_empty(&ic->ib_node)); |
175 | rds_conn_destroy(ic->conn->c_passive); | 169 | list_del(&ic->ib_node); |
176 | rds_conn_destroy(ic->conn); | 170 | spin_unlock_irq(&rds_ibdev->spinlock); |
177 | } | 171 | |
172 | list_add_tail(&ic->ib_node, &ib_nodev_conns); | ||
173 | |||
174 | spin_unlock(&ib_nodev_conns_lock); | ||
175 | |||
176 | ic->rds_ibdev = NULL; | ||
178 | } | 177 | } |
179 | 178 | ||
180 | void rds_ib_remove_conns(struct rds_ib_device *rds_ibdev) | 179 | void __rds_ib_destroy_conns(struct list_head *list, spinlock_t *list_lock) |
181 | { | 180 | { |
182 | struct rds_ib_connection *ic, *_ic; | 181 | struct rds_ib_connection *ic, *_ic; |
183 | LIST_HEAD(tmp_list); | 182 | LIST_HEAD(tmp_list); |
184 | 183 | ||
185 | /* avoid calling conn_destroy with irqs off */ | 184 | /* avoid calling conn_destroy with irqs off */ |
186 | spin_lock_irq(&rds_ibdev->spinlock); | 185 | spin_lock_irq(list_lock); |
187 | list_splice(&rds_ibdev->conn_list, &tmp_list); | 186 | list_splice(list, &tmp_list); |
188 | INIT_LIST_HEAD(&rds_ibdev->conn_list); | 187 | INIT_LIST_HEAD(list); |
189 | spin_unlock_irq(&rds_ibdev->spinlock); | 188 | spin_unlock_irq(list_lock); |
190 | 189 | ||
191 | list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node) { | 190 | list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node) { |
192 | if (ic->conn->c_passive) | 191 | if (ic->conn->c_passive) |
diff --git a/net/rds/iw.c b/net/rds/iw.c index 1b56905c4c08..b732efb5b634 100644 --- a/net/rds/iw.c +++ b/net/rds/iw.c | |||
@@ -51,6 +51,7 @@ MODULE_PARM_DESC(fastreg_message_size, " Max size of a RDMA transfer (fastreg MR | |||
51 | 51 | ||
52 | struct list_head rds_iw_devices; | 52 | struct list_head rds_iw_devices; |
53 | 53 | ||
54 | /* NOTE: if also grabbing iwdev lock, grab this first */ | ||
54 | DEFINE_SPINLOCK(iw_nodev_conns_lock); | 55 | DEFINE_SPINLOCK(iw_nodev_conns_lock); |
55 | LIST_HEAD(iw_nodev_conns); | 56 | LIST_HEAD(iw_nodev_conns); |
56 | 57 | ||
@@ -145,7 +146,7 @@ void rds_iw_remove_one(struct ib_device *device) | |||
145 | } | 146 | } |
146 | spin_unlock_irq(&rds_iwdev->spinlock); | 147 | spin_unlock_irq(&rds_iwdev->spinlock); |
147 | 148 | ||
148 | rds_iw_remove_conns(rds_iwdev); | 149 | rds_iw_destroy_conns(rds_iwdev); |
149 | 150 | ||
150 | if (rds_iwdev->mr_pool) | 151 | if (rds_iwdev->mr_pool) |
151 | rds_iw_destroy_mr_pool(rds_iwdev->mr_pool); | 152 | rds_iw_destroy_mr_pool(rds_iwdev->mr_pool); |
@@ -258,7 +259,7 @@ static int rds_iw_laddr_check(__be32 addr) | |||
258 | void rds_iw_exit(void) | 259 | void rds_iw_exit(void) |
259 | { | 260 | { |
260 | rds_info_deregister_func(RDS_INFO_IWARP_CONNECTIONS, rds_iw_ic_info); | 261 | rds_info_deregister_func(RDS_INFO_IWARP_CONNECTIONS, rds_iw_ic_info); |
261 | rds_iw_remove_nodev_conns(); | 262 | rds_iw_destroy_nodev_conns(); |
262 | ib_unregister_client(&rds_iw_client); | 263 | ib_unregister_client(&rds_iw_client); |
263 | rds_iw_sysctl_exit(); | 264 | rds_iw_sysctl_exit(); |
264 | rds_iw_recv_exit(); | 265 | rds_iw_recv_exit(); |
diff --git a/net/rds/iw.h b/net/rds/iw.h index 0ddda34f2a1c..70eb948f42f4 100644 --- a/net/rds/iw.h +++ b/net/rds/iw.h | |||
@@ -294,9 +294,17 @@ void rds_iw_cm_connect_complete(struct rds_connection *conn, | |||
294 | 294 | ||
295 | /* ib_rdma.c */ | 295 | /* ib_rdma.c */ |
296 | int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id); | 296 | int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id); |
297 | int rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn); | 297 | void rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn); |
298 | void rds_iw_remove_nodev_conns(void); | 298 | void rds_iw_remove_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn); |
299 | void rds_iw_remove_conns(struct rds_iw_device *rds_iwdev); | 299 | void __rds_iw_destroy_conns(struct list_head *list, spinlock_t *list_lock); |
300 | static inline void rds_iw_destroy_nodev_conns(void) | ||
301 | { | ||
302 | __rds_iw_destroy_conns(&iw_nodev_conns, &iw_nodev_conns_lock); | ||
303 | } | ||
304 | static inline void rds_iw_destroy_conns(struct rds_iw_device *rds_iwdev) | ||
305 | { | ||
306 | __rds_iw_destroy_conns(&rds_iwdev->conn_list, &rds_iwdev->spinlock); | ||
307 | } | ||
300 | struct rds_iw_mr_pool *rds_iw_create_mr_pool(struct rds_iw_device *); | 308 | struct rds_iw_mr_pool *rds_iw_create_mr_pool(struct rds_iw_device *); |
301 | void rds_iw_get_mr_info(struct rds_iw_device *rds_iwdev, struct rds_info_rdma_connection *iinfo); | 309 | void rds_iw_get_mr_info(struct rds_iw_device *rds_iwdev, struct rds_info_rdma_connection *iinfo); |
302 | void rds_iw_destroy_mr_pool(struct rds_iw_mr_pool *); | 310 | void rds_iw_destroy_mr_pool(struct rds_iw_mr_pool *); |
diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c index 57ecb3d4b8a5..0ffaa3e97ad6 100644 --- a/net/rds/iw_cm.c +++ b/net/rds/iw_cm.c | |||
@@ -86,9 +86,7 @@ void rds_iw_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even | |||
86 | err = rds_iw_update_cm_id(rds_iwdev, ic->i_cm_id); | 86 | err = rds_iw_update_cm_id(rds_iwdev, ic->i_cm_id); |
87 | if (err) | 87 | if (err) |
88 | printk(KERN_ERR "rds_iw_update_ipaddr failed (%d)\n", err); | 88 | printk(KERN_ERR "rds_iw_update_ipaddr failed (%d)\n", err); |
89 | err = rds_iw_add_conn(rds_iwdev, conn); | 89 | rds_iw_add_conn(rds_iwdev, conn); |
90 | if (err) | ||
91 | printk(KERN_ERR "rds_iw_add_conn failed (%d)\n", err); | ||
92 | 90 | ||
93 | /* If the peer gave us the last packet it saw, process this as if | 91 | /* If the peer gave us the last packet it saw, process this as if |
94 | * we had received a regular ACK. */ | 92 | * we had received a regular ACK. */ |
@@ -637,19 +635,8 @@ void rds_iw_conn_shutdown(struct rds_connection *conn) | |||
637 | * Move connection back to the nodev list. | 635 | * Move connection back to the nodev list. |
638 | * Remove cm_id from the device cm_id list. | 636 | * Remove cm_id from the device cm_id list. |
639 | */ | 637 | */ |
640 | if (ic->rds_iwdev) { | 638 | if (ic->rds_iwdev) |
641 | 639 | rds_iw_remove_conn(ic->rds_iwdev, conn); | |
642 | spin_lock_irq(&ic->rds_iwdev->spinlock); | ||
643 | BUG_ON(list_empty(&ic->iw_node)); | ||
644 | list_del(&ic->iw_node); | ||
645 | spin_unlock_irq(&ic->rds_iwdev->spinlock); | ||
646 | |||
647 | spin_lock_irq(&iw_nodev_conns_lock); | ||
648 | list_add_tail(&ic->iw_node, &iw_nodev_conns); | ||
649 | spin_unlock_irq(&iw_nodev_conns_lock); | ||
650 | rds_iw_remove_cm_id(ic->rds_iwdev, ic->i_cm_id); | ||
651 | ic->rds_iwdev = NULL; | ||
652 | } | ||
653 | 640 | ||
654 | rdma_destroy_id(ic->i_cm_id); | 641 | rdma_destroy_id(ic->i_cm_id); |
655 | 642 | ||
@@ -726,11 +713,27 @@ int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp) | |||
726 | return 0; | 713 | return 0; |
727 | } | 714 | } |
728 | 715 | ||
716 | /* | ||
717 | * Free a connection. Connection must be shut down and not set for reconnect. | ||
718 | */ | ||
729 | void rds_iw_conn_free(void *arg) | 719 | void rds_iw_conn_free(void *arg) |
730 | { | 720 | { |
731 | struct rds_iw_connection *ic = arg; | 721 | struct rds_iw_connection *ic = arg; |
722 | spinlock_t *lock_ptr; | ||
723 | |||
732 | rdsdebug("ic %p\n", ic); | 724 | rdsdebug("ic %p\n", ic); |
725 | |||
726 | /* | ||
727 | * Conn is either on a dev's list or on the nodev list. | ||
728 | * A race with shutdown() or connect() would cause problems | ||
729 | * (since rds_iwdev would change) but that should never happen. | ||
730 | */ | ||
731 | lock_ptr = ic->rds_iwdev ? &ic->rds_iwdev->spinlock : &iw_nodev_conns_lock; | ||
732 | |||
733 | spin_lock_irq(lock_ptr); | ||
733 | list_del(&ic->iw_node); | 734 | list_del(&ic->iw_node); |
735 | spin_unlock_irq(lock_ptr); | ||
736 | |||
734 | kfree(ic); | 737 | kfree(ic); |
735 | } | 738 | } |
736 | 739 | ||
diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c index 1c02a8f952d0..dcdb37da80f2 100644 --- a/net/rds/iw_rdma.c +++ b/net/rds/iw_rdma.c | |||
@@ -196,7 +196,7 @@ int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_i | |||
196 | return rds_iw_add_cm_id(rds_iwdev, cm_id); | 196 | return rds_iw_add_cm_id(rds_iwdev, cm_id); |
197 | } | 197 | } |
198 | 198 | ||
199 | int rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn) | 199 | void rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn) |
200 | { | 200 | { |
201 | struct rds_iw_connection *ic = conn->c_transport_data; | 201 | struct rds_iw_connection *ic = conn->c_transport_data; |
202 | 202 | ||
@@ -205,45 +205,45 @@ int rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn | |||
205 | BUG_ON(list_empty(&iw_nodev_conns)); | 205 | BUG_ON(list_empty(&iw_nodev_conns)); |
206 | BUG_ON(list_empty(&ic->iw_node)); | 206 | BUG_ON(list_empty(&ic->iw_node)); |
207 | list_del(&ic->iw_node); | 207 | list_del(&ic->iw_node); |
208 | spin_unlock_irq(&iw_nodev_conns_lock); | ||
209 | 208 | ||
210 | spin_lock_irq(&rds_iwdev->spinlock); | 209 | spin_lock_irq(&rds_iwdev->spinlock); |
211 | list_add_tail(&ic->iw_node, &rds_iwdev->conn_list); | 210 | list_add_tail(&ic->iw_node, &rds_iwdev->conn_list); |
212 | spin_unlock_irq(&rds_iwdev->spinlock); | 211 | spin_unlock_irq(&rds_iwdev->spinlock); |
212 | spin_unlock_irq(&iw_nodev_conns_lock); | ||
213 | 213 | ||
214 | ic->rds_iwdev = rds_iwdev; | 214 | ic->rds_iwdev = rds_iwdev; |
215 | |||
216 | return 0; | ||
217 | } | 215 | } |
218 | 216 | ||
219 | void rds_iw_remove_nodev_conns(void) | 217 | void rds_iw_remove_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn) |
220 | { | 218 | { |
221 | struct rds_iw_connection *ic, *_ic; | 219 | struct rds_iw_connection *ic = conn->c_transport_data; |
222 | LIST_HEAD(tmp_list); | ||
223 | 220 | ||
224 | /* avoid calling conn_destroy with irqs off */ | 221 | /* place conn on nodev_conns_list */ |
225 | spin_lock_irq(&iw_nodev_conns_lock); | 222 | spin_lock(&iw_nodev_conns_lock); |
226 | list_splice(&iw_nodev_conns, &tmp_list); | ||
227 | INIT_LIST_HEAD(&iw_nodev_conns); | ||
228 | spin_unlock_irq(&iw_nodev_conns_lock); | ||
229 | 223 | ||
230 | list_for_each_entry_safe(ic, _ic, &tmp_list, iw_node) { | 224 | spin_lock_irq(&rds_iwdev->spinlock); |
231 | if (ic->conn->c_passive) | 225 | BUG_ON(list_empty(&ic->iw_node)); |
232 | rds_conn_destroy(ic->conn->c_passive); | 226 | list_del(&ic->iw_node); |
233 | rds_conn_destroy(ic->conn); | 227 | spin_unlock_irq(&rds_iwdev->spinlock); |
234 | } | 228 | |
229 | list_add_tail(&ic->iw_node, &iw_nodev_conns); | ||
230 | |||
231 | spin_unlock(&iw_nodev_conns_lock); | ||
232 | |||
233 | rds_iw_remove_cm_id(ic->rds_iwdev, ic->i_cm_id); | ||
234 | ic->rds_iwdev = NULL; | ||
235 | } | 235 | } |
236 | 236 | ||
237 | void rds_iw_remove_conns(struct rds_iw_device *rds_iwdev) | 237 | void __rds_iw_destroy_conns(struct list_head *list, spinlock_t *list_lock) |
238 | { | 238 | { |
239 | struct rds_iw_connection *ic, *_ic; | 239 | struct rds_iw_connection *ic, *_ic; |
240 | LIST_HEAD(tmp_list); | 240 | LIST_HEAD(tmp_list); |
241 | 241 | ||
242 | /* avoid calling conn_destroy with irqs off */ | 242 | /* avoid calling conn_destroy with irqs off */ |
243 | spin_lock_irq(&rds_iwdev->spinlock); | 243 | spin_lock_irq(list_lock); |
244 | list_splice(&rds_iwdev->conn_list, &tmp_list); | 244 | list_splice(list, &tmp_list); |
245 | INIT_LIST_HEAD(&rds_iwdev->conn_list); | 245 | INIT_LIST_HEAD(list); |
246 | spin_unlock_irq(&rds_iwdev->spinlock); | 246 | spin_unlock_irq(list_lock); |
247 | 247 | ||
248 | list_for_each_entry_safe(ic, _ic, &tmp_list, iw_node) { | 248 | list_for_each_entry_safe(ic, _ic, &tmp_list, iw_node) { |
249 | if (ic->conn->c_passive) | 249 | if (ic->conn->c_passive) |