On Thu, 29 Feb 2024 at 00:13, Tong Tiangen <tongtiangen@xxxxxxxxxx> wrote: > > See the logic before this patch, always success (((void)(K),0)) is > returned for three types: ITER_BVEC, ITER_KVEC and ITER_XARRAY. No, look closer. Yes, the iterate_and_advance() macro does that "((void)(K),0)" to make the compiler generate better code for those cases (because then the compiler can see that the return value is a compile-time zero), but notice how _copy_mc_to_iter() didn't use that macro back then. It used the unvarnished __iterate_and_advance() exactly so that the MC copy case would *not* get that "always return zero" behavior. That goes back to (in a different form) at least commit 1b4fb5ffd79b ("iov_iter: teach iterate_{bvec,xarray}() about possible short copies"). But hardly anybody ever tests this machine-check special case code, so who knows when it broke again. I'm just looking at the source code, and with all the macro games it's *really* hard to follow, so I may well be missing something. > Maybe we're all gonna fix it back? as follows: No. We could do it for the kvec and xarray case, just to get better code generation again (not that I looked at it, so who knows), but the one case that actually uses memcpy_from_iter_mc() needs to react to a short write. One option might be to make a failed memcpy_from_iter_mc() set another flag in the iter, and then make fault_in_iov_iter_readable() test that flag and return 'len' if that flag is set. Something like that (wild handwaving) should get the right error handling. The simpler alternative is maybe something like the attached. COMPLETELY UNTESTED. Maybe I've confused myself with all the different indiraction mazes in the iov_iter code. Linus
lib/iov_iter.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/iov_iter.c b/lib/iov_iter.c index e0aa6b440ca5..5236c16734e0 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -248,7 +248,10 @@ static __always_inline size_t memcpy_from_iter_mc(void *iter_from, size_t progress, size_t len, void *to, void *priv2) { - return copy_mc_to_kernel(to + progress, iter_from, len); + size_t n = copy_mc_to_kernel(to + progress, iter_from, len); + if (n) + memset(to + progress - n, 0, n); + return 0; } static size_t __copy_from_iter_mc(void *addr, size_t bytes, struct iov_iter *i)