fs: Add invalidate_folio() aops method
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Wed, 9 Feb 2022 20:21:32 +0000 (20:21 +0000)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Tue, 15 Mar 2022 12:23:29 +0000 (08:23 -0400)
This is used in preference to invalidatepage, if defined.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Tested-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Acked-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Tested-by: Mike Marshall <hubcap@omnibond.com> # orangefs
Tested-by: David Howells <dhowells@redhat.com> # afs
Documentation/filesystems/locking.rst
Documentation/filesystems/vfs.rst
include/linux/fs.h
mm/truncate.c

index 88b3352..29a045f 100644 (file)
@@ -250,6 +250,7 @@ prototypes::
                                loff_t pos, unsigned len, unsigned copied,
                                struct page *page, void *fsdata);
        sector_t (*bmap)(struct address_space *, sector_t);
+       void (*invalidate_folio) (struct folio *, size_t start, size_t len);
        void (*invalidatepage) (struct page *, unsigned int, unsigned int);
        int (*releasepage) (struct page *, int);
        void (*freepage)(struct page *);
@@ -278,6 +279,7 @@ readpages:          no                                      shared
 write_begin:           locks the page           exclusive
 write_end:             yes, unlocks             exclusive
 bmap:
+invalidate_folio:      yes                                     exclusive
 invalidatepage:                yes                                     exclusive
 releasepage:           yes
 freepage:              yes
@@ -370,13 +372,12 @@ not locked.
 filesystems and by the swapper. The latter will eventually go away.  Please,
 keep it that way and don't breed new callers.
 
-->invalidatepage() is called when the filesystem must attempt to drop
+->invalidate_folio() is called when the filesystem must attempt to drop
 some or all of the buffers from the page when it is being truncated. It
-returns zero on success. If ->invalidatepage is zero, the kernel uses
-block_invalidatepage() instead. The filesystem must exclusively acquire
-invalidate_lock before invalidating page cache in truncate / hole punch path
-(and thus calling into ->invalidatepage) to block races between page cache
-invalidation and page cache filling functions (fault, read, ...).
+returns zero on success.  The filesystem must exclusively acquire
+invalidate_lock before invalidating page cache in truncate / hole punch
+path (and thus calling into ->invalidate_folio) to block races between page
+cache invalidation and page cache filling functions (fault, read, ...).
 
 ->releasepage() is called when the kernel is about to try to drop the
 buffers from the page in preparation for freeing it.  It returns zero to
index da3e7b4..26c090c 100644 (file)
@@ -735,6 +735,7 @@ cache in your filesystem.  The following members are defined:
                                 loff_t pos, unsigned len, unsigned copied,
                                 struct page *page, void *fsdata);
                sector_t (*bmap)(struct address_space *, sector_t);
+               void (*invalidate_folio) (struct folio *, size_t start, size_t len);
                void (*invalidatepage) (struct page *, unsigned int, unsigned int);
                int (*releasepage) (struct page *, int);
                void (*freepage)(struct page *);
@@ -868,15 +869,15 @@ cache in your filesystem.  The following members are defined:
        to find out where the blocks in the file are and uses those
        addresses directly.
 
-``invalidatepage``
-       If a page has PagePrivate set, then invalidatepage will be
-       called when part or all of the page is to be removed from the
+``invalidate_folio``
+       If a folio has private data, then invalidate_folio will be
+       called when part or all of the folio is to be removed from the
        address space.  This generally corresponds to either a
        truncation, punch hole or a complete invalidation of the address
        space (in the latter case 'offset' will always be 0 and 'length'
-       will be PAGE_SIZE).  Any private data associated with the page
+       will be folio_size()).  Any private data associated with the page
        should be updated to reflect this truncation.  If offset is 0
-       and length is PAGE_SIZE, then the private data should be
+       and length is folio_size(), then the private data should be
        released, because the page must be able to be completely
        discarded.  This may be done by calling the ->releasepage
        function, but in this case the release MUST succeed.
index 5939e66..bcdb613 100644 (file)
@@ -387,6 +387,7 @@ struct address_space_operations {
 
        /* Unfortunately this kludge is needed for FIBMAP. Don't use it */
        sector_t (*bmap)(struct address_space *, sector_t);
+       void (*invalidate_folio) (struct folio *, size_t offset, size_t len);
        void (*invalidatepage) (struct page *, unsigned int, unsigned int);
        int (*releasepage) (struct page *, gfp_t);
        void (*freepage)(struct page *);
index aa0ed37..b9ad298 100644 (file)
@@ -154,9 +154,15 @@ static int invalidate_exceptional_entry2(struct address_space *mapping,
  */
 void folio_invalidate(struct folio *folio, size_t offset, size_t length)
 {
+       const struct address_space_operations *aops = folio->mapping->a_ops;
        void (*invalidatepage)(struct page *, unsigned int, unsigned int);
 
-       invalidatepage = folio->mapping->a_ops->invalidatepage;
+       if (aops->invalidate_folio) {
+               aops->invalidate_folio(folio, offset, length);
+               return;
+       }
+
+       invalidatepage = aops->invalidatepage;
 #ifdef CONFIG_BLOCK
        if (!invalidatepage)
                invalidatepage = block_invalidatepage;