forked from Minki/linux
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/b5a1106c-7226-a5c6-ad41-ad4832cae1f@google.com Signed-off-by: Hugh Dickins <hughd@google.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Jan Kara <jack@suse.de> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
7f7609175f
commit
566d336288
@ -1009,8 +1009,7 @@ static inline void __set_page_dirty(struct page *page,
|
||||
{
|
||||
__folio_mark_dirty(page_folio(page), mapping, warn);
|
||||
}
|
||||
void folio_account_cleaned(struct folio *folio, struct address_space *mapping,
|
||||
struct bdi_writeback *wb);
|
||||
void folio_account_cleaned(struct folio *folio, struct bdi_writeback *wb);
|
||||
void __folio_cancel_dirty(struct folio *folio);
|
||||
static inline void folio_cancel_dirty(struct folio *folio)
|
||||
{
|
||||
|
14
mm/filemap.c
14
mm/filemap.c
@ -193,16 +193,20 @@ static void filemap_unaccount_folio(struct address_space *mapping,
|
||||
/*
|
||||
* At this point folio must be either written or cleaned by
|
||||
* truncate. Dirty folio here signals a bug and loss of
|
||||
* unwritten data.
|
||||
* unwritten data - on ordinary filesystems.
|
||||
*
|
||||
* This fixes dirty accounting after removing the folio entirely
|
||||
* But it's harmless on in-memory filesystems like tmpfs; and can
|
||||
* occur when a driver which did get_user_pages() sets page dirty
|
||||
* before putting it, while the inode is being finally evicted.
|
||||
*
|
||||
* Below fixes dirty accounting after removing the folio entirely
|
||||
* but leaves the dirty flag set: it has no effect for truncated
|
||||
* folio and anyway will be cleared before returning folio to
|
||||
* buddy allocator.
|
||||
*/
|
||||
if (WARN_ON_ONCE(folio_test_dirty(folio)))
|
||||
folio_account_cleaned(folio, mapping,
|
||||
inode_to_wb(mapping->host));
|
||||
if (WARN_ON_ONCE(folio_test_dirty(folio) &&
|
||||
mapping_can_writeback(mapping)))
|
||||
folio_account_cleaned(folio, inode_to_wb(mapping->host));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2465,16 +2465,14 @@ static void folio_account_dirtied(struct folio *folio,
|
||||
*
|
||||
* Caller must hold lock_page_memcg().
|
||||
*/
|
||||
void folio_account_cleaned(struct folio *folio, struct address_space *mapping,
|
||||
struct bdi_writeback *wb)
|
||||
void folio_account_cleaned(struct folio *folio, struct bdi_writeback *wb)
|
||||
{
|
||||
if (mapping_can_writeback(mapping)) {
|
||||
long nr = folio_nr_pages(folio);
|
||||
lruvec_stat_mod_folio(folio, NR_FILE_DIRTY, -nr);
|
||||
zone_stat_mod_folio(folio, NR_ZONE_WRITE_PENDING, -nr);
|
||||
wb_stat_mod(wb, WB_RECLAIMABLE, -nr);
|
||||
task_io_account_cancelled_write(nr * PAGE_SIZE);
|
||||
}
|
||||
long nr = folio_nr_pages(folio);
|
||||
|
||||
lruvec_stat_mod_folio(folio, NR_FILE_DIRTY, -nr);
|
||||
zone_stat_mod_folio(folio, NR_ZONE_WRITE_PENDING, -nr);
|
||||
wb_stat_mod(wb, WB_RECLAIMABLE, -nr);
|
||||
task_io_account_cancelled_write(nr * PAGE_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2683,7 +2681,7 @@ void __folio_cancel_dirty(struct folio *folio)
|
||||
wb = unlocked_inode_to_wb_begin(inode, &cookie);
|
||||
|
||||
if (folio_test_clear_dirty(folio))
|
||||
folio_account_cleaned(folio, mapping, wb);
|
||||
folio_account_cleaned(folio, wb);
|
||||
|
||||
unlocked_inode_to_wb_end(inode, &cookie);
|
||||
folio_memcg_unlock(folio);
|
||||
|
Loading…
Reference in New Issue
Block a user