mm: add folio_zero_tail() and use it in ext4
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Tue, 7 Nov 2023 21:26:40 +0000 (21:26 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 11 Dec 2023 00:51:36 +0000 (16:51 -0800)
Patch series "Add folio_zero_tail() and folio_fill_tail()".

I'm trying to make it easier for filesystems with tailpacking / stuffing /
inline data to use folios.  The primary function here is
folio_fill_tail().  You give it a pointer to memory where the data
currently is, and it takes care of copying it into the folio at that
offset.  That works for gfs2 & iomap.  Then There's Ext4.  Rather than gin
up some kind of specialist "Here's a two pointers to two blocks of memory"
routine, just let it do its current thing, and let it call
folio_zero_tail(), which is also called by folio_fill_tail().

Other filesystems can be converted later; these ones seemed like good
examples as they're already partly or completely converted to folios.

This patch (of 3):

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.

[akpm@linux-foundation.org: fix kerneldoc argument ordering]
Link: https://lkml.kernel.org/r/20231107212643.3490372-1-willy@infradead.org
Link: https://lkml.kernel.org/r/20231107212643.3490372-2-willy@infradead.org
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
Cc: Darrick J. Wong <djwong@kernel.org>
Cc: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
fs/ext4/inline.c
include/linux/highmem.h

index 9a84a5f9fef43149e94e8b610ece4bbf07d0408a..d5bd1e3a5d36c679194dfe1082d484adf68e5bdb 100644 (file)
@@ -502,9 +502,8 @@ static int ext4_read_inline_folio(struct inode *inode, struct folio *folio)
        BUG_ON(len > PAGE_SIZE);
        kaddr = kmap_local_folio(folio, 0);
        ret = ext4_read_inline_data(inode, kaddr, len, &iloc);
-       flush_dcache_folio(folio);
+       kaddr = folio_zero_tail(folio, len, kaddr + len);
        kunmap_local(kaddr);
-       folio_zero_segment(folio, len, folio_size(folio));
        folio_mark_uptodate(folio);
        brelse(iloc.bh);
 
index be20cff4ba737038692c04cafd2c2abf0381694f..5ebd5e4dfbf855e56dbcf571d925b4031a9743cc 100644 (file)
@@ -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.
+ * @offset: The byte offset in the folio to start zeroing at.
+ * @kaddr: The address the folio is currently mapped to.
+ *
+ * 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)
+{
+       size_t len = folio_size(folio) - offset;
+
+       if (folio_test_highmem(folio)) {
+               size_t max = PAGE_SIZE - offset_in_page(offset);
+
+               while (len > max) {
+                       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;
+}
+
 /**
  * memcpy_from_file_folio - Copy some bytes from a file folio.
  * @to: The destination buffer.