aboutsummaryrefslogtreecommitdiffstats
path: root/net/rds/iw_cm.c
diff options
context:
space:
mode:
authorAndy Grover <andy.grover@oracle.com>2009-04-01 04:20:19 -0400
committerDavid S. Miller <davem@davemloft.net>2009-04-02 03:52:22 -0400
commit745cbccac3fe8cead529a1b3358e1e86a1505bfa (patch)
tree6c865b19881dbdd64556cc1827f6966d8a646a38 /net/rds/iw_cm.c
parentf1cffcbfcc53b825da7d1d26244aabd8dccb24aa (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.c35
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 */
729void rds_iw_conn_free(void *arg) 719void 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