Skip to content

Commit 02a7fe2

Browse files
jgunthorpejfvogel
authored andcommitted
RDMA/cm: Allow ib_send_cm_drep() to be done under lock
The first thing ib_send_cm_drep() does is obtain the lock, so use the usual unlocked wrapper, locked actor pattern here. This avoids a sketchy lock/unlock sequence (which could allow state to change) during cm_destroy_id(). Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Leon Romanovsky <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]> Orabug: 31483278 (cherry picked from commit 87cabf3) cherry-pick-repo=linux/kernel/git/torvalds/linux.git Conflicts: drivers/infiniband/core/cm.c Conflicts due to context issues. Signed-off-by: Ka-Cheong Poon <[email protected]> Tested-by: June Wang <[email protected]> Reviewed-by: Sharath Srinivasan <[email protected]>
1 parent c4f6b6e commit 02a7fe2

File tree

1 file changed

+33
-22
lines changed
  • drivers/infiniband/core

1 file changed

+33
-22
lines changed

drivers/infiniband/core/cm.c

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ static void cm_add_one(struct ib_device *device);
111111
static void cm_remove_one(struct ib_device *device, void *client_data);
112112
static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv,
113113
const void *private_data, u8 private_data_len);
114+
static int cm_send_drep_locked(struct cm_id_private *cm_id_priv,
115+
void *private_data, u8 private_data_len);
114116

115117
static struct ib_client cm_client = {
116118
.name = "cm",
@@ -1097,8 +1099,8 @@ static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
10971099
spin_unlock_irq(&cm_id_priv->lock);
10981100
break;
10991101
case IB_CM_DREQ_RCVD:
1102+
cm_send_drep_locked(cm_id_priv, NULL, 0);
11001103
spin_unlock_irq(&cm_id_priv->lock);
1101-
ib_send_cm_drep(cm_id, NULL, 0);
11021104
break;
11031105
default:
11041106
spin_unlock_irq(&cm_id_priv->lock);
@@ -2567,51 +2569,60 @@ static void cm_format_drep(struct cm_drep_msg *drep_msg,
25672569
memcpy(drep_msg->private_data, private_data, private_data_len);
25682570
}
25692571

2570-
int ib_send_cm_drep(struct ib_cm_id *cm_id,
2571-
const void *private_data,
2572-
u8 private_data_len)
2572+
static int cm_send_drep_locked(struct cm_id_private *cm_id_priv,
2573+
void *private_data, u8 private_data_len)
25732574
{
2574-
struct cm_id_private *cm_id_priv;
25752575
struct ib_mad_send_buf *msg;
2576-
unsigned long flags;
2577-
void *data;
25782576
int ret;
25792577

2578+
lockdep_assert_held(&cm_id_priv->lock);
2579+
25802580
if (private_data && private_data_len > IB_CM_DREP_PRIVATE_DATA_SIZE)
25812581
return -EINVAL;
25822582

2583-
data = cm_copy_private_data(private_data, private_data_len);
2584-
if (IS_ERR(data))
2585-
return PTR_ERR(data);
2586-
2587-
cm_id_priv = container_of(cm_id, struct cm_id_private, id);
2588-
spin_lock_irqsave(&cm_id_priv->lock, flags);
2589-
if (cm_id->state != IB_CM_DREQ_RCVD) {
2590-
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2591-
kfree(data);
2592-
pr_debug("%s: local_id %d, cm_idcm_id->state(%d) != IB_CM_DREQ_RCVD\n",
2593-
__func__, be32_to_cpu(cm_id->local_id), cm_id->state);
2583+
if (cm_id_priv->id.state != IB_CM_DREQ_RCVD) {
2584+
pr_debug(
2585+
"%s: local_id %d, cm_idcm_id->state(%d) != IB_CM_DREQ_RCVD\n",
2586+
__func__, be32_to_cpu(cm_id_priv->id.local_id),
2587+
cm_id_priv->id.state);
2588+
kfree(private_data);
25942589
return -EINVAL;
25952590
}
25962591

2597-
cm_set_private_data(cm_id_priv, data, private_data_len);
2592+
cm_set_private_data(cm_id_priv, private_data, private_data_len);
25982593
cm_enter_timewait(cm_id_priv);
25992594

26002595
ret = cm_alloc_msg(cm_id_priv, &msg);
26012596
if (ret)
2602-
goto out;
2597+
return ret;
26032598

26042599
cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv,
26052600
private_data, private_data_len);
26062601

26072602
ret = ib_post_send_mad(msg, NULL);
26082603
if (ret) {
2609-
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
26102604
cm_free_msg(msg);
26112605
return ret;
26122606
}
2607+
return 0;
2608+
}
26132609

2614-
out: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2610+
int ib_send_cm_drep(struct ib_cm_id *cm_id, const void *private_data,
2611+
u8 private_data_len)
2612+
{
2613+
struct cm_id_private *cm_id_priv =
2614+
container_of(cm_id, struct cm_id_private, id);
2615+
unsigned long flags;
2616+
void *data;
2617+
int ret;
2618+
2619+
data = cm_copy_private_data(private_data, private_data_len);
2620+
if (IS_ERR(data))
2621+
return PTR_ERR(data);
2622+
2623+
spin_lock_irqsave(&cm_id_priv->lock, flags);
2624+
ret = cm_send_drep_locked(cm_id_priv, data, private_data_len);
2625+
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
26152626
return ret;
26162627
}
26172628
EXPORT_SYMBOL(ib_send_cm_drep);

0 commit comments

Comments
 (0)