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/rds/iw_cm.c | |
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/rds/iw_cm.c')
-rw-r--r-- | net/rds/iw_cm.c | 35 |
1 files changed, 19 insertions, 16 deletions
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 | ||