Re: [PATCH 03/67] vfs, fscache: Force ->write_inode() to occur if cookie pinned for writeback

From: Jeff Layton
Date: Tue Oct 19 2021 - 13:22:58 EST


On Mon, 2021-10-18 at 15:51 +0100, David Howells wrote:
> Use an inode flag, I_PINNING_FSCACHE_WB, to indicate that a cookie is
> pinned in use by that inode for the purposes of writeback.
>
> Pinning is necessary because the in-use pin from the open file is released
> before the writeback takes place, but if the resources aren't pinned, the
> dirty data can't be written to the cache.
>
> Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
> ---
>
> fs/fs-writeback.c | 8 ++++++++
> include/linux/fs.h | 3 +++
> include/linux/fscache.h | 1 +
> include/linux/writeback.h | 1 +
> 4 files changed, 13 insertions(+)
>
> diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
> index 81ec192ce067..f3122831c4fe 100644
> --- a/fs/fs-writeback.c
> +++ b/fs/fs-writeback.c
> @@ -1666,6 +1666,13 @@ __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)) {
> + 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 */
> + }
> + }

IDGI: how would I_PINNING_FSCACHE_WB get set in the first place?

>
> spin_unlock(&inode->i_lock);
>
> @@ -1675,6 +1682,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
> if (ret == 0)
> ret = err;
> }
> + wbc->unpinned_fscache_wb = false;
> trace_writeback_single_inode(inode, wbc, nr_to_write);
> return ret;
> }
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 197493507744..336739fed3e9 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2420,6 +2420,8 @@ static inline void kiocb_clone(struct kiocb *kiocb, struct kiocb *kiocb_src,
> * Used to detect that mark_inode_dirty() should not move
> * inode between dirty lists.
> *
> + * I_PINNING_FSCACHE_WB Inode is pinning an fscache object for writeback.
> + *
> * Q: What is the difference between I_WILL_FREE and I_FREEING?
> */
> #define I_DIRTY_SYNC (1 << 0)
> @@ -2442,6 +2444,7 @@ static inline void kiocb_clone(struct kiocb *kiocb, struct kiocb *kiocb_src,
> #define I_CREATING (1 << 15)
> #define I_DONTCACHE (1 << 16)
> #define I_SYNC_QUEUED (1 << 17)
> +#define I_PINNING_FSCACHE_WB (1 << 18)
>
> #define I_DIRTY_INODE (I_DIRTY_SYNC | I_DIRTY_DATASYNC)
> #define I_DIRTY (I_DIRTY_INODE | I_DIRTY_PAGES)
> diff --git a/include/linux/fscache.h b/include/linux/fscache.h
> index 01558d155799..ba4878b56717 100644
> --- a/include/linux/fscache.h
> +++ b/include/linux/fscache.h
> @@ -19,6 +19,7 @@
> #include <linux/pagemap.h>
> #include <linux/pagevec.h>
> #include <linux/list_bl.h>
> +#include <linux/writeback.h>
> #include <linux/netfs.h>
>
> #if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE)
> diff --git a/include/linux/writeback.h b/include/linux/writeback.h
> index d1f65adf6a26..2fda288600d3 100644
> --- a/include/linux/writeback.h
> +++ b/include/linux/writeback.h
> @@ -69,6 +69,7 @@ struct writeback_control {
> unsigned for_reclaim:1; /* Invoked from the page allocator */
> unsigned range_cyclic:1; /* range_start is cyclic */
> unsigned for_sync:1; /* sync(2) WB_SYNC_ALL writeback */
> + unsigned unpinned_fscache_wb:1; /* Cleared I_PINNING_FSCACHE_WB */
>
> /*
> * When writeback IOs are bounced through async layers, only the
>
>

--
Jeff Layton <jlayton@xxxxxxxxxx>