@@ -1758,6 +1758,64 @@ iomap_add_to_ioend(struct inode *inode, loff_t pos, struct folio *folio,
1758
1758
wbc_account_cgroup_owner (wbc , & folio -> page , len );
1759
1759
}
1760
1760
1761
+ /*
1762
+ * Check interaction of the folio with the file end.
1763
+ *
1764
+ * If the folio is entirely beyond i_size, return false. If it straddles
1765
+ * i_size, adjust end_pos and zero all data beyond i_size.
1766
+ */
1767
+ static bool iomap_writepage_handle_eof (struct folio * folio , struct inode * inode ,
1768
+ u64 * end_pos )
1769
+ {
1770
+ u64 isize = i_size_read (inode );
1771
+
1772
+ if (* end_pos > isize ) {
1773
+ size_t poff = offset_in_folio (folio , isize );
1774
+ pgoff_t end_index = isize >> PAGE_SHIFT ;
1775
+
1776
+ /*
1777
+ * If the folio is entirely ouside of i_size, skip it.
1778
+ *
1779
+ * This can happen due to a truncate operation that is in
1780
+ * progress and in that case truncate will finish it off once
1781
+ * we've dropped the folio lock.
1782
+ *
1783
+ * Note that the pgoff_t used for end_index is an unsigned long.
1784
+ * If the given offset is greater than 16TB on a 32-bit system,
1785
+ * then if we checked if the folio is fully outside i_size with
1786
+ * "if (folio->index >= end_index + 1)", "end_index + 1" would
1787
+ * overflow and evaluate to 0. Hence this folio would be
1788
+ * redirtied and written out repeatedly, which would result in
1789
+ * an infinite loop; the user program performing this operation
1790
+ * would hang. Instead, we can detect this situation by
1791
+ * checking if the folio is totally beyond i_size or if its
1792
+ * offset is just equal to the EOF.
1793
+ */
1794
+ if (folio -> index > end_index ||
1795
+ (folio -> index == end_index && poff == 0 ))
1796
+ return false;
1797
+
1798
+ /*
1799
+ * The folio straddles i_size.
1800
+ *
1801
+ * It must be zeroed out on each and every writepage invocation
1802
+ * because it may be mmapped:
1803
+ *
1804
+ * A file is mapped in multiples of the page size. For a
1805
+ * file that is not a multiple of the page size, the
1806
+ * remaining memory is zeroed when mapped, and writes to that
1807
+ * region are not written out to the file.
1808
+ *
1809
+ * Also adjust the writeback range to skip all blocks entirely
1810
+ * beyond i_size.
1811
+ */
1812
+ folio_zero_segment (folio , poff , folio_size (folio ));
1813
+ * end_pos = isize ;
1814
+ }
1815
+
1816
+ return true;
1817
+ }
1818
+
1761
1819
/*
1762
1820
* We implement an immediate ioend submission policy here to avoid needing to
1763
1821
* chain multiple ioends and hence nest mempool allocations which can violate
@@ -1898,78 +1956,16 @@ static int iomap_do_writepage(struct folio *folio,
1898
1956
{
1899
1957
struct iomap_writepage_ctx * wpc = data ;
1900
1958
struct inode * inode = folio -> mapping -> host ;
1901
- u64 end_pos , isize ;
1959
+ u64 end_pos = folio_pos ( folio ) + folio_size ( folio ) ;
1902
1960
1903
1961
trace_iomap_writepage (inode , folio_pos (folio ), folio_size (folio ));
1904
1962
1905
- /*
1906
- * Is this folio beyond the end of the file?
1907
- *
1908
- * The folio index is less than the end_index, adjust the end_pos
1909
- * to the highest offset that this folio should represent.
1910
- * -----------------------------------------------------
1911
- * | file mapping | <EOF> |
1912
- * -----------------------------------------------------
1913
- * | Page ... | Page N-2 | Page N-1 | Page N | |
1914
- * ^--------------------------------^----------|--------
1915
- * | desired writeback range | see else |
1916
- * ---------------------------------^------------------|
1917
- */
1918
- isize = i_size_read (inode );
1919
- end_pos = folio_pos (folio ) + folio_size (folio );
1920
- if (end_pos > isize ) {
1921
- /*
1922
- * Check whether the page to write out is beyond or straddles
1923
- * i_size or not.
1924
- * -------------------------------------------------------
1925
- * | file mapping | <EOF> |
1926
- * -------------------------------------------------------
1927
- * | Page ... | Page N-2 | Page N-1 | Page N | Beyond |
1928
- * ^--------------------------------^-----------|---------
1929
- * | | Straddles |
1930
- * ---------------------------------^-----------|--------|
1931
- */
1932
- size_t poff = offset_in_folio (folio , isize );
1933
- pgoff_t end_index = isize >> PAGE_SHIFT ;
1934
-
1935
- /*
1936
- * Skip the page if it's fully outside i_size, e.g.
1937
- * due to a truncate operation that's in progress. We've
1938
- * cleaned this page and truncate will finish things off for
1939
- * us.
1940
- *
1941
- * Note that the end_index is unsigned long. If the given
1942
- * offset is greater than 16TB on a 32-bit system then if we
1943
- * checked if the page is fully outside i_size with
1944
- * "if (page->index >= end_index + 1)", "end_index + 1" would
1945
- * overflow and evaluate to 0. Hence this page would be
1946
- * redirtied and written out repeatedly, which would result in
1947
- * an infinite loop; the user program performing this operation
1948
- * would hang. Instead, we can detect this situation by
1949
- * checking if the page is totally beyond i_size or if its
1950
- * offset is just equal to the EOF.
1951
- */
1952
- if (folio -> index > end_index ||
1953
- (folio -> index == end_index && poff == 0 ))
1954
- goto unlock ;
1955
-
1956
- /*
1957
- * The page straddles i_size. It must be zeroed out on each
1958
- * and every writepage invocation because it may be mmapped.
1959
- * "A file is mapped in multiples of the page size. For a file
1960
- * that is not a multiple of the page size, the remaining
1961
- * memory is zeroed when mapped, and writes to that region are
1962
- * not written out to the file."
1963
- */
1964
- folio_zero_segment (folio , poff , folio_size (folio ));
1965
- end_pos = isize ;
1963
+ if (!iomap_writepage_handle_eof (folio , inode , & end_pos )) {
1964
+ folio_unlock (folio );
1965
+ return 0 ;
1966
1966
}
1967
1967
1968
1968
return iomap_writepage_map (wpc , wbc , inode , folio , end_pos );
1969
-
1970
- unlock :
1971
- folio_unlock (folio );
1972
- return 0 ;
1973
1969
}
1974
1970
1975
1971
int
0 commit comments