mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 20:54:10 +08: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
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;
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
const struct address_space_operations *a_ops = mapping->a_ops;
|
||||
size_t chunk = mapping_max_folio_size(mapping);
|
||||
long status = 0;
|
||||
ssize_t written = 0;
|
||||
|
||||
do {
|
||||
struct page *page;
|
||||
unsigned long offset; /* Offset into pagecache page */
|
||||
unsigned long bytes; /* Bytes to write to page */
|
||||
struct folio *folio;
|
||||
size_t offset; /* Offset into folio */
|
||||
size_t bytes; /* Bytes to write to folio */
|
||||
size_t copied; /* Bytes copied from user */
|
||||
void *fsdata = NULL;
|
||||
|
||||
offset = (pos & (PAGE_SIZE - 1));
|
||||
bytes = min_t(unsigned long, PAGE_SIZE - offset,
|
||||
iov_iter_count(i));
|
||||
bytes = iov_iter_count(i);
|
||||
retry:
|
||||
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_.
|
||||
* Otherwise there's a nasty deadlock on copying from the
|
||||
@ -4017,11 +4020,16 @@ again:
|
||||
if (unlikely(status < 0))
|
||||
break;
|
||||
|
||||
if (mapping_writably_mapped(mapping))
|
||||
flush_dcache_page(page);
|
||||
folio = page_folio(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);
|
||||
flush_dcache_page(page);
|
||||
if (mapping_writably_mapped(mapping))
|
||||
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,
|
||||
page, fsdata);
|
||||
@ -4039,14 +4047,16 @@ again:
|
||||
* halfway through, might be a race with munmap,
|
||||
* might be severe memory pressure.
|
||||
*/
|
||||
if (copied)
|
||||
if (chunk > PAGE_SIZE)
|
||||
chunk /= 2;
|
||||
if (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));
|
||||
|
||||
if (!written)
|
||||
|
Loading…
Reference in New Issue
Block a user