2019-05-28 16:57:16 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2013-08-21 21:29:54 +00:00
|
|
|
/*
|
|
|
|
* Ceph cache definitions.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013 by Adfin Solutions, Inc. All Rights Reserved.
|
|
|
|
* Written by Milosz Tanski (milosz@adfin.com)
|
|
|
|
*/
|
|
|
|
|
2019-09-05 15:29:29 +00:00
|
|
|
#include <linux/ceph/ceph_debug.h>
|
|
|
|
|
2019-03-25 16:38:32 +00:00
|
|
|
#include <linux/fs_context.h>
|
2013-08-21 21:29:54 +00:00
|
|
|
#include "super.h"
|
|
|
|
#include "cache.h"
|
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
void ceph_fscache_register_inode_cookie(struct inode *inode)
|
2013-08-21 21:29:54 +00:00
|
|
|
{
|
2021-12-07 13:44:50 +00:00
|
|
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
2023-06-12 02:50:38 +00:00
|
|
|
struct ceph_fs_client *fsc = ceph_inode_to_fs_client(inode);
|
2017-06-27 03:57:56 +00:00
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
/* No caching for filesystem? */
|
|
|
|
if (!fsc->fscache)
|
|
|
|
return;
|
2017-06-27 03:57:56 +00:00
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
/* Regular files only */
|
|
|
|
if (!S_ISREG(inode->i_mode))
|
|
|
|
return;
|
2017-06-27 03:57:56 +00:00
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
/* Only new inodes! */
|
|
|
|
if (!(inode->i_state & I_NEW))
|
|
|
|
return;
|
2018-04-04 12:41:28 +00:00
|
|
|
|
netfs: Fix gcc-12 warning by embedding vfs inode in netfs_i_context
While randstruct was satisfied with using an open-coded "void *" offset
cast for the netfs_i_context <-> inode casting, __builtin_object_size() as
used by FORTIFY_SOURCE was not as easily fooled. This was causing the
following complaint[1] from gcc v12:
In file included from include/linux/string.h:253,
from include/linux/ceph/ceph_debug.h:7,
from fs/ceph/inode.c:2:
In function 'fortify_memset_chk',
inlined from 'netfs_i_context_init' at include/linux/netfs.h:326:2,
inlined from 'ceph_alloc_inode' at fs/ceph/inode.c:463:2:
include/linux/fortify-string.h:242:25: warning: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Wattribute-warning]
242 | __write_overflow_field(p_size_field, size);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Fix this by embedding a struct inode into struct netfs_i_context (which
should perhaps be renamed to struct netfs_inode). The struct inode
vfs_inode fields are then removed from the 9p, afs, ceph and cifs inode
structs and vfs_inode is then simply changed to "netfs.inode" in those
filesystems.
Further, rename netfs_i_context to netfs_inode, get rid of the
netfs_inode() function that converted a netfs_i_context pointer to an
inode pointer (that can now be done with &ctx->inode) and rename the
netfs_i_context() function to netfs_inode() (which is now a wrapper
around container_of()).
Most of the changes were done with:
perl -p -i -e 's/vfs_inode/netfs.inode/'g \
`git grep -l 'vfs_inode' -- fs/{9p,afs,ceph,cifs}/*.[ch]`
Kees suggested doing it with a pair structure[2] and a special
declarator to insert that into the network filesystem's inode
wrapper[3], but I think it's cleaner to embed it - and then it doesn't
matter if struct randomisation reorders things.
Dave Chinner suggested using a filesystem-specific VFS_I() function in
each filesystem to convert that filesystem's own inode wrapper struct
into the VFS inode struct[4].
Version #2:
- Fix a couple of missed name changes due to a disabled cifs option.
- Rename nfs_i_context to nfs_inode
- Use "netfs" instead of "nic" as the member name in per-fs inode wrapper
structs.
[ This also undoes commit 507160f46c55 ("netfs: gcc-12: temporarily
disable '-Wattribute-warning' for now") that is no longer needed ]
Fixes: bc899ee1c898 ("netfs: Add a netfs inode context")
Reported-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
cc: Jonathan Corbet <corbet@lwn.net>
cc: Eric Van Hensbergen <ericvh@gmail.com>
cc: Latchesar Ionkov <lucho@ionkov.net>
cc: Dominique Martinet <asmadeus@codewreck.org>
cc: Christian Schoenebeck <linux_oss@crudebyte.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Ilya Dryomov <idryomov@gmail.com>
cc: Steve French <smfrench@gmail.com>
cc: William Kucharski <william.kucharski@oracle.com>
cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
cc: Dave Chinner <david@fromorbit.com>
cc: linux-doc@vger.kernel.org
cc: v9fs-developer@lists.sourceforge.net
cc: linux-afs@lists.infradead.org
cc: ceph-devel@vger.kernel.org
cc: linux-cifs@vger.kernel.org
cc: samba-technical@lists.samba.org
cc: linux-fsdevel@vger.kernel.org
cc: linux-hardening@vger.kernel.org
Link: https://lore.kernel.org/r/d2ad3a3d7bdd794c6efb562d2f2b655fb67756b9.camel@kernel.org/ [1]
Link: https://lore.kernel.org/r/20220517210230.864239-1-keescook@chromium.org/ [2]
Link: https://lore.kernel.org/r/20220518202212.2322058-1-keescook@chromium.org/ [3]
Link: https://lore.kernel.org/r/20220524101205.GI2306852@dread.disaster.area/ [4]
Link: https://lore.kernel.org/r/165296786831.3591209.12111293034669289733.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/165305805651.4094995.7763502506786714216.stgit@warthog.procyon.org.uk # v2
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2022-06-09 20:46:04 +00:00
|
|
|
WARN_ON_ONCE(ci->netfs.cache);
|
2013-08-21 21:29:54 +00:00
|
|
|
|
netfs: Fix gcc-12 warning by embedding vfs inode in netfs_i_context
While randstruct was satisfied with using an open-coded "void *" offset
cast for the netfs_i_context <-> inode casting, __builtin_object_size() as
used by FORTIFY_SOURCE was not as easily fooled. This was causing the
following complaint[1] from gcc v12:
In file included from include/linux/string.h:253,
from include/linux/ceph/ceph_debug.h:7,
from fs/ceph/inode.c:2:
In function 'fortify_memset_chk',
inlined from 'netfs_i_context_init' at include/linux/netfs.h:326:2,
inlined from 'ceph_alloc_inode' at fs/ceph/inode.c:463:2:
include/linux/fortify-string.h:242:25: warning: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Wattribute-warning]
242 | __write_overflow_field(p_size_field, size);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Fix this by embedding a struct inode into struct netfs_i_context (which
should perhaps be renamed to struct netfs_inode). The struct inode
vfs_inode fields are then removed from the 9p, afs, ceph and cifs inode
structs and vfs_inode is then simply changed to "netfs.inode" in those
filesystems.
Further, rename netfs_i_context to netfs_inode, get rid of the
netfs_inode() function that converted a netfs_i_context pointer to an
inode pointer (that can now be done with &ctx->inode) and rename the
netfs_i_context() function to netfs_inode() (which is now a wrapper
around container_of()).
Most of the changes were done with:
perl -p -i -e 's/vfs_inode/netfs.inode/'g \
`git grep -l 'vfs_inode' -- fs/{9p,afs,ceph,cifs}/*.[ch]`
Kees suggested doing it with a pair structure[2] and a special
declarator to insert that into the network filesystem's inode
wrapper[3], but I think it's cleaner to embed it - and then it doesn't
matter if struct randomisation reorders things.
Dave Chinner suggested using a filesystem-specific VFS_I() function in
each filesystem to convert that filesystem's own inode wrapper struct
into the VFS inode struct[4].
Version #2:
- Fix a couple of missed name changes due to a disabled cifs option.
- Rename nfs_i_context to nfs_inode
- Use "netfs" instead of "nic" as the member name in per-fs inode wrapper
structs.
[ This also undoes commit 507160f46c55 ("netfs: gcc-12: temporarily
disable '-Wattribute-warning' for now") that is no longer needed ]
Fixes: bc899ee1c898 ("netfs: Add a netfs inode context")
Reported-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Xiubo Li <xiubli@redhat.com>
cc: Jonathan Corbet <corbet@lwn.net>
cc: Eric Van Hensbergen <ericvh@gmail.com>
cc: Latchesar Ionkov <lucho@ionkov.net>
cc: Dominique Martinet <asmadeus@codewreck.org>
cc: Christian Schoenebeck <linux_oss@crudebyte.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Ilya Dryomov <idryomov@gmail.com>
cc: Steve French <smfrench@gmail.com>
cc: William Kucharski <william.kucharski@oracle.com>
cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
cc: Dave Chinner <david@fromorbit.com>
cc: linux-doc@vger.kernel.org
cc: v9fs-developer@lists.sourceforge.net
cc: linux-afs@lists.infradead.org
cc: ceph-devel@vger.kernel.org
cc: linux-cifs@vger.kernel.org
cc: samba-technical@lists.samba.org
cc: linux-fsdevel@vger.kernel.org
cc: linux-hardening@vger.kernel.org
Link: https://lore.kernel.org/r/d2ad3a3d7bdd794c6efb562d2f2b655fb67756b9.camel@kernel.org/ [1]
Link: https://lore.kernel.org/r/20220517210230.864239-1-keescook@chromium.org/ [2]
Link: https://lore.kernel.org/r/20220518202212.2322058-1-keescook@chromium.org/ [3]
Link: https://lore.kernel.org/r/20220524101205.GI2306852@dread.disaster.area/ [4]
Link: https://lore.kernel.org/r/165296786831.3591209.12111293034669289733.stgit@warthog.procyon.org.uk/ # v1
Link: https://lore.kernel.org/r/165305805651.4094995.7763502506786714216.stgit@warthog.procyon.org.uk # v2
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2022-06-09 20:46:04 +00:00
|
|
|
ci->netfs.cache =
|
2021-06-29 21:37:05 +00:00
|
|
|
fscache_acquire_cookie(fsc->fscache, 0,
|
|
|
|
&ci->i_vino, sizeof(ci->i_vino),
|
|
|
|
&ci->i_version, sizeof(ci->i_version),
|
|
|
|
i_size_read(inode));
|
mm, netfs, fscache: stop read optimisation when folio removed from pagecache
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: https://github.com/DaveWysochanskiRH/kernel/commit/902c990e311120179fa5de99d68364b2947b79ec
Link: https://lkml.kernel.org/r/20230628104852.3391651-3-dhowells@redhat.com
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@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>
2023-06-28 10:48:52 +00:00
|
|
|
if (ci->netfs.cache)
|
|
|
|
mapping_set_release_always(inode->i_mapping);
|
2013-08-21 21:29:54 +00:00
|
|
|
}
|
|
|
|
|
2021-06-29 21:37:05 +00:00
|
|
|
void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info *ci)
|
2013-08-21 21:29:54 +00:00
|
|
|
{
|
2021-06-29 21:37:05 +00:00
|
|
|
fscache_relinquish_cookie(ceph_fscache_cookie(ci), false);
|
2021-12-07 13:44:50 +00:00
|
|
|
}
|
2013-08-21 21:29:54 +00:00
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
void ceph_fscache_use_cookie(struct inode *inode, bool will_modify)
|
|
|
|
{
|
|
|
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
2013-08-21 21:29:54 +00:00
|
|
|
|
2021-06-29 21:37:05 +00:00
|
|
|
fscache_use_cookie(ceph_fscache_cookie(ci), will_modify);
|
2013-08-21 21:29:54 +00:00
|
|
|
}
|
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
void ceph_fscache_unuse_cookie(struct inode *inode, bool update)
|
2013-08-21 21:29:54 +00:00
|
|
|
{
|
2016-05-18 07:25:03 +00:00
|
|
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
2013-08-21 21:29:54 +00:00
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
if (update) {
|
|
|
|
loff_t i_size = i_size_read(inode);
|
2013-08-21 21:29:54 +00:00
|
|
|
|
2021-06-29 21:37:05 +00:00
|
|
|
fscache_unuse_cookie(ceph_fscache_cookie(ci),
|
|
|
|
&ci->i_version, &i_size);
|
2021-12-07 13:44:50 +00:00
|
|
|
} else {
|
2021-06-29 21:37:05 +00:00
|
|
|
fscache_unuse_cookie(ceph_fscache_cookie(ci), NULL, NULL);
|
2016-05-18 07:25:03 +00:00
|
|
|
}
|
2013-08-21 21:29:54 +00:00
|
|
|
}
|
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
void ceph_fscache_update(struct inode *inode)
|
2013-08-21 21:29:54 +00:00
|
|
|
{
|
2021-12-07 13:44:50 +00:00
|
|
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
|
|
|
loff_t i_size = i_size_read(inode);
|
2013-08-21 21:29:54 +00:00
|
|
|
|
2021-06-29 21:37:05 +00:00
|
|
|
fscache_update_cookie(ceph_fscache_cookie(ci), &ci->i_version, &i_size);
|
2013-08-21 21:29:54 +00:00
|
|
|
}
|
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
void ceph_fscache_invalidate(struct inode *inode, bool dio_write)
|
2016-05-18 07:25:03 +00:00
|
|
|
{
|
2021-12-07 13:44:50 +00:00
|
|
|
struct ceph_inode_info *ci = ceph_inode(inode);
|
|
|
|
|
2021-06-29 21:37:05 +00:00
|
|
|
fscache_invalidate(ceph_fscache_cookie(ci),
|
2021-12-07 13:44:50 +00:00
|
|
|
&ci->i_version, i_size_read(inode),
|
|
|
|
dio_write ? FSCACHE_INVAL_DIO_WRITE : 0);
|
2016-05-18 07:25:03 +00:00
|
|
|
}
|
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
int ceph_fscache_register_fs(struct ceph_fs_client* fsc, struct fs_context *fc)
|
2016-05-18 07:25:03 +00:00
|
|
|
{
|
2021-12-07 13:44:50 +00:00
|
|
|
const struct ceph_fsid *fsid = &fsc->client->fsid;
|
|
|
|
const char *fscache_uniq = fsc->mount_options->fscache_uniq;
|
|
|
|
size_t uniq_len = fscache_uniq ? strlen(fscache_uniq) : 0;
|
|
|
|
char *name;
|
|
|
|
int err = 0;
|
2016-05-18 07:25:03 +00:00
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
name = kasprintf(GFP_KERNEL, "ceph,%pU%s%s", fsid, uniq_len ? "," : "",
|
|
|
|
uniq_len ? fscache_uniq : "");
|
|
|
|
if (!name)
|
|
|
|
return -ENOMEM;
|
2016-05-18 07:25:03 +00:00
|
|
|
|
2021-12-07 13:44:50 +00:00
|
|
|
fsc->fscache = fscache_acquire_volume(name, NULL, NULL, 0);
|
|
|
|
if (IS_ERR_OR_NULL(fsc->fscache)) {
|
|
|
|
errorfc(fc, "Unable to register fscache cookie for %s", name);
|
|
|
|
err = fsc->fscache ? PTR_ERR(fsc->fscache) : -EOPNOTSUPP;
|
|
|
|
fsc->fscache = NULL;
|
2016-05-18 07:25:03 +00:00
|
|
|
}
|
2021-12-07 13:44:50 +00:00
|
|
|
kfree(name);
|
|
|
|
return err;
|
2016-05-18 07:25:03 +00:00
|
|
|
}
|
|
|
|
|
2013-08-21 21:29:54 +00:00
|
|
|
void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc)
|
|
|
|
{
|
2021-12-07 13:44:50 +00:00
|
|
|
fscache_relinquish_volume(fsc->fscache, NULL, false);
|
2013-08-21 21:29:54 +00:00
|
|
|
}
|