summaryrefslogtreecommitdiffstats
path: root/net/rds/rds.h
diff options
context:
space:
mode:
authorZach Brown <zach.brown@oracle.com>2010-06-04 14:41:41 -0700
committerAndy Grover <andy.grover@oracle.com>2010-09-08 18:15:27 -0700
commit0f4b1c7e89e699f588807a914ec6e6396c851a72 (patch)
tree8b882f85f03089283f6d222bf8c7d5616a102ecd /net/rds/rds.h
parent501dcccdb7a2335cde07d4acb56e636182d62944 (diff)
downloadlinux-stable-0f4b1c7e89e699f588807a914ec6e6396c851a72.tar.gz
linux-stable-0f4b1c7e89e699f588807a914ec6e6396c851a72.tar.bz2
linux-stable-0f4b1c7e89e699f588807a914ec6e6396c851a72.zip
rds: fix rds_send_xmit() serialization
rds_send_xmit() was changed to hold an interrupt masking spinlock instead of a mutex so that it could be called from the IB receive tasklet path. This broke the TCP transport because its xmit method can block and masks and unmasks interrupts. This patch serializes callers to rds_send_xmit() with a simple bit instead of the current spinlock or previous mutex. This enables rds_send_xmit() to be called from any context and to call functions which block. Getting rid of the c_send_lock exposes the bare c_lock acquisitions which are changed to block interrupts. A waitqueue is added so that rds_conn_shutdown() can wait for callers to leave rds_send_xmit() before tearing down partial send state. This lets us get rid of c_senders. rds_send_xmit() is changed to check the conn state after acquiring the RDS_IN_XMIT bit to resolve races with the shutdown path. Previously both worked with the conn state and then the lock in the same order, allowing them to race and execute the paths concurrently. rds_send_reset() isn't racing with rds_send_xmit() now that rds_conn_shutdown() properly ensures that rds_send_xmit() can't start once the conn state has been changed. We can remove its previous use of the spinlock. Finally, c_send_generation is redundant. Callers can race to test the c_flags bit by simply retrying instead of racing to test the c_send_generation atomic. Signed-off-by: Zach Brown <zach.brown@oracle.com>
Diffstat (limited to 'net/rds/rds.h')
-rw-r--r--net/rds/rds.h5
1 files changed, 2 insertions, 3 deletions
diff --git a/net/rds/rds.h b/net/rds/rds.h
index 270ded76fd53..4510344ce8ca 100644
--- a/net/rds/rds.h
+++ b/net/rds/rds.h
@@ -80,6 +80,7 @@ enum {
/* Bits for c_flags */
#define RDS_LL_SEND_FULL 0
#define RDS_RECONNECT_PENDING 1
+#define RDS_IN_XMIT 2
struct rds_connection {
struct hlist_node c_hash_node;
@@ -91,9 +92,6 @@ struct rds_connection {
struct rds_cong_map *c_lcong;
struct rds_cong_map *c_fcong;
- spinlock_t c_send_lock; /* protect send ring */
- atomic_t c_send_generation;
- atomic_t c_senders;
struct rds_message *c_xmit_rm;
unsigned long c_xmit_sg;
unsigned int c_xmit_hdr_off;
@@ -120,6 +118,7 @@ struct rds_connection {
struct delayed_work c_conn_w;
struct work_struct c_down_w;
struct mutex c_cm_lock; /* protect conn state & cm */
+ wait_queue_head_t c_waitq;
struct list_head c_map_item;
unsigned long c_map_queued;