Patch "mm, netfs, fscache: stop read optimisation when folio removed from pagecache" has been added to the 6.1-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    mm, netfs, fscache: stop read optimisation when folio removed from pagecache

to the 6.1-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     mm-netfs-fscache-stop-read-optimisation-when-folio-r.patch
and it can be found in the queue-6.1 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit ed65a1b09f78fea9d521a21c25bb036dc802af12
Author: David Howells <dhowells@xxxxxxxxxx>
Date:   Wed Jun 28 11:48:52 2023 +0100

    mm, netfs, fscache: stop read optimisation when folio removed from pagecache
    
    [ Upstream commit b4fa966f03b7401ceacd4ffd7227197afb2b8376 ]
    
    Fscache has an optimisation by which reads from the cache are skipped
    until we know that (a) there's data there to be read and (b) that data
    isn't entirely covered by pages resident in the netfs pagecache.  This is
    done with two flags manipulated by fscache_note_page_release():
    
            if (...
                test_bit(FSCACHE_COOKIE_HAVE_DATA, &cookie->flags) &&
                test_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags))
                    clear_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &cookie->flags);
    
    where the NO_DATA_TO_READ flag causes cachefiles_prepare_read() to
    indicate that netfslib should download from the server or clear the page
    instead.
    
    The fscache_note_page_release() function is intended to be called from
    ->releasepage() - but that only gets called if PG_private or PG_private_2
    is set - and currently the former is at the discretion of the network
    filesystem and the latter is only set whilst a page is being written to
    the cache, so sometimes we miss clearing the optimisation.
    
    Fix this by following Willy's suggestion[1] and adding an address_space
    flag, AS_RELEASE_ALWAYS, that causes filemap_release_folio() to always call
    ->release_folio() if it's set, even if PG_private or PG_private_2 aren't
    set.
    
    Note that this would require folio_test_private() and page_has_private() to
    become more complicated.  To avoid that, in the places[*] where these are
    used to conditionalise calls to filemap_release_folio() and
    try_to_release_page(), the tests are removed the those functions just
    jumped to unconditionally and the test is performed there.
    
    [*] There are some exceptions in vmscan.c where the check guards more than
    just a call to the releaser.  I've added a function, folio_needs_release()
    to wrap all the checks for that.
    
    AS_RELEASE_ALWAYS should be set if a non-NULL cookie is obtained from
    fscache and cleared in ->evict_inode() before truncate_inode_pages_final()
    is called.
    
    Additionally, the FSCACHE_COOKIE_NO_DATA_TO_READ flag needs to be cleared
    and the optimisation cancelled if a cachefiles object already contains data
    when we open it.
    
    [dwysocha@xxxxxxxxxx: call folio_mapping() inside folio_needs_release()]
      Link: https://github.com/DaveWysochanskiRH/kernel/commit/902c990e311120179fa5de99d68364b2947b79ec
    Link: https://lkml.kernel.org/r/20230628104852.3391651-3-dhowells@xxxxxxxxxx
    Fixes: 1f67e6d0b188 ("fscache: Provide a function to note the release of a page")
    Fixes: 047487c947e8 ("cachefiles: Implement the I/O routines")
    Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
    Signed-off-by: Dave Wysochanski <dwysocha@xxxxxxxxxx>
    Reported-by: Rohith Surabattula <rohiths.msft@xxxxxxxxx>
    Suggested-by: Matthew Wilcox <willy@xxxxxxxxxxxxx>
    Tested-by: SeongJae Park <sj@xxxxxxxxxx>
    Cc: Daire Byrne <daire.byrne@xxxxxxxxx>
    Cc: Matthew Wilcox <willy@xxxxxxxxxxxxx>
    Cc: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
    Cc: Steve French <sfrench@xxxxxxxxx>
    Cc: Shyam Prasad N <nspmangalore@xxxxxxxxx>
    Cc: Rohith Surabattula <rohiths.msft@xxxxxxxxx>
    Cc: Dave Wysochanski <dwysocha@xxxxxxxxxx>
    Cc: Dominique Martinet <asmadeus@xxxxxxxxxxxxx>
    Cc: Ilya Dryomov <idryomov@xxxxxxxxx>
    Cc: Andreas Dilger <adilger.kernel@xxxxxxxxx>
    Cc: Jingbo Xu <jefflexu@xxxxxxxxxxxxxxxxx>
    Cc: "Theodore Ts'o" <tytso@xxxxxxx>
    Cc: Xiubo Li <xiubli@xxxxxxxxxx>
    Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
    Stable-dep-of: 1898efcdbed3 ("block: update the stable_writes flag in bdev_add")
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/9p/cache.c b/fs/9p/cache.c
index cebba4eaa0b57..12c0ae29f1857 100644
--- a/fs/9p/cache.c
+++ b/fs/9p/cache.c
@@ -68,6 +68,8 @@ void v9fs_cache_inode_get_cookie(struct inode *inode)
 				       &path, sizeof(path),
 				       &version, sizeof(version),
 				       i_size_read(&v9inode->netfs.inode));
