|
|
|
@ -982,7 +982,32 @@ xfs_vm_writepage( |
|
|
|
|
offset = i_size_read(inode); |
|
|
|
|
end_index = offset >> PAGE_CACHE_SHIFT; |
|
|
|
|
last_index = (offset - 1) >> PAGE_CACHE_SHIFT; |
|
|
|
|
if (page->index >= end_index) { |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The page index is less than the end_index, adjust the end_offset |
|
|
|
|
* to the highest offset that this page should represent. |
|
|
|
|
* ----------------------------------------------------- |
|
|
|
|
* | file mapping | <EOF> | |
|
|
|
|
* ----------------------------------------------------- |
|
|
|
|
* | Page ... | Page N-2 | Page N-1 | Page N | | |
|
|
|
|
* ^--------------------------------^----------|-------- |
|
|
|
|
* | desired writeback range | see else | |
|
|
|
|
* ---------------------------------^------------------| |
|
|
|
|
*/ |
|
|
|
|
if (page->index < end_index) |
|
|
|
|
end_offset = (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT; |
|
|
|
|
else { |
|
|
|
|
/*
|
|
|
|
|
* Check whether the page to write out is beyond or straddles |
|
|
|
|
* i_size or not. |
|
|
|
|
* ------------------------------------------------------- |
|
|
|
|
* | file mapping | <EOF> | |
|
|
|
|
* ------------------------------------------------------- |
|
|
|
|
* | Page ... | Page N-2 | Page N-1 | Page N | Beyond | |
|
|
|
|
* ^--------------------------------^-----------|--------- |
|
|
|
|
* | | Straddles | |
|
|
|
|
* ---------------------------------^-----------|--------| |
|
|
|
|
*/ |
|
|
|
|
unsigned offset_into_page = offset & (PAGE_CACHE_SIZE - 1); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -990,24 +1015,36 @@ xfs_vm_writepage( |
|
|
|
|
* truncate operation that is in progress. We must redirty the |
|
|
|
|
* page so that reclaim stops reclaiming it. Otherwise |
|
|
|
|
* xfs_vm_releasepage() is called on it and gets confused. |
|
|
|
|
* |
|
|
|
|
* Note that the end_index is unsigned long, it would overflow |
|
|
|
|
* if the given offset is greater than 16TB on 32-bit system |
|
|
|
|
* and if we do check the page is fully outside i_size or not |
|
|
|
|
* via "if (page->index >= end_index + 1)" as "end_index + 1" |
|
|
|
|
* will be evaluated to 0. Hence this page will be redirtied |
|
|
|
|
* and be written out repeatedly which would result in an |
|
|
|
|
* infinite loop, the user program that perform this operation |
|
|
|
|
* will hang. Instead, we can verify this situation by checking |
|
|
|
|
* if the page to write is totally beyond the i_size or if it's |
|
|
|
|
* offset is just equal to the EOF. |
|
|
|
|
*/ |
|
|
|
|
if (page->index >= end_index + 1 || offset_into_page == 0) |
|
|
|
|
if (page->index > end_index || |
|
|
|
|
(page->index == end_index && offset_into_page == 0)) |
|
|
|
|
goto redirty; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The page straddles i_size. It must be zeroed out on each |
|
|
|
|
* and every writepage invocation because it may be mmapped. |
|
|
|
|
* "A file is mapped in multiples of the page size. For a file |
|
|
|
|
* that is not a multiple of the page size, the remaining |
|
|
|
|
* that is not a multiple of the page size, the remaining |
|
|
|
|
* memory is zeroed when mapped, and writes to that region are |
|
|
|
|
* not written out to the file." |
|
|
|
|
*/ |
|
|
|
|
zero_user_segment(page, offset_into_page, PAGE_CACHE_SIZE); |
|
|
|
|
|
|
|
|
|
/* Adjust the end_offset to the end of file */ |
|
|
|
|
end_offset = offset; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
end_offset = min_t(unsigned long long, |
|
|
|
|
(xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT, |
|
|
|
|
offset); |
|
|
|
|
len = 1 << inode->i_blkbits; |
|
|
|
|
|
|
|
|
|
bh = head = page_buffers(page); |
|
|
|
|