mm: Account dirty folios properly during splits
If the last folio in a file is split as a result of truncation, we simply clear the dirty bits for the pages we're discarding. That causes NR_FILE_DIRTY (among other counters) to be thrown off and eventually Linux will hang in balance_dirty_pages_ratelimited() Reported-by: Dave Chinner <dchinner@redhat.com> Tested-by: Dave Chinner <dchinner@redhat.com> Tested-by: Darrick J. Wong <djwong@kernel.org> Fixes: d68eccad3706 ("mm/filemap: Allow large folios to be added to the page cache") Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
This commit is contained in:
parent
0840a7914c
commit
fb5c2029f8
@ -18,6 +18,7 @@
|
|||||||
#include <linux/shrinker.h>
|
#include <linux/shrinker.h>
|
||||||
#include <linux/mm_inline.h>
|
#include <linux/mm_inline.h>
|
||||||
#include <linux/swapops.h>
|
#include <linux/swapops.h>
|
||||||
|
#include <linux/backing-dev.h>
|
||||||
#include <linux/dax.h>
|
#include <linux/dax.h>
|
||||||
#include <linux/khugepaged.h>
|
#include <linux/khugepaged.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
@ -2440,11 +2441,15 @@ static void __split_huge_page(struct page *page, struct list_head *list,
|
|||||||
__split_huge_page_tail(head, i, lruvec, list);
|
__split_huge_page_tail(head, i, lruvec, list);
|
||||||
/* Some pages can be beyond EOF: drop them from page cache */
|
/* Some pages can be beyond EOF: drop them from page cache */
|
||||||
if (head[i].index >= end) {
|
if (head[i].index >= end) {
|
||||||
ClearPageDirty(head + i);
|
struct folio *tail = page_folio(head + i);
|
||||||
__delete_from_page_cache(head + i, NULL);
|
|
||||||
if (shmem_mapping(head->mapping))
|
if (shmem_mapping(head->mapping))
|
||||||
shmem_uncharge(head->mapping->host, 1);
|
shmem_uncharge(head->mapping->host, 1);
|
||||||
put_page(head + i);
|
else if (folio_test_clear_dirty(tail))
|
||||||
|
folio_account_cleaned(tail,
|
||||||
|
inode_to_wb(folio->mapping->host));
|
||||||
|
__filemap_remove_folio(tail, NULL);
|
||||||
|
folio_put(tail);
|
||||||
} else if (!PageAnon(page)) {
|
} else if (!PageAnon(page)) {
|
||||||
__xa_store(&head->mapping->i_pages, head[i].index,
|
__xa_store(&head->mapping->i_pages, head[i].index,
|
||||||
head + i, 0);
|
head + i, 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user