From: Kefeng Wang wangkefeng.wang@huawei.com
hulk inclusion category: performance bugzilla: https://gitee.com/openeuler/kernel/issues/IAO6NS
--------------------------------
The tmpfs supports large folio, but there is some configurable options to enable/disable large folio allocation, and for huge=within_size, large folio only allowabled if it fully within i_size, so there is performance issue when perform write without large folio, it is very similar with commit 4e527d5841e2 ("iomap: fault in smaller chunks for non-large folio mappings"),
Fix it by checking whether it allows large folio allocation or not before perform write.
Fixes: 9aac777aaf94 ("filemap: Convert generic_perform_write() to support large folios") Signed-off-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Liu Shixin liushixin2@huawei.com --- include/linux/fs.h | 2 ++ mm/filemap.c | 7 ++++++- mm/shmem.c | 5 +++++ 3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h index e7c55ebb9d71..5e37afb1b844 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -372,6 +372,8 @@ enum rw_hint { #define IOCB_DIO_CALLER_COMP (1 << 22) /* kiocb is a read or write operation submitted by fs/aio.c. */ #define IOCB_AIO_RW (1 << 23) +/* fault int small chunks(PAGE_SIZE) from userspace */ +#define IOCB_NO_LARGE_CHUNK (1 << 24)
/* for use in trace events */ #define TRACE_IOCB_STRINGS \ diff --git a/mm/filemap.c b/mm/filemap.c index 1d5d5f1c2b54..5d8e8810ae34 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -4043,9 +4043,14 @@ 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; + size_t chunk; + + if (iocb->ki_flags & IOCB_NO_LARGE_CHUNK) + chunk = PAGE_SIZE; + else + chunk = mapping_max_folio_size(mapping);
do { struct page *page; diff --git a/mm/shmem.c b/mm/shmem.c index 700335e56e67..72e0ec87219e 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3042,6 +3042,7 @@ static ssize_t shmem_file_write_iter(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; + pgoff_t index = iocb->ki_pos >> PAGE_SHIFT; ssize_t ret;
inode_lock(inode); @@ -3054,6 +3055,10 @@ static ssize_t shmem_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ret = file_update_time(file); if (ret) goto unlock; + + if (!shmem_allowable_huge_orders(inode, NULL, index, 0, false)) + iocb->ki_flags |= IOCB_NO_LARGE_CHUNK; + ret = generic_perform_write(iocb, from); unlock: inode_unlock(inode);