Skip to content

Commit 1412bb2

Browse files
committed
Merge branch 'net-smc-fixes'
Karsten Graul says: ==================== net/smc: fixes 2020-07-08 Please apply the following patch series for smc to netdev's net tree. The patches fix problems found during more testing of SMC functionality, resulting in hang conditions and unneeded link deactivations. The clc module was hardened to be prepared for possible future SMCD versions. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents a42e6ae + fb4f792 commit 1412bb2

File tree

11 files changed

+163
-105
lines changed

11 files changed

+163
-105
lines changed

net/smc/smc_clc.c

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#define SMCR_CLC_ACCEPT_CONFIRM_LEN 68
2929
#define SMCD_CLC_ACCEPT_CONFIRM_LEN 48
30+
#define SMC_CLC_RECV_BUF_LEN 100
3031

3132
/* eye catcher "SMCR" EBCDIC for CLC messages */
3233
static const char SMC_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xd9'};
@@ -36,7 +37,7 @@ static const char SMCD_EYECATCHER[4] = {'\xe2', '\xd4', '\xc3', '\xc4'};
3637
/* check if received message has a correct header length and contains valid
3738
* heading and trailing eyecatchers
3839
*/
39-
static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm)
40+
static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm, bool check_trl)
4041
{
4142
struct smc_clc_msg_proposal_prefix *pclc_prfx;
4243
struct smc_clc_msg_accept_confirm *clc;
@@ -49,12 +50,9 @@ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm)
4950
return false;
5051
switch (clcm->type) {
5152
case SMC_CLC_PROPOSAL:
52-
if (clcm->path != SMC_TYPE_R && clcm->path != SMC_TYPE_D &&
53-
clcm->path != SMC_TYPE_B)
54-
return false;
5553
pclc = (struct smc_clc_msg_proposal *)clcm;
5654
pclc_prfx = smc_clc_proposal_get_prefix(pclc);
57-
if (ntohs(pclc->hdr.length) !=
55+
if (ntohs(pclc->hdr.length) <
5856
sizeof(*pclc) + ntohs(pclc->iparea_offset) +
5957
sizeof(*pclc_prfx) +
6058
pclc_prfx->ipv6_prefixes_cnt *
@@ -86,7 +84,8 @@ static bool smc_clc_msg_hdr_valid(struct smc_clc_msg_hdr *clcm)
8684
default:
8785
return false;
8886
}
89-
if (memcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
87+
if (check_trl &&
88+
memcmp(trl->eyecatcher, SMC_EYECATCHER, sizeof(SMC_EYECATCHER)) &&
9089
memcmp(trl->eyecatcher, SMCD_EYECATCHER, sizeof(SMCD_EYECATCHER)))
9190
return false;
9291
return true;
@@ -276,7 +275,8 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
276275
struct msghdr msg = {NULL, 0};
277276
int reason_code = 0;
278277
struct kvec vec = {buf, buflen};
279-
int len, datlen;
278+
int len, datlen, recvlen;
279+
bool check_trl = true;
280280
int krflags;
281281

282282
/* peek the first few bytes to determine length of data to receive
@@ -320,27 +320,46 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
320320
}
321321
datlen = ntohs(clcm->length);
322322
if ((len < sizeof(struct smc_clc_msg_hdr)) ||
323-
(datlen > buflen) ||
324-
(clcm->version != SMC_CLC_V1) ||
325-
(clcm->path != SMC_TYPE_R && clcm->path != SMC_TYPE_D &&
326-
clcm->path != SMC_TYPE_B) ||
323+
(clcm->version < SMC_CLC_V1) ||
327324
((clcm->type != SMC_CLC_DECLINE) &&
328325
(clcm->type != expected_type))) {
329326
smc->sk.sk_err = EPROTO;
330327
reason_code = -EPROTO;
331328
goto out;
332329
}
333330

331+
if (clcm->type == SMC_CLC_PROPOSAL && clcm->path == SMC_TYPE_N)
332+
reason_code = SMC_CLC_DECL_VERSMISMAT; /* just V2 offered */
333+
334334
/* receive the complete CLC message */
335335
memset(&msg, 0, sizeof(struct msghdr));
336-
iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, datlen);
336+
if (datlen > buflen) {
337+
check_trl = false;
338+
recvlen = buflen;
339+
} else {
340+
recvlen = datlen;
341+
}
342+
iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
337343
krflags = MSG_WAITALL;
338344
len = sock_recvmsg(smc->clcsock, &msg, krflags);
339-
if (len < datlen || !smc_clc_msg_hdr_valid(clcm)) {
345+
if (len < recvlen || !smc_clc_msg_hdr_valid(clcm, check_trl)) {
340346
smc->sk.sk_err = EPROTO;
341347
reason_code = -EPROTO;
342348
goto out;
343349
}
350+
datlen -= len;
351+
while (datlen) {
352+
u8 tmp[SMC_CLC_RECV_BUF_LEN];
353+
354+
vec.iov_base = &tmp;
355+
vec.iov_len = SMC_CLC_RECV_BUF_LEN;
356+
/* receive remaining proposal message */
357+
recvlen = datlen > SMC_CLC_RECV_BUF_LEN ?
358+
SMC_CLC_RECV_BUF_LEN : datlen;
359+
iov_iter_kvec(&msg.msg_iter, READ, &vec, 1, recvlen);
360+
len = sock_recvmsg(smc->clcsock, &msg, krflags);
361+
datlen -= len;
362+
}
344363
if (clcm->type == SMC_CLC_DECLINE) {
345364
struct smc_clc_msg_decline *dclc;
346365

net/smc/smc_clc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#define SMC_CLC_V1 0x1 /* SMC version */
2626
#define SMC_TYPE_R 0 /* SMC-R only */
2727
#define SMC_TYPE_D 1 /* SMC-D only */
28+
#define SMC_TYPE_N 2 /* neither SMC-R nor SMC-D */
2829
#define SMC_TYPE_B 3 /* SMC-R and SMC-D */
2930
#define CLC_WAIT_TIME (6 * HZ) /* max. wait time on clcsock */
3031
#define CLC_WAIT_TIME_SHORT HZ /* short wait time on clcsock */
@@ -46,6 +47,7 @@
4647
#define SMC_CLC_DECL_ISMVLANERR 0x03090000 /* err to reg vlan id on ism dev */
4748
#define SMC_CLC_DECL_NOACTLINK 0x030a0000 /* no active smc-r link in lgr */
4849
#define SMC_CLC_DECL_NOSRVLINK 0x030b0000 /* SMC-R link from srv not found */
50+
#define SMC_CLC_DECL_VERSMISMAT 0x030c0000 /* SMC version mismatch */
4951
#define SMC_CLC_DECL_SYNCERR 0x04000000 /* synchronization error */
5052
#define SMC_CLC_DECL_PEERDECL 0x05000000 /* peer declined during handshake */
5153
#define SMC_CLC_DECL_INTERR 0x09990000 /* internal error */

net/smc/smc_core.c

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/workqueue.h>
1616
#include <linux/wait.h>
1717
#include <linux/reboot.h>
18+
#include <linux/mutex.h>
1819
#include <net/tcp.h>
1920
#include <net/sock.h>
2021
#include <rdma/ib_verbs.h>
@@ -247,7 +248,8 @@ static void smcr_lgr_link_deactivate_all(struct smc_link_group *lgr)
247248
if (smc_link_usable(lnk))
248249
lnk->state = SMC_LNK_INACTIVE;
249250
}
250-
wake_up_interruptible_all(&lgr->llc_waiter);
251+
wake_up_all(&lgr->llc_msg_waiter);
252+
wake_up_all(&lgr->llc_flow_waiter);
251253
}
252254

253255
static void smc_lgr_free(struct smc_link_group *lgr);
@@ -1130,18 +1132,19 @@ static void smcr_link_up(struct smc_link_group *lgr,
11301132
return;
11311133
if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
11321134
/* some other llc task is ongoing */
1133-
wait_event_interruptible_timeout(lgr->llc_waiter,
1134-
(lgr->llc_flow_lcl.type == SMC_LLC_FLOW_NONE),
1135+
wait_event_timeout(lgr->llc_flow_waiter,
1136+
(list_empty(&lgr->list) ||
1137+
lgr->llc_flow_lcl.type == SMC_LLC_FLOW_NONE),
11351138
SMC_LLC_WAIT_TIME);
11361139
}
1137-
if (list_empty(&lgr->list) ||
1138-
!smc_ib_port_active(smcibdev, ibport))
1139-
return; /* lgr or device no longer active */
1140-
link = smc_llc_usable_link(lgr);
1141-
if (!link)
1142-
return;
1143-
smc_llc_send_add_link(link, smcibdev->mac[ibport - 1], gid,
1144-
NULL, SMC_LLC_REQ);
1140+
/* lgr or device no longer active? */
1141+
if (!list_empty(&lgr->list) &&
1142+
smc_ib_port_active(smcibdev, ibport))
1143+
link = smc_llc_usable_link(lgr);
1144+
if (link)
1145+
smc_llc_send_add_link(link, smcibdev->mac[ibport - 1],
1146+
gid, NULL, SMC_LLC_REQ);
1147+
wake_up(&lgr->llc_flow_waiter); /* wake up next waiter */
11451148
}
11461149
}
11471150

@@ -1195,13 +1198,17 @@ static void smcr_link_down(struct smc_link *lnk)
11951198
if (lgr->llc_flow_lcl.type != SMC_LLC_FLOW_NONE) {
11961199
/* another llc task is ongoing */
11971200
mutex_unlock(&lgr->llc_conf_mutex);
1198-
wait_event_interruptible_timeout(lgr->llc_waiter,
1199-
(lgr->llc_flow_lcl.type == SMC_LLC_FLOW_NONE),
1201+
wait_event_timeout(lgr->llc_flow_waiter,
1202+
(list_empty(&lgr->list) ||
1203+
lgr->llc_flow_lcl.type == SMC_LLC_FLOW_NONE),
12001204
SMC_LLC_WAIT_TIME);
12011205
mutex_lock(&lgr->llc_conf_mutex);
12021206
}
1203-
smc_llc_send_delete_link(to_lnk, del_link_id, SMC_LLC_REQ, true,
1204-
SMC_LLC_DEL_LOST_PATH);
1207+
if (!list_empty(&lgr->list))
1208+
smc_llc_send_delete_link(to_lnk, del_link_id,
1209+
SMC_LLC_REQ, true,
1210+
SMC_LLC_DEL_LOST_PATH);
1211+
wake_up(&lgr->llc_flow_waiter); /* wake up next waiter */
12051212
}
12061213
}
12071214

