[openib-general] [PATCH 1/2] sdp_conn_put/sdp_conn_hold race condition
Michael S. Tsirkin
mst at mellanox.co.il
Wed Jul 6 11:02:33 PDT 2005
Protect sdp_conn_put by dev_root_s.sock_lock.
Add sdp_conn_put_light for when we know its not the last reference.
Signed-off-by: Michael S. Tsirkin <mst at mellanox.co.il>
Index: ulp/sdp/sdp_conn.c
===================================================================
--- ulp/sdp/sdp_conn.c (revision 2784)
+++ ulp/sdp/sdp_conn.c (working copy)
@@ -595,12 +595,6 @@ static int sdp_conn_table_insert(struct
int sdp_conn_table_remove(struct sdp_sock *conn)
{
int result = 0;
- unsigned long flags;
-
- /*
- * lock table
- */
- spin_lock_irqsave(&dev_root_s.sock_lock, flags);
/*
* validate entry
*/
@@ -619,10 +613,6 @@ int sdp_conn_table_remove(struct sdp_soc
conn->hashent = SDP_DEV_SK_INVALID;
done:
- /*
- * unlock table
- */
- spin_unlock_irqrestore(&dev_root_s.sock_lock, flags);
return result;
}
@@ -706,13 +696,30 @@ void sdp_iocb_q_cancel_all(struct sdp_so
*/
/*
- * sdp_conn_destruct - final destructor for connection.
+ * sdp_conn_put - reference counting and final destructor for connection.
*/
-void sdp_conn_destruct(struct sdp_sock *conn)
+void sdp_conn_put(struct sdp_sock *conn)
{
+ unsigned long flags;
int dump = 0;
int result;
+
+ spin_lock_irqsave(&dev_root_s.sock_lock, flags);
+
+ if (!atomic_dec_and_test(&conn->refcnt)) {
+ spin_unlock_irqrestore(&dev_root_s.sock_lock, flags);
+ return;
+ }
+
+ result = sdp_conn_table_remove(conn);
+ if (result < 0)
+ sdp_dbg_warn(conn, "Error <%d> removing connection <%u:%u>",
+ result, dev_root_s.sk_entry,
+ dev_root_s.sk_size);
+
+ spin_unlock_irqrestore(&dev_root_s.sock_lock, flags);
+
sdp_dbg_ctrl(conn, "DESTRUCT. <%08x:%04x> <%08x:%04x> <%u:%u>",
conn->src_addr, conn->src_port,
conn->dst_addr, conn->dst_port,
@@ -721,14 +728,6 @@ void sdp_conn_destruct(struct sdp_sock *
* If the socket is bound, return the port
*/
(void)sdp_inet_port_put(conn);
- /*
- * remove connection from table
- */
- result = sdp_conn_table_remove(conn);
- if (result < 0)
- sdp_dbg_warn(conn, "Error <%d> removing connection <%u:%u>",
- result, dev_root_s.sk_entry,
- dev_root_s.sk_size);
sdp_conn_stat_dump(conn);
/*
Index: ulp/sdp/sdp_conn.h
===================================================================
--- ulp/sdp/sdp_conn.h (revision 2784)
+++ ulp/sdp/sdp_conn.h (working copy)
@@ -431,7 +431,6 @@ struct sdp_sock {
extern void sdp_conn_internal_lock(struct sdp_sock *conn, unsigned long *flags);
extern void sdp_conn_internal_unlock(struct sdp_sock *conn);
extern void sdp_conn_relock(struct sdp_sock *conn);
-extern void sdp_conn_destruct(struct sdp_sock *conn);
extern int sdp_conn_cq_drain(struct ib_cq *cq, struct sdp_sock *conn);
#define SDP_CONN_LOCK_IRQ(conn, flags) \
@@ -479,12 +478,17 @@ static inline void sdp_conn_hold(struct
atomic_inc(&conn->refcnt);
}
-static inline void sdp_conn_put(struct sdp_sock *conn)
+/*
+ * safe to call if there's another reference on connection.
+ */
+static inline void sdp_conn_put_light(struct sdp_sock *conn)
{
- if (atomic_dec_and_test(&conn->refcnt))
- sdp_conn_destruct(conn);
+ int noref = atomic_dec_and_test(&conn->refcnt);
+ BUG_ON(noref);
}
+void sdp_conn_put(struct sdp_sock *conn);
+
static inline void *hashent_arg(s32 hashent)
{
return (void *)(unsigned long)hashent;
--
MST
More information about the general
mailing list