mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
b4fa966f03
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@redhat.com: call folio_mapping() inside folio_needs_release()] Link:902c990e31
Link: https://lkml.kernel.org/r/20230628104852.3391651-3-dhowells@redhat.com Fixes:1f67e6d0b1
("fscache: Provide a function to note the release of a page") Fixes:047487c947
("cachefiles: Implement the I/O routines") Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Dave Wysochanski <dwysocha@redhat.com> Reported-by: Rohith Surabattula <rohiths.msft@gmail.com> Suggested-by: Matthew Wilcox <willy@infradead.org> Tested-by: SeongJae Park <sj@kernel.org> Cc: Daire Byrne <daire.byrne@gmail.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Steve French <sfrench@samba.org> Cc: Shyam Prasad N <nspmangalore@gmail.com> Cc: Rohith Surabattula <rohiths.msft@gmail.com> Cc: Dave Wysochanski <dwysocha@redhat.com> Cc: Dominique Martinet <asmadeus@codewreck.org> Cc: Ilya Dryomov <idryomov@gmail.com> Cc: Andreas Dilger <adilger.kernel@dilger.ca> Cc: Jingbo Xu <jefflexu@linux.alibaba.com> Cc: "Theodore Ts'o" <tytso@mit.edu> Cc: Xiubo Li <xiubli@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
76 lines
1.8 KiB
C
76 lines
1.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* V9FS cache definitions.
|
|
*
|
|
* Copyright (C) 2009 by Abhishek Kulkarni <adkulkar@umail.iu.edu>
|
|
*/
|
|
|
|
#include <linux/jiffies.h>
|
|
#include <linux/file.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/stat.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/fs.h>
|
|
#include <net/9p/9p.h>
|
|
|
|
#include "v9fs.h"
|
|
#include "cache.h"
|
|
|
|
int v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses,
|
|
const char *dev_name)
|
|
{
|
|
struct fscache_volume *vcookie;
|
|
char *name, *p;
|
|
|
|
name = kasprintf(GFP_KERNEL, "9p,%s,%s",
|
|
dev_name, v9ses->cachetag ?: v9ses->aname);
|
|
if (!name)
|
|
return -ENOMEM;
|
|
|
|
for (p = name; *p; p++)
|
|
if (*p == '/')
|
|
*p = ';';
|
|
|
|
vcookie = fscache_acquire_volume(name, NULL, NULL, 0);
|
|
p9_debug(P9_DEBUG_FSC, "session %p get volume %p (%s)\n",
|
|
v9ses, vcookie, name);
|
|
if (IS_ERR(vcookie)) {
|
|
if (vcookie != ERR_PTR(-EBUSY)) {
|
|
kfree(name);
|
|
return PTR_ERR(vcookie);
|
|
}
|
|
pr_err("Cache volume key already in use (%s)\n", name);
|
|
vcookie = NULL;
|
|
}
|
|
v9ses->fscache = vcookie;
|
|
kfree(name);
|
|
return 0;
|
|
}
|
|
|
|
void v9fs_cache_inode_get_cookie(struct inode *inode)
|
|
{
|
|
struct v9fs_inode *v9inode = V9FS_I(inode);
|
|
struct v9fs_session_info *v9ses;
|
|
__le32 version;
|
|
__le64 path;
|
|
|
|
if (!S_ISREG(inode->i_mode))
|
|
return;
|
|
if (WARN_ON(v9fs_inode_cookie(v9inode)))
|
|
return;
|
|
|
|
version = cpu_to_le32(v9inode->qid.version);
|
|
path = cpu_to_le64(v9inode->qid.path);
|
|
v9ses = v9fs_inode2v9ses(inode);
|
|
v9inode->netfs.cache =
|
|
fscache_acquire_cookie(v9fs_session_cache(v9ses),
|
|
0,
|
|
&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));
|
|
}
|