Skip to content

Commit

Permalink
netfs: Move pinning-for-writeback from fscache to netfs
Browse files Browse the repository at this point in the history
Move the resource pinning-for-writeback from fscache code to netfslib code.
This is used to keep a cache backing object pinned whilst we have dirty
pages on the netfs inode in the pagecache such that VM writeback will be
able to reach it.

Whilst we're at it, switch the parameters of netfs_unpin_writeback() to
match ->write_inode() so that it can be used for that directly.

Note that this mechanism could be more generically useful than that for
network filesystems.  Quite often they have to keep around other resources
(e.g. authentication tokens or network connections) until the writeback is
complete.

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
cc: linux-fsdevel@vger.kernel.org
cc: linux-mm@kvack.org
  • Loading branch information
David Howells committed Dec 24, 2023
1 parent 7eb5b3e commit c9c4ff1
Show file tree
Hide file tree
Showing 20 changed files with 124 additions and 187 deletions.
33 changes: 9 additions & 24 deletions fs/9p/vfs_addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,30 +317,15 @@ static int v9fs_write_end(struct file *filp, struct address_space *mapping,
return copied;
}

#ifdef CONFIG_9P_FSCACHE
/*
* Mark a page as having been made dirty and thus needing writeback. We also
* need to pin the cache object to write back to.
*/
static bool v9fs_dirty_folio(struct address_space *mapping, struct folio *folio)
{
struct v9fs_inode *v9inode = V9FS_I(mapping->host);

return fscache_dirty_folio(mapping, folio, v9fs_inode_cookie(v9inode));
}
#else
#define v9fs_dirty_folio filemap_dirty_folio
#endif

const struct address_space_operations v9fs_addr_operations = {
.read_folio = netfs_read_folio,
.readahead = netfs_readahead,
.dirty_folio = v9fs_dirty_folio,
.writepage = v9fs_vfs_writepage,
.write_begin = v9fs_write_begin,
.write_end = v9fs_write_end,
.release_folio = v9fs_release_folio,
.read_folio = netfs_read_folio,
.readahead = netfs_readahead,
.dirty_folio = netfs_dirty_folio,
.writepage = v9fs_vfs_writepage,
.write_begin = v9fs_write_begin,
.write_end = v9fs_write_end,
.release_folio = v9fs_release_folio,
.invalidate_folio = v9fs_invalidate_folio,
.launder_folio = v9fs_launder_folio,
.direct_IO = v9fs_direct_IO,
.launder_folio = v9fs_launder_folio,
.direct_IO = v9fs_direct_IO,
};
3 changes: 1 addition & 2 deletions fs/9p/vfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,7 @@ void v9fs_evict_inode(struct inode *inode)

#ifdef CONFIG_9P_FSCACHE
version = cpu_to_le32(v9inode->qid.version);
fscache_clear_inode_writeback(v9fs_inode_cookie(v9inode), inode,
&version);
netfs_clear_inode_writeback(inode, &version);
#endif

clear_inode(inode);
Expand Down
14 changes: 2 additions & 12 deletions fs/9p/vfs_super.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,31 +289,21 @@ static int v9fs_drop_inode(struct inode *inode)
static int v9fs_write_inode(struct inode *inode,
struct writeback_control *wbc)
{
struct v9fs_inode *v9inode;

/*
* send an fsync request to server irrespective of
* wbc->sync_mode.
*/
p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);

v9inode = V9FS_I(inode);
fscache_unpin_writeback(wbc, v9fs_inode_cookie(v9inode));

return 0;
return netfs_unpin_writeback(inode, wbc);
}

static int v9fs_write_inode_dotl(struct inode *inode,
struct writeback_control *wbc)
{
struct v9fs_inode *v9inode;

v9inode = V9FS_I(inode);
p9_debug(P9_DEBUG_VFS, "%s: inode %p\n", __func__, inode);

fscache_unpin_writeback(wbc, v9fs_inode_cookie(v9inode));

return 0;
return netfs_unpin_writeback(inode, wbc);
}

