Skip to content

Commit 566d336

Browse files
Hugh Dickinstorvalds
Hugh Dickins
authored andcommitted
mm: warn on deleting redirtied only if accounted
filemap_unaccount_folio() has a WARN_ON_ONCE(folio_test_dirty(folio)). It is good to warn of late dirtying on a persistent filesystem, but late dirtying on tmpfs can only lose data which is expected to be thrown away; and it's a pity if that warning comes ONCE on tmpfs, then hides others which really matter. Make it conditional on mapping_cap_writeback(). Cleanup: then folio_account_cleaned() no longer needs to check that for itself, and so no longer needs to know the mapping. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Hugh Dickins <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Jan Kara <[email protected]> Cc: Christoph Hellwig <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 7f76091 commit 566d336

File tree

3 files changed

+18
-17
lines changed

3 files changed

+18
-17
lines changed

include/linux/pagemap.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,8 +1009,7 @@ static inline void __set_page_dirty(struct page *page,
10091009
{
10101010
__folio_mark_dirty(page_folio(page), mapping, warn);
10111011
}
1012-
void folio_account_cleaned(struct folio *folio, struct address_space *mapping,
1013-
struct bdi_writeback *wb);
1012+
void folio_account_cleaned(struct folio *folio, struct bdi_writeback *wb);
10141013
void __folio_cancel_dirty(struct folio *folio);
10151014
static inline void folio_cancel_dirty(struct folio *folio)
10161015
{

mm/filemap.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,16 +193,20 @@ static void filemap_unaccount_folio(struct address_space *mapping,
193193
/*
194194
* At this point folio must be either written or cleaned by
195195
* truncate. Dirty folio here signals a bug and loss of
196-
* unwritten data.
196+
* unwritten data - on ordinary filesystems.
197197
*
198-
* This fixes dirty accounting after removing the folio entirely
198+
* But it's harmless on in-memory filesystems like tmpfs; and can
199+
* occur when a driver which did get_user_pages() sets page dirty
200+
* before putting it, while the inode is being finally evicted.
201+
*
202+
* Below fixes dirty accounting after removing the folio entirely
199203
* but leaves the dirty flag set: it has no effect for truncated
200204
* folio and anyway will be cleared before returning folio to
201205
* buddy allocator.
202206
*/
203-
if (WARN_ON_ONCE(folio_test_dirty(folio)))
204-
folio_account_cleaned(folio, mapping,
205-
inode_to_wb(mapping->host));
207+
if (WARN_ON_ONCE(folio_test_dirty(folio) &&
208+
mapping_can_writeback(mapping)))
209+
folio_account_cleaned(folio, inode_to_wb(mapping->host));
206210
}
207211

208212
/*

mm/page-writeback.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2465,16 +2465,14 @@ static void folio_account_dirtied(struct folio *folio,
24652465
*
24662466
* Caller must hold lock_page_memcg().
24672467
*/
2468-
void folio_account_cleaned(struct folio *folio, struct address_space *mapping,
2469-
struct bdi_writeback *wb)
2468+
void folio_account_cleaned(struct folio *folio, struct bdi_writeback *wb)
24702469
{
2471-
if (mapping_can_writeback(mapping)) {
2472-
long nr = folio_nr_pages(folio);
2473-
lruvec_stat_mod_folio(folio, NR_FILE_DIRTY, -nr);
2474-
zone_stat_mod_folio(folio, NR_ZONE_WRITE_PENDING, -nr);
2475-
wb_stat_mod(wb, WB_RECLAIMABLE, -nr);
2476-
task_io_account_cancelled_write(nr * PAGE_SIZE);
2477-
}
2470+
long nr = folio_nr_pages(folio);
2471+
2472+
lruvec_stat_mod_folio(folio, NR_FILE_DIRTY, -nr);
2473+
zone_stat_mod_folio(folio, NR_ZONE_WRITE_PENDING, -nr);
2474+
wb_stat_mod(wb, WB_RECLAIMABLE, -nr);
2475+
task_io_account_cancelled_write(nr * PAGE_SIZE);
24782476
}
24792477

24802478
/*
@@ -2683,7 +2681,7 @@ void __folio_cancel_dirty(struct folio *folio)
26832681
wb = unlocked_inode_to_wb_begin(inode, &cookie);
26842682

26852683
if (folio_test_clear_dirty(folio))
2686-
folio_account_cleaned(folio, mapping, wb);
2684+
folio_account_cleaned(folio, wb);
26872685

26882686
unlocked_inode_to_wb_end(inode, &cookie);
26892687
folio_memcg_unlock(folio);

0 commit comments

Comments
 (0)