@@ -1262,7 +1269,7 @@ static void smc_link_down_work(struct work_struct *work)
12621269

12631270
if (list_empty(&lgr->list))
12641271
return;
1265-
wake_up_interruptible_all(&lgr->llc_waiter);
1272+
wake_up_all(&lgr->llc_msg_waiter);
12661273
mutex_lock(&lgr->llc_conf_mutex);
12671274
smcr_link_down(link);
12681275
mutex_unlock(&lgr->llc_conf_mutex);
@@ -1955,20 +1962,20 @@ static void smc_core_going_away(void)
19551962
struct smc_ib_device *smcibdev;
19561963
struct smcd_dev *smcd;
19571964

1958-
spin_lock(&smc_ib_devices.lock);
1965+
mutex_lock(&smc_ib_devices.mutex);
19591966
list_for_each_entry(smcibdev, &smc_ib_devices.list, list) {
19601967
int i;
19611968

19621969
for (i = 0; i < SMC_MAX_PORTS; i++)
19631970
set_bit(i, smcibdev->ports_going_away);
19641971
}
1965-
spin_unlock(&smc_ib_devices.lock);
1972+
mutex_unlock(&smc_ib_devices.mutex);
19661973

1967-
spin_lock(&smcd_dev_list.lock);
1974+
mutex_lock(&smcd_dev_list.mutex);
19681975
list_for_each_entry(smcd, &smcd_dev_list.list, list) {
19691976
smcd->going_away = 1;
19701977
}
1971-
spin_unlock(&smcd_dev_list.lock);
1978+
mutex_unlock(&smcd_dev_list.mutex);
19721979
}
19731980

