iomap: don't mark the inode dirty in iomap_write_end

Marking the inode dirty for each page copied into the page cache can be
very inefficient for file systems that use the VFS dirty inode tracking,
and is completely pointless for those that don't use the VFS dirty inode
tracking.  So instead, only set an iomap flag when changing the in-core
inode size, and open code the rest of __generic_write_end.

Partially based on code from Christoph Hellwig.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
Andreas Gruenbacher 2019-06-27 17:28:40 -07:00 committed by Darrick J. Wong
parent d1fdb6d8f6
commit 8d3e72a180
3 changed files with 17 additions and 1 deletions

View File

@ -1179,6 +1179,8 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
if (ip->i_qadata && ip->i_qadata->qa_qd_num) if (ip->i_qadata && ip->i_qadata->qa_qd_num)
gfs2_quota_unlock(ip); gfs2_quota_unlock(ip);
if (iomap->flags & IOMAP_F_SIZE_CHANGED)
mark_inode_dirty(inode);
gfs2_write_unlock(inode); gfs2_write_unlock(inode);
out: out:

View File

@ -773,6 +773,7 @@ iomap_write_end(struct inode *inode, loff_t pos, unsigned len,
unsigned copied, struct page *page, struct iomap *iomap) unsigned copied, struct page *page, struct iomap *iomap)
{ {
const struct iomap_page_ops *page_ops = iomap->page_ops; const struct iomap_page_ops *page_ops = iomap->page_ops;
loff_t old_size = inode->i_size;
int ret; int ret;
if (iomap->type == IOMAP_INLINE) { if (iomap->type == IOMAP_INLINE) {
@ -784,7 +785,19 @@ iomap_write_end(struct inode *inode, loff_t pos, unsigned len,
ret = __iomap_write_end(inode, pos, len, copied, page, iomap); ret = __iomap_write_end(inode, pos, len, copied, page, iomap);
} }
__generic_write_end(inode, pos, ret, page); /*
* Update the in-memory inode size after copying the data into the page
* cache. It's up to the file system to write the updated size to disk,
* preferably after I/O completion so that no stale data is exposed.
*/
if (pos + ret > old_size) {
i_size_write(inode, pos + ret);
iomap->flags |= IOMAP_F_SIZE_CHANGED;
}
unlock_page(page);
if (old_size < pos)
pagecache_isize_extended(inode, old_size, pos);
if (page_ops && page_ops->page_done) if (page_ops && page_ops->page_done)
page_ops->page_done(inode, pos, copied, page, iomap); page_ops->page_done(inode, pos, copied, page, iomap);
put_page(page); put_page(page);

View File

@ -35,6 +35,7 @@ struct vm_fault;
#define IOMAP_F_NEW 0x01 /* blocks have been newly allocated */ #define IOMAP_F_NEW 0x01 /* blocks have been newly allocated */
#define IOMAP_F_DIRTY 0x02 /* uncommitted metadata */ #define IOMAP_F_DIRTY 0x02 /* uncommitted metadata */
#define IOMAP_F_BUFFER_HEAD 0x04 /* file system requires buffer heads */ #define IOMAP_F_BUFFER_HEAD 0x04 /* file system requires buffer heads */
#define IOMAP_F_SIZE_CHANGED 0x08 /* file size has changed */
/* /*
* Flags that only need to be reported for IOMAP_REPORT requests: * Flags that only need to be reported for IOMAP_REPORT requests: