Re: [PATCH 03/26] netfs: Update i_blocks when write committed to pagecache

Jeff Layton
2024-04-15T11:28:42Z

On Thu, 2024-03-28 at 16:33 +0000, David Howells wrote:
> Update i_blocks when i_size is updated when we finish making a write to the
> pagecache to reflect the amount of space we think will be consumed.
>

Umm ok, but why? I get that the i_size and i_blocks would be out of sync
until we get back new attrs from the server, but is that a problem? I'm
mainly curious as to what's paying attention to the i_blocks during this
window.

> Signed-off-by: David Howells <dhowells@redhat.com>
> cc: Steve French <sfrench@samba.org>
> cc: Shyam Prasad N <nspmangalore@gmail.com>
> cc: Rohith Surabattula <rohiths.msft@gmail.com>
> cc: Jeff Layton <jlayton@kernel.org>
> cc: linux-cifs@vger.kernel.org
> cc: netfs@lists.linux.dev
> cc: linux-fsdevel@vger.kernel.org
> cc: linux-mm@kvack.org
> ---
> fs/netfs/buffered_write.c | 45 +++++++++++++++++++++++++++++----------
> 1 file changed, 34 insertions(+), 11 deletions(-)
>
> diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c
> index 9a0d32e4b422..c194655a6dcf 100644
> --- a/fs/netfs/buffered_write.c
> +++ b/fs/netfs/buffered_write.c
> @@ -130,6 +130,37 @@ static struct folio *netfs_grab_folio_for_write(struct address_space *mapping,
> mapping_gfp_mask(mapping));
> }
>
> +/*
> + * Update i_size and estimate the update to i_blocks to reflect the additional
> + * data written into the pagecache until we can find out from the server what
> + * the values actually are.
> + */
> +static void netfs_update_i_size(struct netfs_inode *ctx, struct inode *inode,
> + loff_t i_size, loff_t pos, size_t copied)
> +{
> + blkcnt_t add;
> + size_t gap;
> +
> + if (ctx->ops->update_i_size) {
> + ctx->ops->update_i_size(inode, pos);
> + return;
> + }
> +
> + i_size_write(inode, pos);
> +#if IS_ENABLED(CONFIG_FSCACHE)
> + fscache_update_cookie(ctx->cache, NULL, &pos);
> +#endif
> +
> + gap = SECTOR_SIZE - (i_size & (SECTOR_SIZE - 1));
> + if (copied > gap) {
> + add = DIV_ROUND_UP(copied - gap, SECTOR_SIZE);
> +
> + inode->i_blocks = min_t(blkcnt_t,
> + DIV_ROUND_UP(pos, SECTOR_SIZE),
> + inode->i_blocks + add);
> + }
> +}
> +
> /**
> * netfs_perform_write - Copy data into the pagecache.
> * @iocb: The operation parameters
> @@ -352,18 +383,10 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
> trace_netfs_folio(folio, trace);
>
> /* Update the inode size if we moved the EOF marker */
> - i_size = i_size_read(inode);
> pos += copied;
> - if (pos > i_size) {
> - if (ctx->ops->update_i_size) {
> - ctx->ops->update_i_size(inode, pos);
> - } else {
> - i_size_write(inode, pos);
> -#if IS_ENABLED(CONFIG_FSCACHE)
> - fscache_update_cookie(ctx->cache, NULL, &pos);
> -#endif
> - }
> - }
> + i_size = i_size_read(inode);
> + if (pos > i_size)
> + netfs_update_i_size(ctx, inode, i_size, pos, copied);
> written += copied;
>
> if (likely(!wreq)) {
>

Reviewed-by: Jeff Layton <jlayton@kernel.org>