Repository navigation
UCT/API: Purge outstanding work without an RX token - #12006
Conversation
|
🤖 Starting review — findings will be posted here when done. |
| } | ||
|
|
||
| delivered = 1; | ||
| } else { |
There was a problem hiding this comment.
Maybe set receiver_next_psn = first_failed_psn here and keep delivered = 1 before the loop? Then uct_ib_mlx5_wqe_is_delivered() returns false on the first WQE and the existing single code path marks everything undelivered, without the dead receiver_next_psn = 0.
There was a problem hiding this comment.
overcomplicating, receiver_next_psn is not used if delivered == 1, it's initialized to suppress compiler warns
| ctx.num_ops_posted_after_flush); | ||
| } | ||
|
|
||
| UCS_TEST_SKIP_COND_P(test_uct_purge_outstanding, am_short_no_rx_token, |
There was a problem hiding this comment.
This test body is a copy of am_short; can we extract a helper (e.g. do_test_am_short(bool with_rx_token)) and call it from both tests?
|
|
||
| EXPECT_GT(ctx.num_ops_purged_at_completion, 0u); | ||
| EXPECT_GT(ctx.num_ops_posted_after_flush, 0u); | ||
| EXPECT_EQ(ctx.num_ops_purged, ctx.num_ops_purged_at_completion + |
There was a problem hiding this comment.
These are the same expectations as am_short, so the test passes even if delivered operations are skipped. Can we also assert that everything posted is reported, e.g. return num_posted from test_purge_outstanding() and check num_ops_purged == num_posted when rx_token is omitted?
There was a problem hiding this comment.
ctx.num_ops_purged_at_completion + ctx.num_ops_posted_after_flush = num_posted
|
Coverage gap worth confirming with CI results: the no-token path is only exercised for |
|
🤖 CI Triage Agent — TL;DR: The "Basic compile" stage failed because commit Full analysisSummary: Azure Pipelines "Basic compile" job failed with Root cause: A botched edit (leftover text from a copy/paste) in 1350: if ((params->field_mask & UCT_EP_OUTSTANDING_FIELD_RX_TOKEN) &&
1351: (params->rx_token == NULL)) {
1352: ucs_error("rc mlx5: rx token is NULL");
1353: (params->rx_token == NULL)) { <-- stray duplicated line
1354: ucs_error("rc mlx5: rx token is not set");
1355: return UCS_ERR_INVALID_PARAM;
1356: }Line 1353 is a syntax error and, critically, opens an extra Implicated commit: File: Suggested fix: Remove the stray lines 1353–1354 so the check has one condition and one body: if ((params->field_mask & UCT_EP_OUTSTANDING_FIELD_RX_TOKEN) &&
(params->rx_token == NULL)) {
ucs_error("rc mlx5: rx token is NULL");
return UCS_ERR_INVALID_PARAM;
}Note this is the semantically correct form for this PR: Related: PR #12006 (branch |
|
🤖 Starting review — findings will be posted here when done. |
| } | ||
|
|
||
| if (!(params->field_mask & UCT_EP_OUTSTANDING_FIELD_RX_TOKEN)) { | ||
| if ((params->field_mask & UCT_EP_OUTSTANDING_FIELD_RX_TOKEN) && |
There was a problem hiding this comment.
blocker: leftover duplicated condition and error line, this does not compile.
| if ((params->field_mask & UCT_EP_OUTSTANDING_FIELD_RX_TOKEN) && | |
| if ((params->field_mask & UCT_EP_OUTSTANDING_FIELD_RX_TOKEN) && | |
| (params->rx_token == NULL)) { | |
| ucs_error("rc mlx5: rx token is NULL"); |
| * UCT_EP_OUTSTANDING_FIELD_CB must be set. */ | ||
| * UCT_EP_OUTSTANDING_FIELD_CB must be set. If @ref | ||
| * UCT_EP_OUTSTANDING_FIELD_RX_TOKEN is omitted, every outstanding | ||
| * operation is treated as undelivered. */ |
There was a problem hiding this comment.
The new "treated as undelivered" rule is only documented on field_mask; the function/callback doc still describes the callback as reporting undelivered operations, so a caller that reposts from op_info can duplicate data that the peer already received. Can we add this note to the @ref uct_ep_outstanding_purge doc as well, and mention that without the token the callback may also report operations the peer already received, so reposting them can duplicate data?
| ctx.num_ops_posted_after_flush); | ||
| } | ||
|
|
||
| UCS_TEST_SKIP_COND_P(test_uct_purge_outstanding, am_short_no_rx_token, |
There was a problem hiding this comment.
minor: this is an exact copy of am_short, pls move the body to a helper (e.g. test_am_short(bool with_rx_token)) and call it from both tests.
Omitting the RX token means the endpoint is unrecoverable. Every outstanding operation is treated as undelivered and completed canceled.
0149890 to
2799ee8
Compare
|
🤖 Starting review — findings will be posted here when done. |
| ctx.num_ops_posted_after_flush); | ||
| } | ||
|
|
||
| UCS_TEST_SKIP_COND_P(test_uct_purge_outstanding, am_short_no_rx_token, |
There was a problem hiding this comment.
the new test is a line-for-line copy of am_short except for the last argument; pls extract the body into a helper, e.g. test_am_short(bool with_rx_token), and keep both test cases as one-liners.
| * UCT_EP_OUTSTANDING_FIELD_CB must be set. */ | ||
| * UCT_EP_OUTSTANDING_FIELD_CB must be set. If @ref | ||
| * UCT_EP_OUTSTANDING_FIELD_RX_TOKEN is omitted, every outstanding | ||
| * operation is treated as undelivered. */ |
There was a problem hiding this comment.
minor: pls document the optional case on the rx_token field as well ("Valid when @ref UCT_EP_OUTSTANDING_FIELD_RX_TOKEN is set"), like arg does — the field_mask comment alone is easy to miss.
|
🤖 CI Triage Agent — TL;DR: The Coverity stage failed with 1 new defect (FORWARD_NULL) introduced by this PR's new Full analysisSummary: Azure job "coverity devel on coverity_rh7" failed: build and analysis succeeded, but Root cause: Not a build/test failure — a static-analysis gate. The reported path is:
The runtime code is actually safe: Implicated commit: File: Suggested fix: Remove the NULL from the path rather than suppressing it:
Related: PR #12006 (this change); prior work on the same code path: #11874, #11915, #11836, #11969
|
|
@evgeny-leksikov coverity issue seems real? |
| uct_iface_attr_v2_t tx_attr = {}; | ||
| uct_iface_attr_v2_t rx_attr = {}; | ||
| uct_ep_attr_t ep_attr = {}; | ||
| std::vector<uint8_t> tx_token; |
Coverity does not connect the field-mask check in the helper with the later dereference. Document the omitted-token purge case and share the am_short test body.
|
🤖 Starting review — findings will be posted here when done. |
| uct_iface_attr_v2_t rx_attr = {}; | ||
| uct_ep_attr_t ep_attr = {}; | ||
| std::vector<uint8_t> tx_token; | ||
| std::vector<uint8_t> rx_token; |
There was a problem hiding this comment.
blocker: rx_token is now declared inside the if (with_rx_token) block, so the vector is destroyed at the closing brace while purge_params.rx_token is still dereferenced by uct_ep_outstanding_purge() afterwards. The transport reads freed heap memory and derives receiver_next_psn from garbage, which can make the token path return UCS_ERR_INVALID_PARAM (psn_diff > num_outstanding_packets) or misclassify delivered WQEs. This affects all four existing token-based tests (am_short, put_short, put_bcopy, put_zcopy), not just the new one — before this PR the vectors lived at function scope.
Suggestion: declare std::vector<uint8_t> rx_token; at function scope (outside the if (with_rx_token) block) and keep only the other locals (tx_attr, rx_attr, ep_attr, tx_token) inside the block.
| num_outstanding_packets) & UCT_IB_MLX5_PSN_MASK; | ||
| if (params->field_mask & UCT_EP_OUTSTANDING_FIELD_RX_TOKEN) { | ||
| rx_token = params->rx_token; | ||
| if (rx_token == NULL) { |
There was a problem hiding this comment.
minor: the rx_token == NULL validation moved out of uct_rc_mlx5_ep_outstanding_purge_check_params(), which exists for exactly this. Can we keep this NULL check there together with the other parameter validation, so all parameter checks stay in one place and happen before any WQ walking?
|
🤖 CI Triage Agent — [incomplete: stop_reason=max_tokens] |
|
CI issue seems real. token tests pass freed storage. |
The vector was destroyed at the end of the if, while purge_params.rx_token still pointed into it.
|
🤖 Starting review — findings will be posted here when done. |
| num_outstanding_packets) & UCT_IB_MLX5_PSN_MASK; | ||
| if (params->field_mask & UCT_EP_OUTSTANDING_FIELD_RX_TOKEN) { | ||
| rx_token = params->rx_token; | ||
| if (rx_token == NULL) { |
There was a problem hiding this comment.
Parameter validation is now split between uct_rc_mlx5_ep_outstanding_purge_check_params() (NULL params, cb) and the main purge function (rx_token). A reader/maintainer has to look in two places for the purge param contract, and the rx_token check runs after the ucs_assertv_always() and packet-count work instead of with the other early checks.
pls keep this check in uct_rc_mlx5_ep_outstanding_purge_check_params() with the other param validations, so all the purge param contract stays in one place.
| } | ||
|
|
||
| void purge_outstanding(purge_ctx *ctx) | ||
| void purge_outstanding(purge_ctx *ctx, bool with_rx_token = true) |
There was a problem hiding this comment.
minor: the = true default value on purge_outstanding() is unused, the only caller passes it explicitly.
| void purge_outstanding(purge_ctx *ctx, bool with_rx_token = true) | |
| void purge_outstanding(purge_ctx *ctx, bool with_rx_token) |
What?
Purge outstanding work without an RX token. Omitting the RX token means the endpoint is unrecoverable. Every outstanding operation is treated as undelivered.
Why?
When the peer is unavailable this is a way to clean up the EP