+	if (v9inode->netfs.cache)
+		mapping_set_release_always(inode->i_mapping);
 
 	p9_debug(P9_DEBUG_FSC, "inode %p get cookie %p\n",
 		 inode, v9fs_inode_cookie(v9inode));
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index fcbb598d8c85d..a25fdc3e52310 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -682,6 +682,8 @@ static inline void afs_vnode_set_cache(struct afs_vnode *vnode,
 {
 #ifdef CONFIG_AFS_FSCACHE
 	vnode->netfs.cache = cookie;
+	if (cookie)
+		mapping_set_release_always(vnode->netfs.inode.i_mapping);
 #endif
 }
 
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index 03ca8f2f657ab..50b2ee163af60 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -584,6 +584,8 @@ static bool cachefiles_open_file(struct cachefiles_object *object,
 	if (ret < 0)
 		goto check_failed;
 
+	clear_bit(FSCACHE_COOKIE_NO_DATA_TO_READ, &object->cookie->flags);
+
 	object->file = file;
 
 	/* Always update the atime on an object we've just looked up (this is
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c
index 177d8e8d73fe4..de1dee46d3df7 100644
--- a/fs/ceph/cache.c
+++ b/fs/ceph/cache.c
@@ -36,6 +36,8 @@ void ceph_fscache_register_inode_cookie(struct inode *inode)
 				       &ci->i_vino, sizeof(ci->i_vino),
 				       &ci->i_version, sizeof(ci->i_version),
 				       i_size_read(inode));
+	if (ci->netfs.cache)
+		mapping_set_release_always(inode->i_mapping);
 }
 
 void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info *ci)
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index e731c00a9fcbc..d3c938dd2b12a 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -176,6 +176,9 @@ void nfs_fscache_init_inode(struct inode *inode)
 					       &auxdata,      /* aux_data */
 					       sizeof(auxdata),
 					       i_size_read(inode));
+
+	if (netfs_inode(inode)->cache)
+		mapping_set_release_always(inode->i_mapping);
 }
 
 /*
diff --git a/fs/smb/client/fscache.c b/fs/smb/client/fscache.c
index e73625b5d0cc6..f64bad513ba6d 100644
--- a/fs/smb/client/fscache.c
+++ b/fs/smb/client/fscache.c
@@ -108,6 +108,8 @@ void cifs_fscache_get_inode_cookie(struct inode *inode)
 				       &cifsi->uniqueid, sizeof(cifsi->uniqueid),
 				       &cd, sizeof(cd),
 				       i_size_read(&cifsi->netfs.inode));
+	if (cifsi->netfs.cache)
+		mapping_set_release_always(inode->i_mapping);
 }
 
 void cifs_fscache_unuse_inode_cookie(struct inode *inode, bool update)
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 03307b72de6c6..fdbb90ae56c70 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -199,6 +199,7 @@ enum mapping_flags {
 	/* writeback related tags are not used */
 	AS_NO_WRITEBACK_TAGS = 5,
 	AS_LARGE_FOLIO_SUPPORT = 6,
+	AS_RELEASE_ALWAYS,	/* Call ->release_folio(), even if no private data */
 };
 
 /**
@@ -269,6 +270,21 @@ static inline int mapping_use_writeback_tags(struct address_space *mapping)
 	return !test_bit(AS_NO_WRITEBACK_TAGS, &mapping->flags);
 }
 
+static inline bool mapping_release_always(const struct address_space *mapping)
+{
+	return test_bit(AS_RELEASE_ALWAYS, &mapping->flags);
+}
+
+static inline void mapping_set_release_always(struct address_space *mapping)
+{
+	set_bit(AS_RELEASE_ALWAYS, &mapping->flags);
+}
+
+static inline void mapping_clear_release_always(struct address_space *mapping)
+{
+	clear_bit(AS_RELEASE_ALWAYS, &mapping->flags);
+}
+
 static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
 {
 	return mapping->gfp_mask;
diff --git a/mm/internal.h b/mm/internal.h
index 1fefb5181ab78..d01130efce5fb 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -168,7 +168,10 @@ static inline void set_page_refcounted(struct page *page)
  */
 static inline bool folio_needs_release(struct folio *folio)
 {
-	return folio_has_private(folio);
+	struct address_space *mapping = folio_mapping(folio);
+
+	return folio_has_private(folio) ||
+		(mapping && mapping_release_always(mapping));
 }
 
 extern unsigned long highest_memmap_pfn;




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux