mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-01 10:42:11 +00:00
mm: add folio_fill_tail() and use it in iomap
The iomap code was limited to PAGE_SIZE bytes; generalise it to cover an arbitrary-sized folio, and move it to be a common helper. [akpm@linux-foundation.org: fix folio_fill_tail(), per Andreas Gruenbacher] Link: https://lkml.kernel.org/r/20231107212643.3490372-3-willy@infradead.org Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com> Cc: Andreas Dilger <adilger.kernel@dilger.ca> Cc: Darrick J. Wong <djwong@kernel.org> Cc: Theodore Ts'o <tytso@mit.edu> Cc: Andreas Gruenbacher <agruenba@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
a4fc4a0c45
commit
6eaa266b54
@ -305,28 +305,18 @@ static int iomap_read_inline_data(const struct iomap_iter *iter,
|
||||
{
|
||||
const struct iomap *iomap = iomap_iter_srcmap(iter);
|
||||
size_t size = i_size_read(iter->inode) - iomap->offset;
|
||||
size_t poff = offset_in_page(iomap->offset);
|
||||
size_t offset = offset_in_folio(folio, iomap->offset);
|
||||
void *addr;
|
||||
|
||||
if (folio_test_uptodate(folio))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON_ONCE(size > PAGE_SIZE - poff))
|
||||
return -EIO;
|
||||
if (WARN_ON_ONCE(size > PAGE_SIZE -
|
||||
offset_in_page(iomap->inline_data)))
|
||||
return -EIO;
|
||||
if (WARN_ON_ONCE(size > iomap->length))
|
||||
return -EIO;
|
||||
if (offset > 0)
|
||||
ifs_alloc(iter->inode, folio, iter->flags);
|
||||
|
||||
addr = kmap_local_folio(folio, offset);
|
||||
memcpy(addr, iomap->inline_data, size);
|
||||
memset(addr + size, 0, PAGE_SIZE - poff - size);
|
||||
kunmap_local(addr);
|
||||
iomap_set_range_uptodate(folio, offset, PAGE_SIZE - poff);
|
||||
folio_fill_tail(folio, offset, iomap->inline_data, size);
|
||||
iomap_set_range_uptodate(folio, offset, folio_size(folio) - offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -521,6 +521,44 @@ static inline __must_check void *folio_zero_tail(struct folio *folio,
|
||||
return kaddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* folio_fill_tail - Copy some data to a folio and pad with zeroes.
|
||||
* @folio: The destination folio.
|
||||
* @offset: The offset into @folio at which to start copying.
|
||||
* @from: The data to copy.
|
||||
* @len: How many bytes of data to copy.
|
||||
*
|
||||
* This function is most useful for filesystems which support inline data.
|
||||
* When they want to copy data from the inode into the page cache, this
|
||||
* function does everything for them. It supports large folios even on
|
||||
* HIGHMEM configurations.
|
||||
*/
|
||||
static inline void folio_fill_tail(struct folio *folio, size_t offset,
|
||||
const char *from, size_t len)
|
||||
{
|
||||
char *to = kmap_local_folio(folio, offset);
|
||||
|
||||
VM_BUG_ON(offset + len > folio_size(folio));
|
||||
|
||||
if (folio_test_highmem(folio)) {
|
||||
size_t max = PAGE_SIZE - offset_in_page(offset);
|
||||
|
||||
while (len > max) {
|
||||
memcpy(to, from, max);
|
||||
kunmap_local(to);
|
||||
len -= max;
|
||||
from += max;
|
||||
offset += max;
|
||||
max = PAGE_SIZE;
|
||||
to = kmap_local_folio(folio, offset);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(to, from, len);
|
||||
to = folio_zero_tail(folio, offset + len, to + len);
|
||||
kunmap_local(to);
|
||||
}
|
||||
|
||||
/**
|
||||
* memcpy_from_file_folio - Copy some bytes from a file folio.
|
||||
* @to: The destination buffer.
|
||||
|
Loading…
Reference in New Issue
Block a user