Re: [PATCH 1/3] mm: Add folio_zero_tail() and use it in ext4

Andrew Morton
2023-11-08T23:06:09Z

On Tue, 7 Nov 2023 21:26:40 +0000 "Matthew Wilcox (Oracle)" <willy@infradead.org> wrote:

> Instead of unmapping the folio after copying the data to it, then mapping
> it again to zero the tail, provide folio_zero_tail() to zero the tail
> of an already-mapped folio.
>
> ...
>
> --- a/include/linux/highmem.h
> +++ b/include/linux/highmem.h
> @@ -483,6 +483,44 @@ static inline void memcpy_to_folio(struct folio *folio, size_t offset,
> flush_dcache_folio(folio);
> }
>
> +/**
> + * folio_zero_tail - Zero the tail of a folio.
> + * @folio: The folio to zero.
> + * @kaddr: The address the folio is currently mapped to.
> + * @offset: The byte offset in the folio to start zeroing at.

That's the argument ordering I would expect.

> + * If you have already used kmap_local_folio() to map a folio, written
> + * some data to it and now need to zero the end of the folio (and flush
> + * the dcache), you can use this function. If you do not have the
> + * folio kmapped (eg the folio has been partially populated by DMA),
> + * use folio_zero_range() or folio_zero_segment() instead.
> + *
> + * Return: An address which can be passed to kunmap_local().
> + */
> +static inline __must_check void *folio_zero_tail(struct folio *folio,
> + size_t offset, void *kaddr)

While that is not. addr,len is far more common that len,addr?

> +{
> + size_t len = folio_size(folio) - offset;

Calling it `remaining' would be more clear.

> +
> + if (folio_test_highmem(folio)) {
> + size_t max = PAGE_SIZE - offset_in_page(offset);
> +
> + while (len > max) {

Shouldn't this be `while (len)'? AFAICT this code can fail to clear
the final page.

> + memset(kaddr, 0, max);
> + kunmap_local(kaddr);
> + len -= max;
> + offset += max;
> + max = PAGE_SIZE;
> + kaddr = kmap_local_folio(folio, offset);
> + }
> + }
> +
> + memset(kaddr, 0, len);
> + flush_dcache_folio(folio);
> +
> + return kaddr;
> +}
> +