19741981
/* Clean up all SMC link groups */
@@ -1980,10 +1987,10 @@ static void smc_lgrs_shutdown(void)
19801987

19811988
smc_smcr_terminate_all(NULL);
19821989

1983-
spin_lock(&smcd_dev_list.lock);
1990+
mutex_lock(&smcd_dev_list.mutex);
19841991
list_for_each_entry(smcd, &smcd_dev_list.list, list)
19851992
smc_smcd_terminate_all(smcd);
1986-
spin_unlock(&smcd_dev_list.lock);
1993+
mutex_unlock(&smcd_dev_list.mutex);
19871994
}
19881995

19891996
static int smc_core_reboot_event(struct notifier_block *this,

net/smc/smc_core.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,10 @@ struct smc_link_group {
262262
struct work_struct llc_del_link_work;
263263
struct work_struct llc_event_work;
264264
/* llc event worker */
265-
wait_queue_head_t llc_waiter;
265+
wait_queue_head_t llc_flow_waiter;
266266
/* w4 next llc event */
267+
wait_queue_head_t llc_msg_waiter;
268+
/* w4 next llc msg */
267269
struct smc_llc_flow llc_flow_lcl;
268270
/* llc local control field */
269271
struct smc_llc_flow llc_flow_rmt;

net/smc/smc_ib.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/workqueue.h>
1717
#include <linux/scatterlist.h>
1818
#include <linux/wait.h>
19+
#include <linux/mutex.h>
1920
#include <rdma/ib_verbs.h>
2021
#include <rdma/ib_cache.h>
2122

@@ -33,7 +34,7 @@
3334
#define SMC_QP_RNR_RETRY 7 /* 7: infinite */
3435

3536
struct smc_ib_devices smc_ib_devices = { /* smc-registered ib devices */
36-
.lock = __SPIN_LOCK_UNLOCKED(smc_ib_devices.lock),
37+
.mutex = __MUTEX_INITIALIZER(smc_ib_devices.mutex),
3738
.list = LIST_HEAD_INIT(smc_ib_devices.list),
3839
};
3940

@@ -565,9 +566,9 @@ static int smc_ib_add_dev(struct ib_device *ibdev)
565566
INIT_WORK(&smcibdev->port_event_work, smc_ib_port_event_work);
566567
atomic_set(&smcibdev->lnk_cnt, 0);
567568
init_waitqueue_head(&smcibdev->lnks_deleted);
568-
spin_lock(&smc_ib_devices.lock);
569+
mutex_lock(&smc_ib_devices.mutex);
569570
list_add_tail(&smcibdev->list, &smc_ib_devices.list);
570-
spin_unlock(&smc_ib_devices.lock);
571+
mutex_unlock(&smc_ib_devices.mutex);
571572
ib_set_client_data(ibdev, &smc_ib_client, smcibdev);
572573
INIT_IB_EVENT_HANDLER(&smcibdev->event_handler, smcibdev->ibdev,
573574
smc_ib_global_event_handler);
@@ -602,9 +603,9 @@ static void smc_ib_remove_dev(struct ib_device *ibdev, void *client_data)
602603
{
603604
struct smc_ib_device *smcibdev = client_data;
604605

605-
spin_lock(&smc_ib_devices.lock);
606+
mutex_lock(&smc_ib_devices.mutex);
606607
list_del_init(&smcibdev->list); /* remove from smc_ib_devices */
607-
spin_unlock(&smc_ib_devices.lock);
608+
mutex_unlock(&smc_ib_devices.mutex);
608609
pr_warn_ratelimited("smc: removing ib device %s\n",
609610
smcibdev->ibdev->name);
610611
smc_smcr_terminate_all(smcibdev);

net/smc/smc_ib.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <linux/interrupt.h>
1616
#include <linux/if_ether.h>
17+
#include <linux/mutex.h>
1718
#include <linux/wait.h>
1819
#include <rdma/ib_verbs.h>
1920
#include <net/smc.h>
@@ -25,7 +26,7 @@
2526

2627
struct smc_ib_devices { /* list of smc ib devices definition */
2728
struct list_head list;
28-
spinlock_t lock; /* protects list of smc ib devices */
29+
struct mutex mutex; /* protects list of smc ib devices */
2930
};
3031

3132
extern struct smc_ib_devices smc_ib_devices; /* list of smc ib devices */

net/smc/smc_ism.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include <linux/spinlock.h>
10+
#include <linux/mutex.h>
1011
#include <linux/slab.h>
1112
#include <asm/page.h>
1213

@@ -17,7 +18,7 @@
1718

1819
struct smcd_dev_list smcd_dev_list = {
1920
.list = LIST_HEAD_INIT(smcd_dev_list.list),
20-
.lock = __SPIN_LOCK_UNLOCKED(smcd_dev_list.lock)
21+
.mutex = __MUTEX_INITIALIZER(smcd_dev_list.mutex)
2122
};
2223

2324
/* Test if an ISM communication is possible. */
@@ -317,9 +318,9 @@ EXPORT_SYMBOL_GPL(smcd_alloc_dev);
317318

318319
int smcd_register_dev(struct smcd_dev *smcd)
319320
{
320-
spin_lock(&smcd_dev_list.lock);
321+
mutex_lock(&smcd_dev_list.mutex);
321322
list_add_tail(&smcd->list, &smcd_dev_list.list);
322-
spin_unlock(&smcd_dev_list.lock);
323+
mutex_unlock(&smcd_dev_list.mutex);
323324

324325
pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n",
325326
dev_name(&smcd->dev), smcd->pnetid,
@@ -333,9 +334,9 @@ void smcd_unregister_dev(struct smcd_dev *smcd)
333334
{
334335
pr_warn_ratelimited("smc: removing smcd device %s\n",
335336
dev_name(&smcd->dev));
336-
spin_lock(&smcd_dev_list.lock);
337+
mutex_lock(&smcd_dev_list.mutex);
337338
list_del_init(&smcd->list);
338-
spin_unlock(&smcd_dev_list.lock);
339+
mutex_unlock(&smcd_dev_list.mutex);
339340
smcd->going_away = 1;
340341
smc_smcd_terminate_all(smcd);
341342
flush_workqueue(smcd->event_wq);

net/smc/smc_ism.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010
#define SMCD_ISM_H
1111

1212
#include <linux/uio.h>
13+
#include <linux/mutex.h>
1314

1415
#include "smc.h"
1516

1617
struct smcd_dev_list { /* List of SMCD devices */
1718
struct list_head list;
18-
spinlock_t lock; /* Protects list of devices */
19+
struct mutex mutex; /* Protects list of devices */
1920
};
2021

2122
extern struct smcd_dev_list smcd_dev_list; /* list of smcd devices */

0 commit comments

Comments
 (0)