@@ -221,7 +221,7 @@ static int v9fs_launder_folio(struct folio *folio)
{
int retval;
- if (folio_clear_dirty_for_io(folio)) {
+ if (folio_clear_dirty_for_io(NULL, folio)) {
retval = v9fs_vfs_write_folio_locked(folio);
if (retval)
return retval;
@@ -453,7 +453,7 @@ static void afs_invalidate_dirty(struct folio *folio, size_t offset,
undirty:
trace_afs_folio_dirty(vnode, tracepoint_string("undirty"), folio);
- folio_clear_dirty_for_io(folio);
+ folio_clear_dirty_for_io(NULL, folio);
full_invalidate:
trace_afs_folio_dirty(vnode, tracepoint_string("inval"), folio);
folio_detach_private(folio);
@@ -555,7 +555,7 @@ static void afs_extend_writeback(struct address_space *mapping,
folio = page_folio(pvec.pages[i]);
trace_afs_folio_dirty(vnode, tracepoint_string("store+"), folio);
- if (!folio_clear_dirty_for_io(folio))
+ if (!folio_clear_dirty_for_io(NULL, folio))
BUG();
if (folio_start_writeback(folio))
BUG();
@@ -769,7 +769,7 @@ static int afs_writepages_region(struct address_space *mapping,
continue;
}
- if (!folio_clear_dirty_for_io(folio))
+ if (!folio_clear_dirty_for_io(NULL, folio))
BUG();
ret = afs_write_back_from_locked_folio(mapping, wbc, folio, start, end);
folio_put(folio);
@@ -1000,7 +1000,7 @@ int afs_launder_folio(struct folio *folio)
_enter("{%lx}", folio->index);
priv = (unsigned long)folio_get_private(folio);
- if (folio_clear_dirty_for_io(folio)) {
+ if (folio_clear_dirty_for_io(NULL, folio)) {
f = 0;
t = folio_size(folio);
if (folio_test_private(folio)) {
@@ -215,7 +215,7 @@ void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end)
while (index <= end_index) {
page = find_get_page(inode->i_mapping, index);
BUG_ON(!page); /* Pages should be in the extent_io_tree */
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
put_page(page);
index++;
}
@@ -2590,7 +2590,7 @@ static int write_one_subpage_eb(struct extent_buffer *eb,
no_dirty_ebs = btrfs_subpage_clear_and_test_dirty(fs_info, page,
eb->start, eb->len);
if (no_dirty_ebs)
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
bio_ctrl->end_io_func = end_bio_subpage_eb_writepage;
@@ -2633,7 +2633,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
for (i = 0; i < num_pages; i++) {
struct page *p = eb->pages[i];
- clear_page_dirty_for_io(p);
+ clear_page_dirty_for_io(NULL, p);
set_page_writeback(p);
ret = submit_extent_page(REQ_OP_WRITE | write_flags, wbc,
bio_ctrl, disk_bytenr, p,
@@ -2655,7 +2655,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
if (unlikely(ret)) {
for (; i < num_pages; i++) {
struct page *p = eb->pages[i];
- clear_page_dirty_for_io(p);
+ clear_page_dirty_for_io(NULL, p);
unlock_page(p);
}
}
@@ -3083,7 +3083,7 @@ static int extent_write_cache_pages(struct address_space *mapping,
}
if (PageWriteback(page) ||
- !clear_page_dirty_for_io(page)) {
+ !clear_page_dirty_for_io(wbc, page)) {
unlock_page(page);
continue;
}
@@ -3174,7 +3174,7 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end)
*/
ASSERT(PageLocked(page));
ASSERT(PageDirty(page));
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
ret = __extent_writepage(page, &wbc_writepages, &bio_ctrl);
ASSERT(ret <= 0);
if (ret < 0) {
@@ -4698,7 +4698,7 @@ static void btree_clear_page_dirty(struct page *page)
{
ASSERT(PageDirty(page));
ASSERT(PageLocked(page));
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
xa_lock_irq(&page->mapping->i_pages);
if (!PageDirty(page))
__xa_clear_mark(&page->mapping->i_pages,
@@ -507,7 +507,7 @@ static int io_ctl_prepare_pages(struct btrfs_io_ctl *io_ctl, bool uptodate)
}
for (i = 0; i < io_ctl->num_pages; i++)
- clear_page_dirty_for_io(io_ctl->pages[i]);
+ clear_page_dirty_for_io(NULL, io_ctl->pages[i]);
return 0;
}
@@ -3002,7 +3002,7 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
*/
mapping_set_error(page->mapping, ret);
end_extent_writepage(page, ret, page_start, page_end);
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
SetPageError(page);
}
btrfs_page_clear_checked(inode->root->fs_info, page, page_start, PAGE_SIZE);
@@ -515,7 +515,7 @@ void btrfs_subpage_clear_dirty(const struct btrfs_fs_info *fs_info,
last = btrfs_subpage_clear_and_test_dirty(fs_info, page, start, len);
if (last)
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
}
void btrfs_subpage_set_writeback(const struct btrfs_fs_info *fs_info,
@@ -926,7 +926,7 @@ static int ceph_writepages_start(struct address_space *mapping,
folio->index, ceph_wbc.i_size);
if ((ceph_wbc.size_stable ||
folio_pos(folio) >= i_size_read(inode)) &&
- folio_clear_dirty_for_io(folio))
+ folio_clear_dirty_for_io(wbc, folio))
folio_invalidate(folio, 0,
folio_size(folio));
folio_unlock(folio);
@@ -948,7 +948,7 @@ static int ceph_writepages_start(struct address_space *mapping,
wait_on_page_fscache(page);
}
- if (!clear_page_dirty_for_io(page)) {
+ if (!clear_page_dirty_for_io(wbc, page)) {
dout("%p !clear_page_dirty_for_io\n", page);
unlock_page(page);
continue;
@@ -1282,7 +1282,7 @@ ceph_find_incompatible(struct page *page)
/* yay, writeable, do it now (without dropping page lock) */
dout(" page %p snapc %p not current, but oldest\n", page, snapc);
- if (clear_page_dirty_for_io(page)) {
+ if (clear_page_dirty_for_io(NULL, page)) {
int r = writepage_nounlock(page, NULL);
if (r < 0)
return ERR_PTR(r);
@@ -2342,7 +2342,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
for (j = 0; j < nr_pages; j++) {
wdata2->pages[j] = wdata->pages[i + j];
lock_page(wdata2->pages[j]);
- clear_page_dirty_for_io(wdata2->pages[j]);
+ clear_page_dirty_for_io(NULL, wdata2->pages[j]);
}
wdata2->sync_mode = wdata->sync_mode;
@@ -2582,7 +2582,7 @@ wdata_prepare_pages(struct cifs_writedata *wdata, unsigned int found_pages,
wait_on_page_writeback(page);
if (PageWriteback(page) ||
- !clear_page_dirty_for_io(page)) {
+ !clear_page_dirty_for_io(wbc, page)) {
unlock_page(page);
break;
}
@@ -5076,7 +5076,7 @@ static int cifs_launder_folio(struct folio *folio)
cifs_dbg(FYI, "Launder page: %lu\n", folio->index);
- if (folio_clear_dirty_for_io(folio))
+ if (folio_clear_dirty_for_io(&wbc, folio))
rc = cifs_writepage_locked(&folio->page, &wbc);
folio_wait_fscache(folio);
@@ -1616,7 +1616,7 @@ static void mpage_release_unused_pages(struct mpage_da_data *mpd,
BUG_ON(folio_test_writeback(folio));
if (invalidate) {
if (folio_mapped(folio))
- folio_clear_dirty_for_io(folio);
+ folio_clear_dirty_for_io(NULL, folio);
block_invalidate_folio(folio, 0,
folio_size(folio));
folio_clear_uptodate(folio);
@@ -2106,7 +2106,7 @@ static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page)
int err;
BUG_ON(page->index != mpd->first_page);
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
/*
* We have to be very careful here! Nothing protects writeback path
* against i_size changes and the page can be writeably mapped into
@@ -435,7 +435,7 @@ long f2fs_sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
f2fs_wait_on_page_writeback(page, META, true, true);
- if (!clear_page_dirty_for_io(page))
+ if (!clear_page_dirty_for_io(NULL, page))
goto continue_unlock;
if (__f2fs_write_meta_page(page, &wbc, io_type)) {
@@ -1415,7 +1415,7 @@ static void commit_checkpoint(struct f2fs_sb_info *sbi,
memcpy(page_address(page), src, PAGE_SIZE);
set_page_dirty(page);
- if (unlikely(!clear_page_dirty_for_io(page)))
+ if (unlikely(!clear_page_dirty_for_io(NULL, page)))
f2fs_bug_on(sbi, 1);
/* writeout cp pack 2 page */
@@ -1459,7 +1459,7 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
if (!PageDirty(cc->rpages[i]))
goto continue_unlock;
- if (!clear_page_dirty_for_io(cc->rpages[i]))
+ if (!clear_page_dirty_for_io(NULL, cc->rpages[i]))
goto continue_unlock;
ret = f2fs_write_single_data_page(cc->rpages[i], &_submitted,
@@ -3102,7 +3102,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
goto continue_unlock;
}
- if (!clear_page_dirty_for_io(page))
+ if (!clear_page_dirty_for_io(NULL, page))
goto continue_unlock;
#ifdef CONFIG_F2FS_FS_COMPRESSION
@@ -938,7 +938,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
if (bit_pos == NR_DENTRY_IN_BLOCK &&
!f2fs_truncate_hole(dir, page->index, page->index + 1)) {
f2fs_clear_page_cache_dirty_tag(page);
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
ClearPageUptodate(page);
clear_page_private_gcing(page);
@@ -1361,7 +1361,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
f2fs_invalidate_compress_page(fio.sbi, fio.old_blkaddr);
set_page_dirty(fio.encrypted_page);
- if (clear_page_dirty_for_io(fio.encrypted_page))
+ if (clear_page_dirty_for_io(NULL, fio.encrypted_page))
dec_page_count(fio.sbi, F2FS_DIRTY_META);
set_page_writeback(fio.encrypted_page);
@@ -1446,7 +1446,7 @@ static int move_data_page(struct inode *inode, block_t bidx, int gc_type,
f2fs_wait_on_page_writeback(page, DATA, true, true);
set_page_dirty(page);
- if (clear_page_dirty_for_io(page)) {
+ if (clear_page_dirty_for_io(NULL, page)) {
inode_dec_dirty_pages(inode);
f2fs_remove_dirty_inode(inode);
}
@@ -170,7 +170,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
set_page_dirty(page);
/* clear dirty state */
- dirty = clear_page_dirty_for_io(page);
+ dirty = clear_page_dirty_for_io(NULL, page);
/* write data page to try to make data consistent */
set_page_writeback(page);
@@ -124,7 +124,7 @@ static void clear_node_page_dirty(struct page *page)
{
if (PageDirty(page)) {
f2fs_clear_page_cache_dirty_tag(page);
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
dec_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES);
}
ClearPageUptodate(page);
@@ -1501,7 +1501,7 @@ static void flush_inline_data(struct f2fs_sb_info *sbi, nid_t ino)
if (!PageDirty(page))
goto page_out;
- if (!clear_page_dirty_for_io(page))
+ if (!clear_page_dirty_for_io(NULL, page))
goto page_out;
ret = f2fs_write_inline_data(inode, page);
@@ -1696,7 +1696,7 @@ int f2fs_move_node_page(struct page *node_page, int gc_type)
set_page_dirty(node_page);
- if (!clear_page_dirty_for_io(node_page)) {
+ if (!clear_page_dirty_for_io(NULL, node_page)) {
err = -EAGAIN;
goto out_page;
}
@@ -1803,7 +1803,7 @@ int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
set_page_dirty(page);
}
- if (!clear_page_dirty_for_io(page))
+ if (!clear_page_dirty_for_io(NULL, page))
goto continue_unlock;
ret = __write_node_page(page, atomic &&
@@ -2011,7 +2011,7 @@ int f2fs_sync_node_pages(struct f2fs_sb_info *sbi,
write_node:
f2fs_wait_on_page_writeback(page, NODE, true, true);
- if (!clear_page_dirty_for_io(page))
+ if (!clear_page_dirty_for_io(NULL, page))
goto continue_unlock;
set_fsync_mark(page, 0);
@@ -2399,7 +2399,7 @@ static int fuse_write_end(struct file *file, struct address_space *mapping,
static int fuse_launder_folio(struct folio *folio)
{
int err = 0;
- if (folio_clear_dirty_for_io(folio)) {
+ if (folio_clear_dirty_for_io(NULL, folio)) {
struct inode *inode = folio->mapping->host;
/* Serialize with pending writeback for the same page */
@@ -247,7 +247,7 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping,
}
BUG_ON(PageWriteback(page));
- if (!clear_page_dirty_for_io(page))
+ if (!clear_page_dirty_for_io(wbc, page))
goto continue_unlock;
trace_wbc_writepage(wbc, inode_to_bdi(inode));
@@ -2089,7 +2089,7 @@ int nfs_wb_page(struct inode *inode, struct page *page)
for (;;) {
wait_on_page_writeback(page);
- if (clear_page_dirty_for_io(page)) {
+ if (clear_page_dirty_for_io(&wbc, page)) {
ret = nfs_writepage_locked(page, &wbc);
if (ret < 0)
goto out_error;
@@ -456,7 +456,7 @@ int __nilfs_clear_page_dirty(struct page *page)
__xa_clear_mark(&mapping->i_pages, page_index(page),
PAGECACHE_TAG_DIRTY);
xa_unlock_irq(&mapping->i_pages);
- return clear_page_dirty_for_io(page);
+ return clear_page_dirty_for_io(NULL, page);
}
xa_unlock_irq(&mapping->i_pages);
return 0;
@@ -1644,7 +1644,7 @@ static void nilfs_begin_page_io(struct page *page)
return;
lock_page(page);
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
set_page_writeback(page);
unlock_page(page);
}
@@ -1662,7 +1662,7 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci)
if (bh->b_page != bd_page) {
if (bd_page) {
lock_page(bd_page);
- clear_page_dirty_for_io(bd_page);
+ clear_page_dirty_for_io(NULL, bd_page);
set_page_writeback(bd_page);
unlock_page(bd_page);
}
@@ -1676,7 +1676,7 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci)
if (bh == segbuf->sb_super_root) {
if (bh->b_page != bd_page) {
lock_page(bd_page);
- clear_page_dirty_for_io(bd_page);
+ clear_page_dirty_for_io(NULL, bd_page);
set_page_writeback(bd_page);
unlock_page(bd_page);
bd_page = bh->b_page;
@@ -1691,7 +1691,7 @@ static void nilfs_segctor_prepare_write(struct nilfs_sc_info *sci)
}
if (bd_page) {
lock_page(bd_page);
- clear_page_dirty_for_io(bd_page);
+ clear_page_dirty_for_io(NULL, bd_page);
set_page_writeback(bd_page);
unlock_page(bd_page);
}
@@ -501,7 +501,7 @@ static int orangefs_launder_folio(struct folio *folio)
.nr_to_write = 0,
};
folio_wait_writeback(folio);
- if (folio_clear_dirty_for_io(folio)) {
+ if (folio_clear_dirty_for_io(&wbc, folio)) {
r = orangefs_writepage_locked(&folio->page, &wbc);
folio_end_writeback(folio);
}
@@ -1159,7 +1159,7 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
*/
ubifs_assert(c, PagePrivate(page));
- clear_page_dirty_for_io(page);
+ clear_page_dirty_for_io(NULL, page);
if (UBIFS_BLOCKS_PER_PAGE_SHIFT)
offset = new_size &
(PAGE_SIZE - 1);
@@ -1059,8 +1059,9 @@ static inline void folio_cancel_dirty(struct folio *folio)
if (folio_test_dirty(folio))
__folio_cancel_dirty(folio);
}
-bool folio_clear_dirty_for_io(struct folio *folio);
-bool clear_page_dirty_for_io(struct page *page);
+bool folio_clear_dirty_for_io(struct writeback_control *wbc,
+ struct folio *folio);
+bool clear_page_dirty_for_io(struct writeback_control *wbc, struct page *page);
void folio_invalidate(struct folio *folio, size_t offset, size_t length);
int __must_check folio_write_one(struct folio *folio);
static inline int __must_check write_one_page(struct page *page)
@@ -63,9 +63,9 @@ int __set_page_dirty_nobuffers(struct page *page)
}
EXPORT_SYMBOL(__set_page_dirty_nobuffers);
-bool clear_page_dirty_for_io(struct page *page)
+bool clear_page_dirty_for_io(struct writeback_control *wbc, struct page *page)
{
- return folio_clear_dirty_for_io(page_folio(page));
+ return folio_clear_dirty_for_io(wbc, page_folio(page));
}
EXPORT_SYMBOL(clear_page_dirty_for_io);
@@ -870,7 +870,7 @@ static int writeout(struct address_space *mapping, struct folio *folio)
/* No write method for the address space */
return -EINVAL;
- if (!folio_clear_dirty_for_io(folio))
+ if (!folio_clear_dirty_for_io(&wbc, folio))
/* Someone else already triggered a write */
return -EAGAIN;
@@ -2465,7 +2465,7 @@ int write_cache_pages(struct address_space *mapping,
}
BUG_ON(PageWriteback(page));
- if (!clear_page_dirty_for_io(page))
+ if (!clear_page_dirty_for_io(wbc, page))
goto continue_unlock;
trace_wbc_writepage(wbc, inode_to_bdi(mapping->host));
@@ -2628,7 +2628,7 @@ int folio_write_one(struct folio *folio)
folio_wait_writeback(folio);
- if (folio_clear_dirty_for_io(folio)) {
+ if (folio_clear_dirty_for_io(&wbc, folio)) {
folio_get(folio);
ret = mapping->a_ops->writepage(&folio->page, &wbc);
if (ret == 0)
@@ -2924,7 +2924,7 @@ EXPORT_SYMBOL(__folio_cancel_dirty);
/*
* Clear a folio's dirty flag, while caring for dirty memory accounting.
- * Returns true if the folio was previously dirty.
+ * Returns true if the folio was previously dirty and should be written back.
*
* This is for preparing to put the folio under writeout. We leave
* the folio tagged as dirty in the xarray so that a concurrent
@@ -2935,8 +2935,14 @@ EXPORT_SYMBOL(__folio_cancel_dirty);
*
* This incoherency between the folio's dirty flag and xarray tag is
* unfortunate, but it only exists while the folio is locked.
+ *
+ * If the folio is pinned, its writeback is problematic so we just don't bother
+ * for memory cleaning writeback - this is why writeback control is passed in.
+ * If it is NULL, we assume pinned pages are not expected (e.g. this can be
+ * a metadata page) and warn if the page is actually pinned.
*/
-bool folio_clear_dirty_for_io(struct folio *folio)
+bool folio_clear_dirty_for_io(struct writeback_control *wbc,
+ struct folio *folio)
{
struct address_space *mapping = folio_mapping(folio);
bool ret = false;
@@ -2975,6 +2981,16 @@ bool folio_clear_dirty_for_io(struct folio *folio)
*/
if (folio_mkclean(folio))
folio_mark_dirty(folio);
+ /*
+ * For pinned folios we have no chance to reclaim them anyway
+ * and we cannot be sure folio is ever clean. So memory
+ * cleaning writeback is pointless. Just skip it.
+ */
+ if (wbc && wbc->sync_mode == WB_SYNC_NONE &&
+ folio_maybe_dma_pinned(folio))
+ return false;
+ /* Catch callers not expecting pinned pages */
+ WARN_ON_ONCE(!wbc && folio_maybe_dma_pinned(folio));
/*
* We carefully synchronise fault handlers against
* installing a dirty pte and marking the folio dirty
@@ -1283,7 +1283,7 @@ static pageout_t pageout(struct folio *folio, struct address_space *mapping,
if (mapping->a_ops->writepage == NULL)
return PAGE_ACTIVATE;
- if (folio_clear_dirty_for_io(folio)) {
+ if (folio_clear_dirty_for_io(NULL, folio)) {
int res;
struct writeback_control wbc = {
.sync_mode = WB_SYNC_NONE,
When a folio is pinned, there is no point in trying to write it during memory cleaning writeback. We cannot reclaim the folio until it is unpinned anyway and we cannot even be sure the folio is really clean. On top of that writeback of such folio may be problematic as the data can change while the writeback is running thus causing checksum or DIF/DIX failures. So just don't bother doing memory cleaning writeback for pinned folios. Signed-off-by: Jan Kara <jack@suse.cz> --- fs/9p/vfs_addr.c | 2 +- fs/afs/file.c | 2 +- fs/afs/write.c | 6 +++--- fs/btrfs/extent_io.c | 14 +++++++------- fs/btrfs/free-space-cache.c | 2 +- fs/btrfs/inode.c | 2 +- fs/btrfs/subpage.c | 2 +- fs/ceph/addr.c | 6 +++--- fs/cifs/file.c | 6 +++--- fs/ext4/inode.c | 4 ++-- fs/f2fs/checkpoint.c | 4 ++-- fs/f2fs/compress.c | 2 +- fs/f2fs/data.c | 2 +- fs/f2fs/dir.c | 2 +- fs/f2fs/gc.c | 4 ++-- fs/f2fs/inline.c | 2 +- fs/f2fs/node.c | 10 +++++----- fs/fuse/file.c | 2 +- fs/gfs2/aops.c | 2 +- fs/nfs/write.c | 2 +- fs/nilfs2/page.c | 2 +- fs/nilfs2/segment.c | 8 ++++---- fs/orangefs/inode.c | 2 +- fs/ubifs/file.c | 2 +- include/linux/pagemap.h | 5 +++-- mm/folio-compat.c | 4 ++-- mm/migrate.c | 2 +- mm/page-writeback.c | 24 ++++++++++++++++++++---- mm/vmscan.c | 2 +- 29 files changed, 73 insertions(+), 56 deletions(-)