Summary
nvme_mi_mctp_submit() handles "More Processing Required" responses with an unbounded retry: every MPR response just sets the next poll timeout from the device-supplied MPRT and jumps back to the retry: label (src/nvme/mi-mctp.c ~lines 498-590). There is no limit on consecutive MPR responses.
nvme_mi_ep_set_mprt_max() (default 0 = no limit) only clamps the per-iteration wait time, not the number of iterations.
Impact
A device that keeps answering MPR (faulty, or intentionally) blocks the calling thread forever while holding the preallocated MCTP message tag. Since the tag stays owned by the in-flight command, all other commands on the same endpoint stall behind it — a full endpoint-level denial of service from a single malfunctioning device. Unlike a timeout, this never recovers: poll() returns rc=0 only when the last-issued timeout expires, then the next MPR simply re-arms it.
My application's host fabric management stack can't easily work around this because the MPR handling is internal to the transport.
Possible directions (maintainer input wanted)
- Extend the
mprt_max semantics: interpret it as an absolute deadline for the whole command (sum of MPR waits), not just per-iteration clamp. Keeps the existing API, hardens the default-0 case to "no limit" (unchanged behavior) while giving callers a total budget. Note this technically changes the documented meaning of a non-zero mprt_max.
- Add a separate, internal cap on consecutive MPR responses (e.g. 100) with a config knob on the endpoint. Arbitrary default though; legitimate flows like SANITIZE can stream MPRs for a long time and must not be broken.
- Document the current semantics clearly, and expose the "still in MPR" state so callers can cancel via a separate thread.
Happy to implement whichever direction the maintainers prefer; submitting as an issue not a PR because the right policy here isn't obvious to me.
Summary
nvme_mi_mctp_submit()handles "More Processing Required" responses with an unbounded retry: every MPR response just sets the next poll timeout from the device-supplied MPRT and jumps back to theretry:label (src/nvme/mi-mctp.c ~lines 498-590). There is no limit on consecutive MPR responses.nvme_mi_ep_set_mprt_max()(default 0 = no limit) only clamps the per-iteration wait time, not the number of iterations.Impact
A device that keeps answering MPR (faulty, or intentionally) blocks the calling thread forever while holding the preallocated MCTP message tag. Since the tag stays owned by the in-flight command, all other commands on the same endpoint stall behind it — a full endpoint-level denial of service from a single malfunctioning device. Unlike a timeout, this never recovers:
poll()returns rc=0 only when the last-issued timeout expires, then the next MPR simply re-arms it.My application's host fabric management stack can't easily work around this because the MPR handling is internal to the transport.
Possible directions (maintainer input wanted)
mprt_maxsemantics: interpret it as an absolute deadline for the whole command (sum of MPR waits), not just per-iteration clamp. Keeps the existing API, hardens the default-0 case to "no limit" (unchanged behavior) while giving callers a total budget. Note this technically changes the documented meaning of a non-zero mprt_max.Happy to implement whichever direction the maintainers prefer; submitting as an issue not a PR because the right policy here isn't obvious to me.