Skip to content

Commit 87cabf3

Browse files
committed
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]>
1 parent e029fdc commit 87cabf3

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
@@ -85,6 +85,8 @@ static void cm_add_one(struct ib_device *device);
8585
static void cm_remove_one(struct ib_device *device, void *client_data);
8686
static int cm_send_dreq_locked(struct cm_id_private *cm_id_priv,
8787
const void *private_data, u8 private_data_len);
88+
static int cm_send_drep_locked(struct cm_id_private *cm_id_priv,
89+
void *private_data, u8 private_data_len);
8890

8991
static struct ib_client cm_client = {
9092
.name = "cm",
@@ -1100,8 +1102,8 @@ static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
11001102
spin_unlock_irq(&cm_id_priv->lock);
11011103
break;
11021104
case IB_CM_DREQ_RCVD:
1105+
cm_send_drep_locked(cm_id_priv, NULL, 0);
11031106
spin_unlock_irq(&cm_id_priv->lock);
1104-
ib_send_cm_drep(cm_id, NULL, 0);
11051107
break;
11061108
default:
11071109
spin_unlock_irq(&cm_id_priv->lock);
@@ -2685,51 +2687,60 @@ static void cm_format_drep(struct cm_drep_msg *drep_msg,
26852687
private_data_len);
26862688
}
26872689

2688-
int ib_send_cm_drep(struct ib_cm_id *cm_id,
2689-
const void *private_data,
2690-
u8 private_data_len)
2690+
static int cm_send_drep_locked(struct cm_id_private *cm_id_priv,
2691+
void *private_data, u8 private_data_len)
26912692
{
2692-
struct cm_id_private *cm_id_priv;
26932693
struct ib_mad_send_buf *msg;
2694-
unsigned long flags;
2695-
void *data;
26962694
int ret;
26972695

2696+
lockdep_assert_held(&cm_id_priv->lock);
2697+
26982698
if (private_data && private_data_len > IB_CM_DREP_PRIVATE_DATA_SIZE)
26992699
return -EINVAL;
27002700

2701-
data = cm_copy_private_data(private_data, private_data_len);
2702-
if (IS_ERR(data))
2703-
return PTR_ERR(data);
2704-
2705-
cm_id_priv = container_of(cm_id, struct cm_id_private, id);
2706-
spin_lock_irqsave(&cm_id_priv->lock, flags);
2707-
if (cm_id->state != IB_CM_DREQ_RCVD) {
2708-
pr_debug("%s: local_id %d, cm_idcm_id->state(%d) != IB_CM_DREQ_RCVD\n",
2709-
__func__, be32_to_cpu(cm_id->local_id), cm_id->state);
2710-
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2711-
kfree(data);
2701+
if (cm_id_priv->id.state != IB_CM_DREQ_RCVD) {
2702+
pr_debug(
2703+
"%s: local_id %d, cm_idcm_id->state(%d) != IB_CM_DREQ_RCVD\n",
2704+
__func__, be32_to_cpu(cm_id_priv->id.local_id),
2705+
cm_id_priv->id.state);
2706+
kfree(private_data);
27122707
return -EINVAL;
27132708
}
27142709

2715-
cm_set_private_data(cm_id_priv, data, private_data_len);
2710+
cm_set_private_data(cm_id_priv, private_data, private_data_len);
27162711
cm_enter_timewait(cm_id_priv);
27172712

27182713
ret = cm_alloc_msg(cm_id_priv, &msg);
27192714
if (ret)
2720-
goto out;
2715+
return ret;
27212716

27222717
cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv,
27232718
private_data, private_data_len);
27242719

27252720
ret = ib_post_send_mad(msg, NULL);
27262721
if (ret) {
2727-
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
27282722
cm_free_msg(msg);
27292723
return ret;
27302724
}
2725+
return 0;
2726+
}
27312727

2732-
out: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
2728+
int ib_send_cm_drep(struct ib_cm_id *cm_id, const void *private_data,
2729+
u8 private_data_len)
2730+
{
2731+
struct cm_id_private *cm_id_priv =
2732+
container_of(cm_id, struct cm_id_private, id);
2733+
unsigned long flags;
2734+
void *data;
2735+
int ret;
2736+
2737+
data = cm_copy_private_data(private_data, private_data_len);
2738+
if (IS_ERR(data))
2739+
return PTR_ERR(data);
2740+
2741+
spin_lock_irqsave(&cm_id_priv->lock, flags);
2742+
ret = cm_send_drep_locked(cm_id_priv, data, private_data_len);
2743+
spin_unlock_irqrestore(&cm_id_priv->lock, flags);
27332744
return ret;
27342745
}
27352746
EXPORT_SYMBOL(ib_send_cm_drep);

0 commit comments

Comments
 (0)