aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_aops.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_aops.c')
-rw-r--r--fs/xfs/xfs_aops.c49
1 files changed, 43 insertions, 6 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 0479c32c5eb1..d1b99b692ccb 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -982,7 +982,32 @@ xfs_vm_writepage(
982 offset = i_size_read(inode); 982 offset = i_size_read(inode);
983 end_index = offset >> PAGE_CACHE_SHIFT; 983 end_index = offset >> PAGE_CACHE_SHIFT;
984 last_index = (offset - 1) >> PAGE_CACHE_SHIFT; 984 last_index = (offset - 1) >> PAGE_CACHE_SHIFT;
985 if (page->index >= end_index) { 985
986 /*
987 * The page index is less than the end_index, adjust the end_offset
988 * to the highest offset that this page should represent.
989 * -----------------------------------------------------
990 * | file mapping | <EOF> |
991 * -----------------------------------------------------
992 * | Page ... | Page N-2 | Page N-1 | Page N | |
993 * ^--------------------------------^----------|--------
994 * | desired writeback range | see else |
995 * ---------------------------------^------------------|
996 */
997 if (page->index < end_index)
998 end_offset = (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT;
999 else {
1000 /*
1001 * Check whether the page to write out is beyond or straddles
1002 * i_size or not.
1003 * -------------------------------------------------------
1004 * | file mapping | <EOF> |
1005 * -------------------------------------------------------
1006 * | Page ... | Page N-2 | Page N-1 | Page N | Beyond |
1007 * ^--------------------------------^-----------|---------
1008 * | | Straddles |
1009 * ---------------------------------^-----------|--------|
1010 */
986 unsigned offset_into_page = offset & (PAGE_CACHE_SIZE - 1); 1011 unsigned offset_into_page = offset & (PAGE_CACHE_SIZE - 1);
987 1012
988 /* 1013 /*
@@ -990,24 +1015,36 @@ xfs_vm_writepage(
990 * truncate operation that is in progress. We must redirty the 1015 * truncate operation that is in progress. We must redirty the
991 * page so that reclaim stops reclaiming it. Otherwise 1016 * page so that reclaim stops reclaiming it. Otherwise
992 * xfs_vm_releasepage() is called on it and gets confused. 1017 * xfs_vm_releasepage() is called on it and gets confused.
1018 *
1019 * Note that the end_index is unsigned long, it would overflow
1020 * if the given offset is greater than 16TB on 32-bit system
1021 * and if we do check the page is fully outside i_size or not
1022 * via "if (page->index >= end_index + 1)" as "end_index + 1"
1023 * will be evaluated to 0. Hence this page will be redirtied
1024 * and be written out repeatedly which would result in an
1025 * infinite loop, the user program that perform this operation
1026 * will hang. Instead, we can verify this situation by checking
1027 * if the page to write is totally beyond the i_size or if it's
1028 * offset is just equal to the EOF.
993 */ 1029 */
994 if (page->index >= end_index + 1 || offset_into_page == 0) 1030 if (page->index > end_index ||
1031 (page->index == end_index && offset_into_page == 0))
995 goto redirty; 1032 goto redirty;
996 1033
997 /* 1034 /*
998 * The page straddles i_size. It must be zeroed out on each 1035 * The page straddles i_size. It must be zeroed out on each
999 * and every writepage invocation because it may be mmapped. 1036 * and every writepage invocation because it may be mmapped.
1000 * "A file is mapped in multiples of the page size. For a file 1037 * "A file is mapped in multiples of the page size. For a file
1001 * that is not a multiple of the page size, the remaining 1038 * that is not a multiple of the page size, the remaining
1002 * memory is zeroed when mapped, and writes to that region are 1039 * memory is zeroed when mapped, and writes to that region are
1003 * not written out to the file." 1040 * not written out to the file."
1004 */ 1041 */
1005 zero_user_segment(page, offset_into_page, PAGE_CACHE_SIZE); 1042 zero_user_segment(page, offset_into_page, PAGE_CACHE_SIZE);
1043
1044 /* Adjust the end_offset to the end of file */
1045 end_offset = offset;
1006 } 1046 }
1007 1047
1008 end_offset = min_t(unsigned long long,
1009 (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT,
1010 offset);
1011 len = 1 << inode->i_blkbits; 1048 len = 1 << inode->i_blkbits;
1012 1049
1013 bh = head = page_buffers(page); 1050 bh = head = page_buffers(page);