Skip to content

Commit 677b60d

Browse files
committed
Merge tag 'iomap-5.6-merge-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
Pull iomap fix from Darrick Wong: "A single patch fixing an off-by-one error when we're checking to see how far we're gotten into an EOF page" * tag 'iomap-5.6-merge-3' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: fs: Fix page_mkwrite off-by-one errors
2 parents 7eec11d + 243145b commit 677b60d

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

fs/iomap/buffered-io.c

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,24 +1077,16 @@ vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf, const struct iomap_ops *ops)
10771077
struct page *page = vmf->page;
10781078
struct inode *inode = file_inode(vmf->vma->vm_file);
10791079
unsigned long length;
1080-
loff_t offset, size;
1080+
loff_t offset;
10811081
ssize_t ret;
10821082

10831083
lock_page(page);
1084-
size = i_size_read(inode);
1085-
offset = page_offset(page);
1086-
if (page->mapping != inode->i_mapping || offset > size) {
1087-
/* We overload EFAULT to mean page got truncated */
1088-
ret = -EFAULT;
1084+
ret = page_mkwrite_check_truncate(page, inode);
1085+
if (ret < 0)
10891086
goto out_unlock;
1090-
}
1091-
1092-
/* page is wholly or partially inside EOF */
1093-
if (offset > size - PAGE_SIZE)
1094-
length = offset_in_page(size);
1095-
else
1096-
length = PAGE_SIZE;
1087+
length = ret;
10971088

1089+
offset = page_offset(page);
10981090
while (length > 0) {
10991091
ret = iomap_apply(inode, offset, length,
11001092
IOMAP_WRITE | IOMAP_FAULT, ops, page,

include/linux/pagemap.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,4 +636,32 @@ static inline unsigned long dir_pages(struct inode *inode)
636636
PAGE_SHIFT;
637637
}
638638

639+
/**
640+
* page_mkwrite_check_truncate - check if page was truncated
641+
* @page: the page to check
642+
* @inode: the inode to check the page against
643+
*
644+
* Returns the number of bytes in the page up to EOF,
645+
* or -EFAULT if the page was truncated.
646+
*/
647+
static inline int page_mkwrite_check_truncate(struct page *page,
648+
struct inode *inode)
649+
{
650+
loff_t size = i_size_read(inode);
651+
pgoff_t index = size >> PAGE_SHIFT;
652+
int offset = offset_in_page(size);
653+
654+
if (page->mapping != inode->i_mapping)
655+
return -EFAULT;
656+
657+
/* page is wholly inside EOF */
658+
if (page->index < index)
659+
return PAGE_SIZE;
660+
/* page is wholly past EOF */
661+
if (page->index > index || !offset)
662+
return -EFAULT;
663+
/* page is partially inside EOF */
664+
return offset;
665+
}
666+
639667
#endif /* _LINUX_PAGEMAP_H */

0 commit comments

Comments
 (0)