Bugzilla : 23575
Description: fix o2iblnd v2 regression of credit deadlock with v1 peers (bug 14425).
+Severity : normal
+Bugzilla : 21456
+Description: lctl ping of 1.6.6 server from 1.8 router causes protocol error
+
-------------------------------------------------------------------------------
2010-10-29 Oracle, Inc.
int lnet_router_checker_start(void);
void lnet_router_checker_stop(void);
-void lnet_swap_pinginfo(lnet_ping_info_t *info);
int lnet_router_down_ni(lnet_peer_t *rtr, __u32 net);
+int lnet_parse_pinginfo(lnet_ping_info_t *info, int len, int expected_nids);
int lnet_ping_target_init(void);
void lnet_ping_target_fini(void);
#endif
} lnd_t;
+#define LNET_PROTO_PING_MATCHBITS 0x8000000000000000LL
+#define LNET_PROTO_PING_VERSION 2
+#define LNET_PROTO_PING_VERSION1 1
+
#define LNET_NI_STATUS_UP 0x15aac0de
#define LNET_NI_STATUS_DOWN 0xdeadface
#define LNET_NI_STATUS_INVALID 0x00000000
+
typedef struct {
lnet_nid_t ns_nid;
__u32 ns_status;
__u32 ns_unused;
} WIRE_ATTR lnet_ni_status_t;
+typedef struct {
+ __u32 pi_magic;
+ __u32 pi_version;
+ lnet_pid_t pi_pid;
+ __u32 pi_nnis;
+#define pi_ni pi_body.pb_ni
+#define pi_nid pi_body.pb_nid
+
+ union {
+ lnet_nid_t pb_nid[0]; /* LNET_PROTO_PING_VERSION1 */
+ lnet_ni_status_t pb_ni[0]; /* LNET_PROTO_PING_VERSION */
+ } pi_body;
+} WIRE_ATTR lnet_ping_info_t;
+
+static inline size_t
+lnet_pinginfo_size_v(int n_ids, int version)
+{
+ LASSERT (n_ids >= 0);
+ LASSERT (version == LNET_PROTO_PING_VERSION ||
+ version == LNET_PROTO_PING_VERSION1);
+
+ if (version == LNET_PROTO_PING_VERSION)
+ return offsetof(lnet_ping_info_t, pi_ni[n_ids]);
+
+ return offsetof(lnet_ping_info_t, pi_nid[n_ids]);
+}
+
+#define lnet_pinginfo_size(n) lnet_pinginfo_size_v((n), LNET_PROTO_PING_VERSION)
+
#define LNET_MAX_INTERFACES 16
typedef struct lnet_ni {
char *ni_interfaces[LNET_MAX_INTERFACES]; /* equivalent interfaces to use */
} lnet_ni_t;
-#define LNET_PROTO_PING_MATCHBITS 0x8000000000000000LL
-#define LNET_PROTO_PING_VERSION 2
-#define LNET_PROTO_PING_VERSION1 1
-typedef struct {
- __u32 pi_magic;
- __u32 pi_version;
- lnet_pid_t pi_pid;
- __u32 pi_nnis;
- lnet_ni_status_t pi_ni[0];
-} WIRE_ATTR lnet_ping_info_t;
-
/* router checker data, per router */
-#define LNET_MAX_RTR_NIS 16
-#define LNET_PINGINFO_SIZE offsetof(lnet_ping_info_t, pi_ni[LNET_MAX_RTR_NIS])
+#define LNET_MAX_RTR_NIS 16
+#define LNET_MAX_PINGINFO_SIZE lnet_pinginfo_size(LNET_MAX_RTR_NIS)
+
typedef struct {
struct list_head rcd_list; /* chain on the_lnet.ln_zombie_rcd */
lnet_handle_md_t rcd_mdh; /* ping buffer MD */
LASSERT (rc == 0);
}
- infosz = offsetof(lnet_ping_info_t, pi_ni[n]);
+ infosz = lnet_pinginfo_size(n);
LIBCFS_ALLOC(pinfo, infosz);
if (pinfo == NULL) {
CERROR("Can't allocate ping info[%d]\n", n);
LNET_UNLOCK();
LIBCFS_FREE(the_lnet.ln_ping_info,
- offsetof(lnet_ping_info_t,
- pi_ni[the_lnet.ln_ping_info->pi_nnis]));
+ lnet_pinginfo_size(the_lnet.ln_ping_info->pi_nnis));
the_lnet.ln_ping_info = NULL;
return;
}
lnet_handle_me_t meh;
int rc;
int rc2;
- int infosz;
rc = lnet_create_ping_info();
if (rc != 0)
goto failed_1;
}
- infosz = offsetof(lnet_ping_info_t,
- pi_ni[the_lnet.ln_ping_info->pi_nnis]);
rc = LNetMDAttach(meh,
(lnet_md_t){.start = the_lnet.ln_ping_info,
- .length = infosz,
+ .length = lnet_pinginfo_size(the_lnet.ln_ping_info->pi_nnis),
.threshold = LNET_MD_THRESH_INF,
.options = (LNET_MD_OP_GET |
LNET_MD_TRUNCATE |
int unlinked = 0;
int replied = 0;
const int a_long_time = 60000; /* mS */
- int infosz = offsetof(lnet_ping_info_t, pi_ni[n_ids]);
+ int infosz;
lnet_ping_info_t *info;
lnet_process_id_t tmpid;
int i;
- int nob;
int rc;
int rc2;
cfs_sigset_t blocked;
if (id.pid == LNET_PID_ANY)
id.pid = LUSTRE_SRV_LNET_PID;
+ infosz = lnet_pinginfo_size(n_ids);
LIBCFS_ALLOC(info, infosz);
if (info == NULL)
return -ENOMEM;
if (!replied) {
if (rc >= 0)
- CWARN("%s: Unexpected rc >= 0 but no reply!\n",
- libcfs_id2str(id));
+ CWARN("%s: Unexpected rc(%d) >= 0 but no reply!\n",
+ libcfs_id2str(id), rc);
rc = -EIO;
goto out_1;
}
- nob = rc;
- LASSERT (nob >= 0 && nob <= infosz);
-
- rc = -EPROTO; /* if I can't parse... */
-
- if (nob < 8) {
- /* can't check magic/version */
- CERROR("%s: ping info too short %d\n",
- libcfs_id2str(id), nob);
- goto out_1;
- }
-
- if (info->pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) {
- lnet_swap_pinginfo(info);
- } else if (info->pi_magic != LNET_PROTO_PING_MAGIC) {
- CERROR("%s: Unexpected magic %08x\n",
- libcfs_id2str(id), info->pi_magic);
- goto out_1;
- }
-
- if (info->pi_version != LNET_PROTO_PING_VERSION) {
- CERROR("%s: Unexpected version 0x%x\n",
- libcfs_id2str(id), info->pi_version);
- goto out_1;
- }
-
- if (nob < offsetof(lnet_ping_info_t, pi_ni[0])) {
- CERROR("%s: Short reply %d(%d min)\n", libcfs_id2str(id),
- nob, (int)offsetof(lnet_ping_info_t, pi_ni[0]));
- goto out_1;
- }
-
- if (info->pi_nnis < n_ids)
- n_ids = info->pi_nnis;
-
- if (nob < offsetof(lnet_ping_info_t, pi_ni[n_ids])) {
- CERROR("%s: Short reply %d(%d expected)\n", libcfs_id2str(id),
- nob, (int)offsetof(lnet_ping_info_t, pi_ni[n_ids]));
+ LASSERT (rc >= 0 && rc <= infosz); /* rc == event.mlength */
+ rc = lnet_parse_pinginfo(info, rc, n_ids);
+ if (rc != 0) {
+ CERROR("Bad ping reply from %s\n", libcfs_id2str(id));
goto out_1;
}
rc = -EFAULT; /* If I SEGV... */
-
+ n_ids = MIN(info->pi_nnis, n_ids);
for (i = 0; i < n_ids; i++) {
tmpid.pid = info->pi_pid;
- tmpid.nid = info->pi_ni[i].ns_nid;
+ if (info->pi_version == LNET_PROTO_PING_VERSION)
+ tmpid.nid = info->pi_ni[i].ns_nid;
+ else
+ tmpid.nid = info->pi_nid[i];
+
#ifdef __KERNEL__
if (copy_to_user(&ids[i], &tmpid, sizeof(tmpid)))
goto out_1;
return -ENOENT;
}
-void
-lnet_swap_pinginfo(lnet_ping_info_t *info)
+int
+lnet_parse_pinginfo(lnet_ping_info_t *info, int len, int expected_nids)
{
- int i;
- lnet_ni_status_t *stat;
+ int rc = -EPROTO; /* if I can't parse... */
+ int i, swab, n_nids;
+
+ if (len < 8) { /* can't check magic/version */
+ CNETERR("Ping info too short %d\n", len);
+ return rc;
+ }
+
+ if (info->pi_magic == LNET_PROTO_PING_MAGIC) {
+ swab = 0;
+ } else if (info->pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) {
+ swab = 1;
+ } else {
+ CNETERR("Unexpected magic %08x\n", info->pi_magic);
+ return rc;
+ }
+
+ if (swab)
+ __swab32s(&info->pi_version);
+
+ if (info->pi_version != LNET_PROTO_PING_VERSION &&
+ info->pi_version != LNET_PROTO_PING_VERSION1) {
+ CNETERR("Unexpected version 0x%x\n", info->pi_version);
+ return rc;
+ }
+
+ if (len < lnet_pinginfo_size(0)) { /* can't check pid/nnis */
+ CNETERR("Short reply %d(%d min)\n", len,
+ (int)lnet_pinginfo_size(0));
+ return rc;
+ }
+
+ if (swab) {
+ __swab32s(&info->pi_pid);
+ __swab32s(&info->pi_nnis);
+ }
+
+ n_nids = MIN(info->pi_nnis, expected_nids);
+ if (len < lnet_pinginfo_size_v(n_nids, info->pi_version)) {
+ CNETERR("Short reply %d(%d expected)\n", len,
+ (int)lnet_pinginfo_size_v(n_nids, info->pi_version));
+ return rc;
+ }
+
+ if (!swab)
+ return 0;
+
+ for (i = 0; i < n_nids; i++) {
+ lnet_ni_status_t *stat;
+
+ if (info->pi_version == LNET_PROTO_PING_VERSION1) {
+ __swab64s(&info->pi_nid[i]);
+ continue;
+ }
- __swab32s(&info->pi_version);
- __swab32s(&info->pi_pid);
- __swab32s(&info->pi_nnis);
- for (i = 0; i < info->pi_nnis && i < LNET_MAX_RTR_NIS; i++) {
stat = &info->pi_ni[i];
__swab64s(&stat->ns_nid);
__swab32s(&stat->ns_status);
}
- return;
+ return 0;
}
/* Returns # of down NIs, or negative error codes; ignore downed NIs
int ptl_up = 0;
int ptl_down = 0;
lnet_ping_info_t *info;
+ int rc;
if (!avoid_asym_router_failure)
return -ENOENT;
info = rtr->lp_rcd->rcd_pinginfo;
LASSERT (info != NULL);
- /* NB always racing with network! */
- if (info->pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) {
- lnet_swap_pinginfo(info);
- } else if (info->pi_magic != LNET_PROTO_PING_MAGIC) {
- CNETERR("%s: Unexpected magic %08x\n",
- libcfs_nid2str(rtr->lp_nid), info->pi_magic);
+ rc = lnet_parse_pinginfo(info, /* NB always racing with network! */
+ LNET_MAX_PINGINFO_SIZE, LNET_MAX_RTR_NIS);
+ if (rc != 0) {
+ CNETERR("Bad ping reply from %s\n",
+ libcfs_nid2str(rtr->lp_nid));
return -EPROTO;
}
if (info->pi_version == LNET_PROTO_PING_VERSION1)
return -ENOENT; /* v1 doesn't carry NI status info */
- if (info->pi_version != LNET_PROTO_PING_VERSION) {
- CNETERR("%s: Unexpected version 0x%x\n",
- libcfs_nid2str(rtr->lp_nid), info->pi_version);
- return -EPROTO;
- }
-
for (i = 0; i < info->pi_nnis && i < LNET_MAX_RTR_NIS; i++) {
lnet_ni_status_t *stat = &info->pi_ni[i];
lnet_nid_t nid = stat->ns_nid;
/* detached from network */
LASSERT (LNetHandleIsEqual(rcd->rcd_mdh, LNET_INVALID_HANDLE));
- LIBCFS_FREE(rcd->rcd_pinginfo, LNET_PINGINFO_SIZE);
+ LIBCFS_FREE(rcd->rcd_pinginfo, LNET_MAX_PINGINFO_SIZE);
LIBCFS_FREE(rcd, sizeof(*rcd));
return;
}
if (rcd == NULL)
return NULL;
- LIBCFS_ALLOC(pi, LNET_PINGINFO_SIZE);
+ LIBCFS_ALLOC(pi, LNET_MAX_PINGINFO_SIZE);
if (pi == NULL) {
LIBCFS_FREE(rcd, sizeof(*rcd));
return NULL;
}
- memset(pi, 0, LNET_PINGINFO_SIZE);
+ memset(pi, 0, LNET_MAX_PINGINFO_SIZE);
for (i = 0; i < LNET_MAX_RTR_NIS; i++) {
pi->pi_ni[i].ns_nid = LNET_NID_ANY;
pi->pi_ni[i].ns_status = LNET_NI_STATUS_INVALID;
LASSERT (!LNetHandleIsEqual(the_lnet.ln_rc_eqh, LNET_EQ_NONE));
rc = LNetMDBind((lnet_md_t){.start = pi,
.user_ptr = rcd,
- .length = LNET_PINGINFO_SIZE,
+ .length = LNET_MAX_PINGINFO_SIZE,
.threshold = LNET_MD_THRESH_INF,
.options = LNET_MD_TRUNCATE,
.eq_handle = the_lnet.ln_rc_eqh},