mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
filemap: Convert generic_perform_write() to support large folios
Modelled after the loop in iomap_write_iter(), copy larger chunks from userspace if the filesystem has created large folios. [hch: use mapping_max_folio_size to keep supporting file systems that do not support large folios] Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Signed-off-by: Christoph Hellwig <hch@lst.de> Tested-by: Shaun Tancheff <shaun.tancheff@hpe.com> Tested-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
parent
146a99aefe
commit
9aac777aaf
1 changed files with 26 additions and 16 deletions
42
mm/filemap.c
42
mm/filemap.c
|
@ -3981,21 +3981,24 @@ ssize_t generic_perform_write(struct kiocb *iocb, struct iov_iter *i)
|
||||||
loff_t pos = iocb->ki_pos;
|
loff_t pos = iocb->ki_pos;
|
||||||
struct address_space *mapping = file->f_mapping;
|
struct address_space *mapping = file->f_mapping;
|
||||||
const struct address_space_operations *a_ops = mapping->a_ops;
|
const struct address_space_operations *a_ops = mapping->a_ops;
|
||||||
|
size_t chunk = mapping_max_folio_size(mapping);
|
||||||
long status = 0;
|
long status = 0;
|
||||||
ssize_t written = 0;
|
ssize_t written = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
struct page *page;
|
struct page *page;
|
||||||
unsigned long offset; /* Offset into pagecache page */
|
struct folio *folio;
|
||||||
unsigned long bytes; /* Bytes to write to page */
|
size_t offset; /* Offset into folio */
|
||||||
|
size_t bytes; /* Bytes to write to folio */
|
||||||
size_t copied; /* Bytes copied from user */
|
size_t copied; /* Bytes copied from user */
|
||||||
void *fsdata = NULL;
|
void *fsdata = NULL;
|
||||||
|
|
||||||
offset = (pos & (PAGE_SIZE - 1));
|
bytes = iov_iter_count(i);
|
||||||
bytes = min_t(unsigned long, PAGE_SIZE - offset,
|
retry:
|
||||||
iov_iter_count(i));
|
offset = pos & (chunk - 1);
|
||||||
|
bytes = min(chunk - offset, bytes);
|
||||||
|
balance_dirty_pages_ratelimited(mapping);
|
||||||
|
|
||||||
again:
|
|
||||||
/*
|
/*
|
||||||
* Bring in the user page that we will copy from _first_.
|
* Bring in the user page that we will copy from _first_.
|
||||||
* Otherwise there's a nasty deadlock on copying from the
|
* Otherwise there's a nasty deadlock on copying from the
|
||||||
|
@ -4017,11 +4020,16 @@ again:
|
||||||
if (unlikely(status < 0))
|
if (unlikely(status < 0))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (mapping_writably_mapped(mapping))
|
folio = page_folio(page);
|
||||||
flush_dcache_page(page);
|
offset = offset_in_folio(folio, pos);
|
||||||
|
if (bytes > folio_size(folio) - offset)
|
||||||
|
bytes = folio_size(folio) - offset;
|
||||||
|
|
||||||
copied = copy_page_from_iter_atomic(page, offset, bytes, i);
|
if (mapping_writably_mapped(mapping))
|
||||||
flush_dcache_page(page);
|
flush_dcache_folio(folio);
|
||||||
|
|
||||||
|
copied = copy_folio_from_iter_atomic(folio, offset, bytes, i);
|
||||||
|
flush_dcache_folio(folio);
|
||||||
|
|
||||||
status = a_ops->write_end(file, mapping, pos, bytes, copied,
|
status = a_ops->write_end(file, mapping, pos, bytes, copied,
|
||||||
page, fsdata);
|
page, fsdata);
|
||||||
|
@ -4039,14 +4047,16 @@ again:
|
||||||
* halfway through, might be a race with munmap,
|
* halfway through, might be a race with munmap,
|
||||||
* might be severe memory pressure.
|
* might be severe memory pressure.
|
||||||
*/
|
*/
|
||||||
if (copied)
|
if (chunk > PAGE_SIZE)
|
||||||
|
chunk /= 2;
|
||||||
|
if (copied) {
|
||||||
bytes = copied;
|
bytes = copied;
|
||||||
goto again;
|
goto retry;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pos += status;
|
||||||
|
written += status;
|
||||||
}
|
}
|
||||||
pos += status;
|
|
||||||
written += status;
|
|
||||||
|
|
||||||
balance_dirty_pages_ratelimited(mapping);
|
|
||||||
} while (iov_iter_count(i));
|
} while (iov_iter_count(i));
|
||||||
|
|
||||||
if (!written)
|
if (!written)
|
||||||
|
|
Loading…
Add table
Reference in a new issue