[PATCH 7/7] Remove folio_launder()
"Matthew Wilcox (Oracle)" <[email protected]>
| Newsgroups | org.kernel.vger.linux-block,dev.linux.lists.fuse-devel,org.kernel.vger.linux-btrfs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-nfs,org.kvack.linux-mm |
|---|---|
| Message-ID | <[email protected]> |
When we do direct I/O, we need to evict any page cache that overlaps the range in the file. First we write back any dirty folios in the range, then we lock each folio and remove it from the CPU page tables. This leaves a wide window for userspace to re-dirty the folio by storing to a shared writable mmap. Many filesystems respond to this situation by failing the call to release_folio(), but some try to writeback the dirty folio again, formerly in their release_folio() method and now in their launder_folio() method. Remove this inconsistency between filesystems by checking whether the folio is dirty in the VFS and failing the call to folio_unmap_invalidate(). Since we hold the folio locked and unmapped at this time, there is no way to dirty the folio after this point. Signed-off-by: Matthew Wilcox (Oracle) <[email protected]> --- Documentation/filesystems/locking.rst | 8 -------- Documentation/filesystems/vfs.rst | 6 ------ include/linux/fs.h | 1 - mm/truncate.c | 15 ++------------- 4 files changed, 2 insertions(+), 28 deletions(-) diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index 08d01bc62c31..fd11f5c5d91e 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -261,7 +261,6 @@ prototypes:: int (*direct_IO)(struct kiocb *, struct iov_iter *iter); int (*migrate_folio)(struct address_space *, struct folio *dst, struct folio *src, enum migrate_mode); - int (*launder_folio)(struct folio *); bool (*is_partially_uptodate)(struct folio *, size_t from, size_t count); int (*error_remove_folio)(struct address_space *, struct folio *); int (*swap_activate)(struct swap_info_struct *sis, struct file *f, sector_t *span) @@ -286,7 +285,6 @@ release_folio: yes free_folio: yes direct_IO: migrate_folio: yes (both) -launder_folio: yes is_partially_uptodate: yes error_remove_folio: yes swap_activate: no @@ -344,12 +342,6 @@ try_to_free_buffers(). ->free_folio() is called when the kernel has dropped the folio from the page cache. -->launder_folio() may be called prior to releasing a folio if -it is still found to be dirty. It returns zero if the folio was successfully -cleaned, or an error value if not. Note that in order to prevent the folio -getting mapped back in and redirtied, it needs to be kept locked -across the entire operation. - ->swap_activate() will be called to prepare the given file for swap. It should perform any validation and preparation necessary to ensure that writes can be performed with minimal memory allocation. It should call diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index 7c753148af88..bff64713bd09 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -768,7 +768,6 @@ cache in your filesystem. The following members are defined: ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter); int (*migrate_folio)(struct mapping *, struct folio *dst, struct folio *src, enum migrate_mode); - int (*launder_folio) (struct folio *); bool (*is_partially_uptodate) (struct folio *, size_t from, size_t count); @@ -942,11 +941,6 @@ cache in your filesystem. The following members are defined: folio to this function. migrate_folio should transfer any private data across and update any references that it has to the folio. -``launder_folio`` - Called before freeing a folio - it writes back the dirty folio. - To prevent redirtying the folio, it is kept locked during the - whole operation. - ``is_partially_uptodate`` Called by the VM when reading a file through the pagecache when the underlying blocksize is smaller than the size of the folio. diff --git a/include/linux/fs.h b/include/linux/fs.h index 50ce731a2b78..e0f4f518fe24 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -428,7 +428,6 @@ struct address_space_operations { */ int (*migrate_folio)(struct address_space *, struct folio *dst, struct folio *src, enum migrate_mode); - int (*launder_folio)(struct folio *); bool (*is_partially_uptodate) (struct folio *, size_t from, size_t count); void (*is_dirty_writeback) (struct folio *, bool *dirty, bool *wb); diff --git a/mm/truncate.c b/mm/truncate.c index b58ba940be47..7f7d65fa926a 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -603,15 +603,6 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping, } EXPORT_SYMBOL(invalidate_mapping_pages); -static int folio_launder(struct address_space *mapping, struct folio *folio) -{ - if (!folio_test_dirty(folio)) - return 0; - if (folio->mapping != mapping || mapping->a_ops->launder_folio == NULL) - return 0; - return mapping->a_ops->launder_folio(folio); -} - /* * This is like mapping_evict_folio(), except it ignores the folio's * refcount. We do this because invalidate_inode_pages2() needs stronger @@ -623,7 +614,6 @@ int folio_unmap_invalidate(struct address_space *mapping, struct folio *folio, gfp_t gfp) { void (*free_folio)(struct folio *); - int ret; VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio); @@ -631,9 +621,8 @@ int folio_unmap_invalidate(struct address_space *mapping, struct folio *folio, unmap_mapping_folio(folio); BUG_ON(folio_mapped(folio)); - ret = folio_launder(mapping, folio); - if (ret) - return ret; + if (folio_test_dirty(folio)) + return -EBUSY; if (folio->mapping != mapping) return -EBUSY; if (!filemap_release_folio(folio, gfp)) -- 2.47.3