|WARNING| [v2,2/2] net/ixgbe: fix return value of close operation
dpdklab at iol.unh.edu
dpdklab at iol.unh.edu
Wed Jul 15 15:51:08 CEST 2026
Test-Label: ai-code-review
Test-Status: WARNING
https://dpdk.org/patch/166742
_AI Code Review_
=== Patch Review: series.patch (via Claude) ===
Review date: 2026-07-15
# DPDK Patch Review
## Patch 1/2: net/i40e: fix return value of close operation
### Correctness Issues
**Error: Resource leak on unregister failure**
The patch stops retrying on non-`-EAGAIN` errors, but the interrupt callback remains registered if unregister fails. This leaks the callback registration, and the callback may fire after the device is closed, accessing freed memory.
The original retry loop at least attempted to unregister multiple times. Now, a transient error like `-EBUSY` terminates the loop immediately. While the comment says "non-transient," only `-EAGAIN` is documented as transient in the `rte_intr_callback_unregister()` contract; other negative values could be retryable hardware/system states.
**Suggested fix:**
Retain the retry logic for all negative errors, not just `-EAGAIN`. Only break on success (`>= 0`) or `-ENOENT` (callback not found). Log the final error if all retries fail, but do not store it in `ret` -- a failed unregister after earlier errors should not mask the first failure.
```c
do {
cb_ret = rte_intr_callback_unregister(intr_handle,
i40e_dev_interrupt_handler, dev);
if (cb_ret >= 0 || cb_ret == -ENOENT) {
break;
}
if (retries >= 5) {
PMD_INIT_LOG(ERR,
"intr callback unregister failed: %d",
cb_ret);
/* Do not overwrite earlier error */
if (ret == 0)
ret = cb_ret;
break;
}
i40e_msec_delay(500);
} while (++retries < 5);
```
**Error: Logic error in storing unregister failure**
The code checks `if (ret == 0)` before storing `cb_ret`, but `ret` is uninitialized at the start of the function. If a previous operation set `ret` to a positive value (e.g., from an earlier error that was cleared), the condition is false and the unregister error is silently dropped.
**Suggested fix:**
Initialize `ret = 0;` at function entry, or remove the conditional -- if unregister fails after all retries, that error should be returned even if earlier operations succeeded.
---
## Patch 2/2: net/ixgbe: fix return value of close operation
### Correctness Issues
**Error: Resource leak on unregister failure**
Same issue as i40e: the patch stops retrying on non-`-EAGAIN` errors, leaving the callback registered. The callback may fire after device close, accessing freed memory.
**Suggested fix:**
Same as i40e: retry on all negative errors, not just `-EAGAIN`. Only stop on success or `-ENOENT`. Log and optionally store the error only after all retries fail.
**Error: Logic error in storing unregister failure**
The code checks `if (ret == 0)` before storing `cb_ret`. The function calls `dev_stop` early, which can set `ret` to a negative value. If `dev_stop` failed (`ret < 0`), the condition `ret == 0` is false, and the unregister error is never stored.
This is the opposite problem from i40e: here, an unregister failure after a `dev_stop` failure is silently dropped. The intent is correct (preserve the first error), but the check is wrong -- it should be `if (ret >= 0)` to preserve negative stop errors but overwrite a successful stop (ret=0) with an unregister error.
**Suggested fix:**
```c
if (ret == 0)
ret = cb_ret;
```
is correct for the stated intent. The difference from i40e is that ixgbe explicitly calls `dev_stop` and stores its return value in `ret` before the unregister loop, so `ret` is initialized. Verify that `dev_stop` initializes `ret` on all paths.
However, the retry logic is still wrong (see above).
---
## Cross-Patch Consistency Issue
**Warning: Inconsistent retry limits**
i40e retries 5 times with 500ms delays (2.5s total). ixgbe retries 10 times with 100ms delays (1s total + `IXGBE_LINK_UP_TIME`, which is 20ms, so ~1.02s). The i40e timeout is longer but less granular. Consider using the same policy in both drivers unless there is a hardware reason for the difference.
---
## Style and Process
**Info: Variable naming**
`cb_ret` is clear. No issues.
**Info: Log message punctuation**
Both patches use `"intr callback unregister failed: %d"` without a trailing period. This is consistent with existing log style in both files. No change needed.
---
## Summary
Both patches address a real bug (positive return value leaking from `rte_intr_callback_unregister()`), but the fix introduces new problems:
1. **Retry logic too aggressive** -- stops on first non-`-EAGAIN` error, leaving callback registered
2. **i40e uses uninitialized `ret`** when checking whether to store unregister error
3. **ixgbe logic is correct** for storing unregister error, but retry issue remains
The correct approach is:
- Retry until success/`-ENOENT`, or until retry limit, regardless of error code
- Store unregister error in `ret` only if `ret == 0` (no prior error)
- Initialize `ret = 0;` at function entry in i40e
More information about the test-report
mailing list