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 | |
| 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>
| -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) |