static const struct super_operations v9fs_super_ops = {
Expand Down
8 changes: 1 addition & 7 deletions fs/afs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const struct inode_operations afs_file_inode_operations = {
const struct address_space_operations afs_file_aops = {
.read_folio = netfs_read_folio,
.readahead = netfs_readahead,
.dirty_folio = afs_dirty_folio,
.dirty_folio = netfs_dirty_folio,
.launder_folio = afs_launder_folio,
.release_folio = afs_release_folio,
.invalidate_folio = afs_invalidate_folio,
Expand Down Expand Up @@ -386,12 +386,6 @@ const struct netfs_request_ops afs_req_ops = {
.issue_read = afs_issue_read,
};

int afs_write_inode(struct inode *inode, struct writeback_control *wbc)
{
fscache_unpin_writeback(wbc, afs_vnode_cache(AFS_FS_I(inode)));
return 0;
}

/*
* Adjust the dirty region of the page on truncation or full invalidation,
* getting rid of the markers altogether if the region is entirely invalidated.
Expand Down
2 changes: 1 addition & 1 deletion fs/afs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,7 @@ void afs_evict_inode(struct inode *inode)
truncate_inode_pages_final(&inode->i_data);

afs_set_cache_aux(vnode, &aux);
fscache_clear_inode_writeback(afs_vnode_cache(vnode), inode, &aux);
netfs_clear_inode_writeback(inode, &aux);
clear_inode(inode);

while (!list_empty(&vnode->wb_keys)) {
Expand Down
6 changes: 0 additions & 6 deletions fs/afs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,6 @@ extern int afs_release(struct inode *, struct file *);
extern int afs_fetch_data(struct afs_vnode *, struct afs_read *);
extern struct afs_read *afs_alloc_read(gfp_t);
extern void afs_put_read(struct afs_read *);
extern int afs_write_inode(struct inode *, struct writeback_control *);

static inline struct afs_read *afs_get_read(struct afs_read *req)
{
Expand Down Expand Up @@ -1522,11 +1521,6 @@ extern int afs_check_volume_status(struct afs_volume *, struct afs_operation *);
/*
* write.c
*/
#ifdef CONFIG_AFS_FSCACHE
bool afs_dirty_folio(struct address_space *, struct folio *);
#else
#define afs_dirty_folio filemap_dirty_folio
#endif
extern int afs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len,
struct page **pagep, void **fsdata);
Expand Down
2 changes: 1 addition & 1 deletion fs/afs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ int afs_net_id;
static const struct super_operations afs_super_ops = {
.statfs = afs_statfs,
.alloc_inode = afs_alloc_inode,
.write_inode = afs_write_inode,
.write_inode = netfs_unpin_writeback,
.drop_inode = afs_drop_inode,
.destroy_inode = afs_destroy_inode,
.free_inode = afs_free_inode,
Expand Down
9 changes: 0 additions & 9 deletions fs/afs/write.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,6 @@ static void afs_write_to_cache(struct afs_vnode *vnode, loff_t start, size_t len
loff_t i_size, bool caching);

#ifdef CONFIG_AFS_FSCACHE
/*
* Mark a page as having been made dirty and thus needing writeback. We also
* need to pin the cache object to write back to.
*/
bool afs_dirty_folio(struct address_space *mapping, struct folio *folio)
{
return fscache_dirty_folio(mapping, folio,
afs_vnode_cache(AFS_FS_I(mapping->host)));
}
static void afs_folio_start_fscache(bool caching, struct folio *folio)
{
if (caching)
Expand Down
23 changes: 7 additions & 16 deletions fs/ceph/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,13 @@ static inline void ceph_fscache_resize(struct inode *inode, loff_t to)
}
}

static inline void ceph_fscache_unpin_writeback(struct inode *inode,
static inline int ceph_fscache_unpin_writeback(struct inode *inode,
struct writeback_control *wbc)
{
fscache_unpin_writeback(wbc, ceph_fscache_cookie(ceph_inode(inode)));
return netfs_unpin_writeback(inode, wbc);
}

static inline int ceph_fscache_dirty_folio(struct address_space *mapping,
struct folio *folio)
{
struct ceph_inode_info *ci = ceph_inode(mapping->host);

return fscache_dirty_folio(mapping, folio, ceph_fscache_cookie(ci));
}
#define ceph_fscache_dirty_folio netfs_dirty_folio

static inline bool ceph_is_cache_enabled(struct inode *inode)
{
Expand Down Expand Up @@ -112,16 +106,13 @@ static inline void ceph_fscache_resize(struct inode *inode, loff_t to)
{
}

static inline void ceph_fscache_unpin_writeback(struct inode *inode,
struct writeback_control *wbc)
static inline int ceph_fscache_unpin_writeback(struct inode *inode,
struct writeback_control *wbc)
{
return 0;
}

static inline int ceph_fscache_dirty_folio(struct address_space *mapping,
struct folio *folio)
{
return filemap_dirty_folio(mapping, folio);
}
#define ceph_fscache_dirty_folio filemap_dirty_folio

static inline bool ceph_is_cache_enabled(struct inode *inode)
{
Expand Down
2 changes: 1 addition & 1 deletion fs/ceph/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ void ceph_evict_inode(struct inode *inode)
percpu_counter_dec(&mdsc->metric.total_inodes);

truncate_inode_pages_final(&inode->i_data);
if (inode->i_state & I_PINNING_FSCACHE_WB)
if (inode->i_state & I_PINNING_NETFS_WB)
ceph_fscache_unuse_cookie(inode, true);
clear_inode(inode);

Expand Down
10 changes: 5 additions & 5 deletions fs/fs-writeback.c
Original file line number Diff line number Diff line change
Expand Up @@ -1675,11 +1675,11 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)

if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY))
inode->i_state |= I_DIRTY_PAGES;
else if (unlikely(inode->i_state & I_PINNING_FSCACHE_WB)) {
else if (unlikely(inode->i_state & I_PINNING_NETFS_WB)) {
if (!(inode->i_state & I_DIRTY_PAGES)) {
inode->i_state &= ~I_PINNING_FSCACHE_WB;
wbc->unpinned_fscache_wb = true;
dirty |= I_PINNING_FSCACHE_WB; /* Cause write_inode */
inode->i_state &= ~I_PINNING_NETFS_WB;
wbc->unpinned_netfs_wb = true;
dirty |= I_PINNING_NETFS_WB; /* Cause write_inode */
}
}

Expand All @@ -1691,7 +1691,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
if (ret == 0)
ret = err;
}
wbc->unpinned_fscache_wb = false;
wbc->unpinned_netfs_wb = false;
trace_writeback_single_inode(inode, wbc, nr_to_write);
return ret;
}
Expand Down
1 change: 1 addition & 0 deletions fs/netfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ netfs-y := \
io.o \
iterator.o \
main.o \
misc.o \
objects.o

netfs-$(CONFIG_NETFS_STATS) += stats.o
Expand Down
40 changes: 0 additions & 40 deletions fs/netfs/fscache_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,46 +158,6 @@ int __fscache_begin_write_operation(struct netfs_cache_resources *cres,
}
EXPORT_SYMBOL(__fscache_begin_write_operation);

/**
* fscache_dirty_folio - Mark folio dirty and pin a cache object for writeback
* @mapping: The mapping the folio belongs to.
* @folio: The folio being dirtied.
* @cookie: The cookie referring to the cache object
*
* Set the dirty flag on a folio and pin an in-use cache object in memory
* so that writeback can later write to it. This is intended
* to be called from the filesystem's ->dirty_folio() method.
*
* Return: true if the dirty flag was set on the folio, false otherwise.
*/
bool fscache_dirty_folio(struct address_space *mapping, struct folio *folio,
struct fscache_cookie *cookie)
{
struct inode *inode = mapping->host;
bool need_use = false;

_enter("");

if (!filemap_dirty_folio(mapping, folio))
return false;
if (!fscache_cookie_valid(cookie))
return true;

if (!(inode->i_state & I_PINNING_FSCACHE_WB)) {
spin_lock(&inode->i_lock);
if (!(inode->i_state & I_PINNING_FSCACHE_WB)) {
inode->i_state |= I_PINNING_FSCACHE_WB;
need_use = true;
}
spin_unlock(&inode->i_lock);

if (need_use)
fscache_use_cookie(cookie, true);
}
return true;
}
EXPORT_SYMBOL(fscache_dirty_folio);

struct fscache_write_request {
struct netfs_cache_resources cache_resources;
struct address_space *mapping;
Expand Down
86 changes: 86 additions & 0 deletions fs/netfs/misc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Miscellaneous routines.
*
* Copyright (C) 2023 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*/

#include <linux/swap.h>
#include "internal.h"

/**
* netfs_dirty_folio - Mark folio dirty and pin a cache object for writeback
* @mapping: The mapping the folio belongs to.
* @folio: The folio being dirtied.
*
* Set the dirty flag on a folio and pin an in-use cache object in memory so
* that writeback can later write to it. This is intended to be called from
* the filesystem's ->dirty_folio() method.
*
* Return: true if the dirty flag was set on the folio, false otherwise.
*/
bool netfs_dirty_folio(struct address_space *mapping, struct folio *folio)
{
struct inode *inode = mapping->host;
struct netfs_inode *ictx = netfs_inode(inode);
struct fscache_cookie *cookie = netfs_i_cookie(ictx);
bool need_use = false;

_enter("");

if (!filemap_dirty_folio(mapping, folio))
return false;
if (!fscache_cookie_valid(cookie))
return true;

if (!(inode->i_state & I_PINNING_NETFS_WB)) {
spin_lock(&inode->i_lock);
if (!(inode->i_state & I_PINNING_NETFS_WB)) {
inode->i_state |= I_PINNING_NETFS_WB;
need_use = true;
}
spin_unlock(&inode->i_lock);

if (need_use)
fscache_use_cookie(cookie, true);
}
return true;
}
EXPORT_SYMBOL(netfs_dirty_folio);

/**
* netfs_unpin_writeback - Unpin writeback resources
* @inode: The inode on which the cookie resides
* @wbc: The writeback control
*
* Unpin the writeback resources pinned by netfs_dirty_folio(). This is
* intended to be called as/by the netfs's ->write_inode() method.
*/
int netfs_unpin_writeback(struct inode *inode, struct writeback_control *wbc)
{
struct fscache_cookie *cookie = netfs_i_cookie(netfs_inode(inode));

if (wbc->unpinned_netfs_wb)
fscache_unuse_cookie(cookie, NULL, NULL);
return 0;
}
EXPORT_SYMBOL(netfs_unpin_writeback);

/**
* netfs_clear_inode_writeback - Clear writeback resources pinned by an inode
* @inode: The inode to clean up
* @aux: Auxiliary data to apply to the inode
*
* Clear any writeback resources held by an inode when the inode is evicted.
* This must be called before clear_inode() is called.
*/
void netfs_clear_inode_writeback(struct inode *inode, const void *aux)
{
struct fscache_cookie *cookie = netfs_i_cookie(netfs_inode(inode));

if (inode->i_state & I_PINNING_NETFS_WB) {
loff_t i_size = i_size_read(inode);
fscache_unuse_cookie(cookie, aux, &i_size);
}
}
EXPORT_SYMBOL(netfs_clear_inode_writeback);
5 changes: 2 additions & 3 deletions fs/smb/client/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ static void
cifs_evict_inode(struct inode *inode)
{
truncate_inode_pages_final(&inode->i_data);
if (inode->i_state & I_PINNING_FSCACHE_WB)
if (inode->i_state & I_PINNING_NETFS_WB)
cifs_fscache_unuse_inode_cookie(inode, true);
cifs_fscache_release_inode_cookie(inode);
clear_inode(inode);
Expand Down Expand Up @@ -792,8 +792,7 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root)

static int cifs_write_inode(struct inode *inode, struct writeback_control *wbc)
{
fscache_unpin_writeback(wbc, cifs_inode_cookie(inode));
return 0;
return netfs_unpin_writeback(inode, wbc);
}

static int cifs_drop_inode(struct inode *inode)
Expand Down
Loading

0 comments on commit c9c4ff1

Please sign in to comment.