diff options
| -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); |
