diff options
Diffstat (limited to 'fs/xfs/xfs_aops.c')
-rw-r--r-- | fs/xfs/xfs_aops.c | 49 |
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); |