Skip to content

Commit e3a491a

Browse files
Christoph Hellwigbrauner
authored andcommitted
iomap: factor out a iomap_writepage_handle_eof helper
Most of iomap_do_writepage is dedidcated to handling a folio crossing or beyond i_size. Split this is into a separate helper and update the commens to deal with folios instead of pages and make them more readable. Signed-off-by: Christoph Hellwig <hch@lst.de> Link: https://lore.kernel.org/r/20231207072710.176093-6-hch@lst.de Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent c2dc7e5 commit e3a491a

File tree

1 file changed

+62
-66
lines changed

1 file changed

+62
-66
lines changed

fs/iomap/buffered-io.c

Lines changed: 62 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,64 @@ iomap_add_to_ioend(struct inode *inode, loff_t pos, struct folio *folio,
17581758
wbc_account_cgroup_owner(wbc, &folio->page, len);
17591759
}
17601760

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+
17611819
/*
17621820
* We implement an immediate ioend submission policy here to avoid needing to
17631821
* chain multiple ioends and hence nest mempool allocations which can violate
@@ -1898,78 +1956,16 @@ static int iomap_do_writepage(struct folio *folio,
18981956
{
18991957
struct iomap_writepage_ctx *wpc = data;
19001958
struct inode *inode = folio->mapping->host;
1901-
u64 end_pos, isize;
1959+
u64 end_pos = folio_pos(folio) + folio_size(folio);
19021960

19031961
trace_iomap_writepage(inode, folio_pos(folio), folio_size(folio));
19041962

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;
19661966
}
19671967

19681968
return iomap_writepage_map(wpc, wbc, inode, folio, end_pos);
1969-
1970-
unlock:
1971-
folio_unlock(folio);
1972-
return 0;
19731969
}
19741970

19751971
int

0 commit comments

Comments
 (0)