Re: [PATCH] iov_iter: Four fixes for ITER_XARRAY

From: Al Viro
Date: Mon Apr 26 2021 - 13:14:49 EST


On Mon, Apr 26, 2021 at 12:14:50AM +0100, David Howells wrote:
> Hi Al,
>
> I think this patch should include all the fixes necessary. I could merge
> it in, but I think it might be better to tag it on the end as an additional
> patch.

Looks sane, but I wonder if it would've been better to deal with this

> @@ -791,6 +791,8 @@ size_t _copy_mc_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
> curr_addr = (unsigned long) from;
> bytes = curr_addr - s_addr - rem;
> rcu_read_unlock();
> + i->iov_offset += bytes;
> + i->count -= bytes;
> return bytes;
> }
> })

by having your iterator check the return value of X callback and, having
decremented .bv_len by return value, broke out of the loop.

__label__ __bugger_off;

xas_for_each(&xas, head, ULONG_MAX) { \
if (xas_retry(&xas, head)) \
continue; \
if (WARN_ON(xa_is_value(head))) \
break; \
if (WARN_ON(PageHuge(head))) \
break; \
for (j = (head->index < index) ? index - head->index : 0; \
j < thp_nr_pages(head); j++) { \
__v.bv_page = head + j; \

size_t left;

offset = (i->xarray_start + skip) & ~PAGE_MASK; \
seg = PAGE_SIZE - offset; \
__v.bv_offset = offset; \
__v.bv_len = min(n, seg); \

left = (STEP);
__v.bv_len -= left;

n -= __v.bv_len; \
skip += __v.bv_len; \

if (!n || left)
goto __bugger_off;

} \
if (n == 0) \
break; \
} \

__bugger_off:


Then rename iterate_and_advance() to __iterate_and_advance() and have
#define iterate_and_advance(....., X) __iterate_and_advance(....., ((void)(X),0))
with iterate_all_kinds() using iterate_xarray(....,((void)(X),0)

Then _copy_mc_to_iter() could use __iterate_and_advance(), getting rid of
the need of doing anything special in case of short copy. OTOH, I can do
that myself in a followup - not a problem.