Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2225006/?format=api
{ "id": 2225006, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2225006/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-cifs-client/patch/20260420083705.1009074-10-dhowells@redhat.com/", "project": { "id": 12, "url": "http://patchwork.ozlabs.org/api/1.1/projects/12/?format=api", "name": "Linux CIFS Client", "link_name": "linux-cifs-client", "list_id": "linux-cifs.vger.kernel.org", "list_email": "linux-cifs@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20260420083705.1009074-10-dhowells@redhat.com>", "date": "2026-04-20T08:37:00", "name": "[09/11] netfs: Fix potential for tearing in ->remote_i_size and ->zero_point", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "a90add3c6df6423ed0e86f0d51df1e2232dfbadd", "submitter": { "id": 59, "url": "http://patchwork.ozlabs.org/api/1.1/people/59/?format=api", "name": "David Howells", "email": "dhowells@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-cifs-client/patch/20260420083705.1009074-10-dhowells@redhat.com/mbox/", "series": [ { "id": 500568, "url": "http://patchwork.ozlabs.org/api/1.1/series/500568/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-cifs-client/list/?series=500568", "date": "2026-04-20T08:36:52", "name": "netfs: Further miscellaneous fixes", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/500568/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2225006/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2225006/checks/", "tags": {}, "headers": { "Return-Path": "\n <linux-cifs+bounces-10932-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-cifs@vger.kernel.org" ], "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=FxjbXCJl;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=104.64.211.4; helo=sin.lore.kernel.org;\n envelope-from=linux-cifs+bounces-10932-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n\tdkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com\n header.b=\"FxjbXCJl\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=170.10.133.124", "smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=redhat.com", "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=redhat.com" ], "Received": [ "from sin.lore.kernel.org (sin.lore.kernel.org [104.64.211.4])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fzfB10w8Yz1yGs\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 20 Apr 2026 18:42:17 +1000 (AEST)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id EBD773025E19\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 20 Apr 2026 08:38:42 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id AFD05391E7F;\n\tMon, 20 Apr 2026 08:38:06 +0000 (UTC)", "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 0DE7B38B148\n\tfor <linux-cifs@vger.kernel.org>; Mon, 20 Apr 2026 08:38:03 +0000 (UTC)", "from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-156-684tbrelMNmXQAwFCRwFlA-1; Mon,\n 20 Apr 2026 04:38:01 -0400", "from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 649701800473;\n\tMon, 20 Apr 2026 08:37:59 +0000 (UTC)", "from warthog.procyon.org.com (unknown [10.44.48.17])\n\tby mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 289F81801481;\n\tMon, 20 Apr 2026 08:37:55 +0000 (UTC)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1776674286; cv=none;\n b=WC0zTWMHz2cDQadMVYWVURgMwk2+pUUthgIY3M4YZgKwJFNKqhLTEOdUEdJummA9ALTpdE59O4X52EzpFwfrRPVlz0iG4pKZrgaALLEL3IekT3WBCVMadekU9At2QqAaT+FMC3EE1TrlfWphv54LGpOw90d/BSRpmwmGbgIoD9I=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1776674286; c=relaxed/simple;\n\tbh=M4G7CQ90pI0guOT8qdXsIFfuTO8z4pu+AYho3qmmbvI=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=DuUk0ZH5rmH+CpN+yrLkvWWmKZMatGGAwUUMDsx6Hk6ThQJYdrAuWuyYvZwFvdrgJ1yZLFVEhZo5orVmVTFjYjyBUPz3RdF+AaTd5uhByfPc10arXcXlemjWhXZU9+EyZq9NBXKPIrV0Cby3YHjyFzua8UR3vpXUfg7/kP/stsM=", "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=redhat.com;\n spf=pass smtp.mailfrom=redhat.com;\n dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com\n header.b=FxjbXCJl; arc=none smtp.client-ip=170.10.133.124", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1776674283;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\t to:to:cc:cc:mime-version:mime-version:\n\t content-transfer-encoding:content-transfer-encoding:\n\t in-reply-to:in-reply-to:references:references;\n\tbh=I5D+Oxw+ox5fGkrZ90uYeUrfVkAZVJhvtSK5/NHTQNY=;\n\tb=FxjbXCJlz2zdKiAYECjEQVigLI82b+JmjHqO1y4opK5fr39tTTOcfAe4VPXF0mwWbQf3lg\n\tGpo+ri2dhyqbUgkhCwtvtGSkDhEwdtmFHlnG3SoNVmgO6npQSMQC7udUF3P19pNee1tbz5\n\t2+MXH0IeazkOCG99uKmhRTUrbRStsE8=", "X-MC-Unique": "684tbrelMNmXQAwFCRwFlA-1", "X-Mimecast-MFC-AGG-ID": "684tbrelMNmXQAwFCRwFlA_1776674279", "From": "David Howells <dhowells@redhat.com>", "To": "Christian Brauner <christian@brauner.io>", "Cc": "David Howells <dhowells@redhat.com>,\n\tPaulo Alcantara <pc@manguebit.org>,\n\tnetfs@lists.linux.dev,\n\tlinux-afs@lists.infradead.org,\n\tlinux-cifs@vger.kernel.org,\n\tceph-devel@vger.kernel.org,\n\tlinux-fsdevel@vger.kernel.org,\n\tlinux-kernel@vger.kernel.org,\n\tMatthew Wilcox <willy@infradead.org>", "Subject": "[PATCH 09/11] netfs: Fix potential for tearing in ->remote_i_size and\n ->zero_point", "Date": "Mon, 20 Apr 2026 09:37:00 +0100", "Message-ID": "<20260420083705.1009074-10-dhowells@redhat.com>", "In-Reply-To": "<20260420083705.1009074-1-dhowells@redhat.com>", "References": "<20260420083705.1009074-1-dhowells@redhat.com>", "Precedence": "bulk", "X-Mailing-List": "linux-cifs@vger.kernel.org", "List-Id": "<linux-cifs.vger.kernel.org>", "List-Subscribe": "<mailto:linux-cifs+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-cifs+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.93" }, "content": "Fix potential tearing in using ->remote_i_size and ->zero_point by copying\ni_size_read() and i_size_write() and using the same seqcount as for i_size.\n\nFixes: 4058f742105e (\"netfs: Keep track of the actual remote file size\")\nFixes: 100ccd18bb41 (\"netfs: Optimise away reads above the point at which there can be no data\")\nCloses: https://sashiko.dev/#/patchset/20260414082004.3756080-1-dhowells%40redhat.com\nSigned-off-by: David Howells <dhowells@redhat.com>\ncc: Paulo Alcantara <pc@manguebit.org>\ncc: Matthew Wilcox <willy@infradead.org>\ncc: netfs@lists.linux.dev\ncc: linux-fsdevel@vger.kernel.org\n---\n fs/9p/vfs_inode.c | 2 +-\n fs/9p/vfs_inode_dotl.c | 4 +-\n fs/afs/inode.c | 8 +-\n fs/afs/write.c | 2 +-\n fs/netfs/buffered_read.c | 5 +-\n fs/netfs/buffered_write.c | 2 +-\n fs/netfs/direct_write.c | 4 +-\n fs/netfs/misc.c | 13 +-\n fs/netfs/write_collect.c | 3 +-\n fs/smb/client/cifsfs.c | 24 +--\n fs/smb/client/cifssmb.c | 2 +-\n fs/smb/client/file.c | 9 +-\n fs/smb/client/inode.c | 9 +-\n fs/smb/client/readdir.c | 3 +-\n fs/smb/client/smb2ops.c | 16 +-\n fs/smb/client/smb2pdu.c | 2 +-\n include/linux/netfs.h | 299 ++++++++++++++++++++++++++++++++++++--\n 17 files changed, 348 insertions(+), 59 deletions(-)", "diff": "diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c\nindex d1508b1fe109..b13156ac2f1f 100644\n--- a/fs/9p/vfs_inode.c\n+++ b/fs/9p/vfs_inode.c\n@@ -1141,7 +1141,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,\n \tmode |= inode->i_mode & ~S_IALLUGO;\n \tinode->i_mode = mode;\n \n-\tv9inode->netfs.remote_i_size = stat->length;\n+\tnetfs_write_remote_i_size(&v9inode->netfs, stat->length);\n \tif (!(flags & V9FS_STAT2INODE_KEEP_ISIZE))\n \t\tv9fs_i_size_write(inode, stat->length);\n \t/* not real number of blocks, but 512 byte ones ... */\ndiff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c\nindex 71796a89bcf4..81d6150a8ae4 100644\n--- a/fs/9p/vfs_inode_dotl.c\n+++ b/fs/9p/vfs_inode_dotl.c\n@@ -634,7 +634,7 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,\n \t\tmode |= inode->i_mode & ~S_IALLUGO;\n \t\tinode->i_mode = mode;\n \n-\t\tv9inode->netfs.remote_i_size = stat->st_size;\n+\t\tnetfs_write_remote_i_size(&v9inode->netfs, stat->st_size);\n \t\tif (!(flags & V9FS_STAT2INODE_KEEP_ISIZE))\n \t\t\tv9fs_i_size_write(inode, stat->st_size);\n \t\tinode->i_blocks = stat->st_blocks;\n@@ -664,7 +664,7 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,\n \t\t}\n \t\tif (!(flags & V9FS_STAT2INODE_KEEP_ISIZE) &&\n \t\t stat->st_result_mask & P9_STATS_SIZE) {\n-\t\t\tv9inode->netfs.remote_i_size = stat->st_size;\n+\t\t\tnetfs_write_remote_i_size(&v9inode->netfs, stat->st_size);\n \t\t\tv9fs_i_size_write(inode, stat->st_size);\n \t\t}\n \t\tif (stat->st_result_mask & P9_STATS_BLOCKS)\ndiff --git a/fs/afs/inode.c b/fs/afs/inode.c\nindex a5173434f786..06e25e1b12df 100644\n--- a/fs/afs/inode.c\n+++ b/fs/afs/inode.c\n@@ -343,11 +343,11 @@ static void afs_apply_status(struct afs_operation *op,\n \t\t * idea of what the size should be that's not the same as\n \t\t * what's on the server.\n \t\t */\n-\t\tvnode->netfs.remote_i_size = status->size;\n+\t\tnetfs_write_remote_i_size(&vnode->netfs, status->size);\n \t\tif (change_size || status->size > i_size_read(inode)) {\n \t\t\tafs_set_i_size(vnode, status->size);\n \t\t\tif (unexpected_jump)\n-\t\t\t\tvnode->netfs.zero_point = status->size;\n+\t\t\t\tnetfs_write_zero_point(&vnode->netfs, status->size);\n \t\t\tinode_set_ctime_to_ts(inode, t);\n \t\t\tinode_set_atime_to_ts(inode, t);\n \t\t}\n@@ -709,7 +709,7 @@ int afs_getattr(struct mnt_idmap *idmap, const struct path *path,\n \t\t * it, but we need to give userspace the server's size.\n \t\t */\n \t\tif (S_ISDIR(inode->i_mode))\n-\t\t\tstat->size = vnode->netfs.remote_i_size;\n+\t\t\tstat->size = netfs_read_remote_i_size(&vnode->netfs);\n \t} while (read_seqretry(&vnode->cb_lock, seq));\n \n \treturn 0;\n@@ -889,7 +889,7 @@ int afs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,\n \t\t */\n \t\tif (!(attr->ia_valid & (supported & ~ATTR_SIZE & ~ATTR_MTIME)) &&\n \t\t attr->ia_size < i_size &&\n-\t\t attr->ia_size > vnode->netfs.remote_i_size) {\n+\t\t attr->ia_size > netfs_read_remote_i_size(&vnode->netfs)) {\n \t\t\ttruncate_setsize(inode, attr->ia_size);\n \t\t\tnetfs_resize_file(&vnode->netfs, size, false);\n \t\t\tfscache_resize_cookie(afs_vnode_cache(vnode),\ndiff --git a/fs/afs/write.c b/fs/afs/write.c\nindex 93ad86ff3345..a82ad996dc22 100644\n--- a/fs/afs/write.c\n+++ b/fs/afs/write.c\n@@ -143,7 +143,7 @@ static void afs_issue_write_worker(struct work_struct *work)\n \tafs_begin_vnode_operation(op);\n \n \top->store.write_iter\t= &subreq->io_iter;\n-\top->store.i_size\t= umax(pos + len, vnode->netfs.remote_i_size);\n+\top->store.i_size\t= umax(pos + len, netfs_read_remote_i_size(&vnode->netfs));\n \top->mtime\t\t= inode_get_mtime(&vnode->netfs.inode);\n \n \tafs_wait_for_operation(op);\ndiff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c\nindex 98bfec0af0e1..4d6dfcffba78 100644\n--- a/fs/netfs/buffered_read.c\n+++ b/fs/netfs/buffered_read.c\n@@ -236,7 +236,8 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq,\n \t\tsource = netfs_cache_prepare_read(rreq, subreq, rreq->i_size);\n \t\tsubreq->source = source;\n \t\tif (source == NETFS_DOWNLOAD_FROM_SERVER) {\n-\t\t\tunsigned long long zp = umin(ictx->zero_point, rreq->i_size);\n+\t\t\tunsigned long long zero_point = netfs_read_zero_point(ictx);\n+\t\t\tunsigned long long zp = umin(zero_point, rreq->i_size);\n \t\t\tsize_t len = subreq->len;\n \n \t\t\tif (unlikely(rreq->origin == NETFS_READ_SINGLE))\n@@ -252,7 +253,7 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq,\n \t\t\t\tpr_err(\"ZERO-LEN READ: R=%08x[%x] l=%zx/%zx s=%llx z=%llx i=%llx\",\n \t\t\t\t rreq->debug_id, subreq->debug_index,\n \t\t\t\t subreq->len, size,\n-\t\t\t\t subreq->start, ictx->zero_point, rreq->i_size);\n+\t\t\t\t subreq->start, zero_point, rreq->i_size);\n \t\t\t\tbreak;\n \t\t\t}\n \t\t\tsubreq->len = len;\ndiff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c\nindex 0ca8e922790d..c840f5448178 100644\n--- a/fs/netfs/buffered_write.c\n+++ b/fs/netfs/buffered_write.c\n@@ -228,7 +228,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,\n \t\t * server would just return a block of zeros or a short read if\n \t\t * we try to read it.\n \t\t */\n-\t\tif (fpos >= ctx->zero_point) {\n+\t\tif (fpos >= netfs_read_zero_point(ctx)) {\n \t\t\tfolio_zero_segment(folio, 0, offset);\n \t\t\tcopied = copy_folio_from_iter_atomic(folio, offset, part, iter);\n \t\t\tif (unlikely(copied == 0))\ndiff --git a/fs/netfs/direct_write.c b/fs/netfs/direct_write.c\nindex f9ab69de3e29..96c1dad04168 100644\n--- a/fs/netfs/direct_write.c\n+++ b/fs/netfs/direct_write.c\n@@ -376,8 +376,8 @@ ssize_t netfs_unbuffered_write_iter(struct kiocb *iocb, struct iov_iter *from)\n \tif (ret < 0)\n \t\tgoto out;\n \tend = iocb->ki_pos + iov_iter_count(from);\n-\tif (end > ictx->zero_point)\n-\t\tictx->zero_point = end;\n+\tif (end > netfs_read_zero_point(ictx))\n+\t\tnetfs_write_zero_point(ictx, end);\n \n \tfscache_invalidate(netfs_i_cookie(ictx), NULL, i_size_read(inode),\n \t\t\t FSCACHE_INVAL_DIO_WRITE);\ndiff --git a/fs/netfs/misc.c b/fs/netfs/misc.c\nindex 8b457124b0e3..1f09733e50a8 100644\n--- a/fs/netfs/misc.c\n+++ b/fs/netfs/misc.c\n@@ -221,8 +221,8 @@ void netfs_invalidate_folio(struct folio *folio, size_t offset, size_t length)\n \t\tunsigned long long fpos = folio_pos(folio), end;\n \n \t\tend = umin(fpos + flen, i_size);\n-\t\tif (fpos < i_size && end > ctx->zero_point)\n-\t\t\tctx->zero_point = end;\n+\t\tif (fpos < i_size && end > netfs_read_zero_point(ctx))\n+\t\t\tnetfs_write_zero_point(ctx, end);\n \t}\n \n \tfolio_wait_private_2(folio); /* [DEPRECATED] */\n@@ -297,14 +297,15 @@ EXPORT_SYMBOL(netfs_invalidate_folio);\n bool netfs_release_folio(struct folio *folio, gfp_t gfp)\n {\n \tstruct netfs_inode *ctx = netfs_inode(folio_inode(folio));\n-\tunsigned long long end;\n+\tunsigned long long remote_i_size, zero_point, end;\n \n \tif (folio_test_dirty(folio))\n \t\treturn false;\n \n-\tend = umin(folio_next_pos(folio), ctx->remote_i_size);\n-\tif (end > ctx->zero_point)\n-\t\tctx->zero_point = end;\n+\tnetfs_read_sizes(ctx, &remote_i_size, &zero_point);\n+\tend = umin(folio_next_pos(folio), remote_i_size);\n+\tif (end > zero_point)\n+\t\tnetfs_write_zero_point(ctx, end);\n \n \tif (folio_test_private(folio))\n \t\treturn false;\ndiff --git a/fs/netfs/write_collect.c b/fs/netfs/write_collect.c\nindex b194447f4b11..4718e5174d65 100644\n--- a/fs/netfs/write_collect.c\n+++ b/fs/netfs/write_collect.c\n@@ -69,8 +69,7 @@ int netfs_folio_written_back(struct folio *folio)\n \t\tunsigned long long fend;\n \n \t\tfend = folio_pos(folio) + finfo->dirty_offset + finfo->dirty_len;\n-\t\tif (fend > ictx->zero_point)\n-\t\t\tictx->zero_point = fend;\n+\t\tnetfs_push_back_zero_point(ictx, fend);\n \n \t\tfolio_detach_private(folio);\n \t\tgroup = finfo->netfs_group;\ndiff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c\nindex 2025739f070a..382dccbc3507 100644\n--- a/fs/smb/client/cifsfs.c\n+++ b/fs/smb/client/cifsfs.c\n@@ -471,7 +471,8 @@ cifs_alloc_inode(struct super_block *sb)\n \tspin_lock_init(&cifs_inode->writers_lock);\n \tcifs_inode->writers = 0;\n \tcifs_inode->netfs.inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */\n-\tcifs_inode->netfs.remote_i_size = 0;\n+\tcifs_inode->netfs._remote_i_size = 0;\n+\tcifs_inode->netfs._zero_point = 0;\n \tcifs_inode->uniqueid = 0;\n \tcifs_inode->createtime = 0;\n \tcifs_inode->epoch = 0;\n@@ -1340,7 +1341,7 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,\n \tstruct cifsFileInfo *smb_file_src = src_file->private_data;\n \tstruct cifsFileInfo *smb_file_target = dst_file->private_data;\n \tstruct cifs_tcon *target_tcon, *src_tcon;\n-\tunsigned long long destend, fstart, fend, old_size, new_size;\n+\tunsigned long long destend, fstart, fend, old_size, new_size, zero_point;\n \tunsigned int xid;\n \tint rc;\n \n@@ -1384,7 +1385,7 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,\n \t * Advance the EOF marker after the flush above to the end of the range\n \t * if it's short of that.\n \t */\n-\tif (src_cifsi->netfs.remote_i_size < off + len) {\n+\tif (netfs_read_remote_i_size(&src_cifsi->netfs) < off + len) {\n \t\trc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len);\n \t\tif (rc < 0)\n \t\t\tgoto unlock;\n@@ -1405,9 +1406,10 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,\n \trc = cifs_flush_folio(target_inode, destend, &fstart, &fend, false);\n \tif (rc)\n \t\tgoto unlock;\n-\tif (fend > target_cifsi->netfs.zero_point)\n-\t\ttarget_cifsi->netfs.zero_point = fend + 1;\n-\told_size = target_cifsi->netfs.remote_i_size;\n+\n+\tnetfs_read_sizes(&target_cifsi->netfs, &old_size, &zero_point);\n+\tif (fend > zero_point)\n+\t\tnetfs_write_zero_point(&target_cifsi->netfs, fend + 1);\n \n \t/* Discard all the folios that overlap the destination region. */\n \tcifs_dbg(FYI, \"about to discard pages %llx-%llx\\n\", fstart, fend);\n@@ -1439,8 +1441,8 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,\n \t\t\t\t\trc = -EINVAL;\n \t\t\t}\n \t\t}\n-\t\tif (rc == 0 && new_size > target_cifsi->netfs.zero_point)\n-\t\t\ttarget_cifsi->netfs.zero_point = new_size;\n+\t\tif (rc == 0)\n+\t\t\tnetfs_push_back_zero_point(&target_cifsi->netfs, new_size);\n \t}\n \n \t/* force revalidate of size and timestamps of target file now\n@@ -1511,7 +1513,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,\n \t * Advance the EOF marker after the flush above to the end of the range\n \t * if it's short of that.\n \t */\n-\tif (src_cifsi->netfs.remote_i_size < off + len) {\n+\tif (netfs_read_remote_i_size(&src_cifsi->netfs) < off + len) {\n \t\trc = cifs_precopy_set_eof(src_inode, src_cifsi, src_tcon, xid, off + len);\n \t\tif (rc < 0)\n \t\t\tgoto unlock;\n@@ -1539,8 +1541,8 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,\n \t\t\tfscache_resize_cookie(cifs_inode_cookie(target_inode),\n \t\t\t\t\t i_size_read(target_inode));\n \t\t}\n-\t\tif (rc > 0 && destoff + rc > target_cifsi->netfs.zero_point)\n-\t\t\ttarget_cifsi->netfs.zero_point = destoff + rc;\n+\t\tif (rc > 0)\n+\t\t\tnetfs_push_back_zero_point(&target_cifsi->netfs, destoff + rc);\n \t}\n \n \tfile_accessed(src_file);\ndiff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c\nindex 3990a9012264..102dd9dde760 100644\n--- a/fs/smb/client/cifssmb.c\n+++ b/fs/smb/client/cifssmb.c\n@@ -1538,7 +1538,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)\n \t} else {\n \t\tsize_t trans = rdata->subreq.transferred + rdata->got_bytes;\n \t\tif (trans < rdata->subreq.len &&\n-\t\t rdata->subreq.start + trans >= ictx->remote_i_size) {\n+\t\t rdata->subreq.start + trans >= netfs_read_remote_i_size(ictx)) {\n \t\t\trdata->result = 0;\n \t\t\t__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);\n \t\t} else if (rdata->got_bytes > 0) {\ndiff --git a/fs/smb/client/file.c b/fs/smb/client/file.c\nindex 5d5b49468aff..ec1b1198642c 100644\n--- a/fs/smb/client/file.c\n+++ b/fs/smb/client/file.c\n@@ -2502,16 +2502,19 @@ void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t\n {\n \tstruct netfs_io_request *wreq = wdata->rreq;\n \tstruct netfs_inode *ictx = netfs_inode(wreq->inode);\n+\tunsigned long long remote_i_size, zero_point;\n \tloff_t wrend;\n \n \tif (result > 0) {\n+\t\tnetfs_read_sizes(ictx, &remote_i_size, &zero_point);\n+\n \t\twrend = wdata->subreq.start + wdata->subreq.transferred + result;\n \n-\t\tif (wrend > ictx->zero_point &&\n+\t\tif (wrend > zero_point &&\n \t\t (wdata->rreq->origin == NETFS_UNBUFFERED_WRITE ||\n \t\t wdata->rreq->origin == NETFS_DIO_WRITE))\n-\t\t\tictx->zero_point = wrend;\n-\t\tif (wrend > ictx->remote_i_size)\n+\t\t\tnetfs_write_zero_point(ictx, wrend);\n+\t\tif (wrend > remote_i_size)\n \t\t\tnetfs_resize_file(ictx, wrend, true);\n \t}\n \ndiff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c\nindex 24040909d184..4189741d63fe 100644\n--- a/fs/smb/client/inode.c\n+++ b/fs/smb/client/inode.c\n@@ -119,7 +119,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)\n \tfattr->cf_mtime = timestamp_truncate(fattr->cf_mtime, inode);\n \tmtime = inode_get_mtime(inode);\n \tif (timespec64_equal(&mtime, &fattr->cf_mtime) &&\n-\t cifs_i->netfs.remote_i_size == fattr->cf_eof) {\n+\t netfs_read_remote_i_size(&cifs_i->netfs) == fattr->cf_eof) {\n \t\tcifs_dbg(FYI, \"%s: inode %llu is unchanged\\n\",\n \t\t\t __func__, cifs_i->uniqueid);\n \t\treturn;\n@@ -174,7 +174,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,\n \t\treturn -ESTALE;\n \t}\n \tif (inode_state_read_once(inode) & I_NEW)\n-\t\tCIFS_I(inode)->netfs.zero_point = fattr->cf_eof;\n+\t\tnetfs_write_zero_point(&CIFS_I(inode)->netfs, fattr->cf_eof);\n \n \tcifs_revalidate_cache(inode, fattr);\n \n@@ -212,7 +212,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr,\n \telse\n \t\tclear_bit(CIFS_INO_DELETE_PENDING, &cifs_i->flags);\n \n-\tcifs_i->netfs.remote_i_size = fattr->cf_eof;\n+\tnetfs_write_remote_i_size(&cifs_i->netfs, fattr->cf_eof);\n \t/*\n \t * Can't safely change the file size here if the client is writing to\n \t * it due to potential races.\n@@ -2772,7 +2772,8 @@ cifs_revalidate_mapping(struct inode *inode)\n \t\tif (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_RW_CACHE)\n \t\t\tgoto skip_invalidate;\n \n-\t\tcifs_inode->netfs.zero_point = cifs_inode->netfs.remote_i_size;\n+\t\tnetfs_write_zero_point(&cifs_inode->netfs,\n+\t\t\t\t netfs_read_remote_i_size(&cifs_inode->netfs));\n \t\trc = filemap_invalidate_inode(inode, true, 0, LLONG_MAX);\n \t\tif (rc) {\n \t\t\tcifs_dbg(VFS, \"%s: invalidate inode %p failed with rc %d\\n\",\ndiff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c\nindex be22bbc4a65a..d88682e89ec0 100644\n--- a/fs/smb/client/readdir.c\n+++ b/fs/smb/client/readdir.c\n@@ -143,7 +143,8 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,\n \t\t\t\t\t\tfattr->cf_rdev = inode->i_rdev;\n \t\t\t\t\t\tfattr->cf_uid = inode->i_uid;\n \t\t\t\t\t\tfattr->cf_gid = inode->i_gid;\n-\t\t\t\t\t\tfattr->cf_eof = CIFS_I(inode)->netfs.remote_i_size;\n+\t\t\t\t\t\tfattr->cf_eof =\n+\t\t\t\t\t\t\tnetfs_read_remote_i_size(&CIFS_I(inode)->netfs);\n \t\t\t\t\t\tfattr->cf_symlink_target = NULL;\n \t\t\t\t\t} else {\n \t\t\t\t\t\tCIFS_I(inode)->time = 0;\ndiff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c\nindex 509fcea28a42..5550d9c55ab2 100644\n--- a/fs/smb/client/smb2ops.c\n+++ b/fs/smb/client/smb2ops.c\n@@ -3398,7 +3398,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,\n \tfilemap_invalidate_lock(inode->i_mapping);\n \n \ti_size = i_size_read(inode);\n-\tremote_size = ictx->remote_i_size;\n+\tremote_size = netfs_read_remote_i_size(ictx);\n \tif (offset + len >= remote_size && offset < i_size) {\n \t\tunsigned long long top = umin(offset + len, i_size);\n \n@@ -3433,8 +3433,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,\n \t\tif (rc >= 0) {\n \t\t\ttruncate_setsize(inode, new_size);\n \t\t\tnetfs_resize_file(&cifsi->netfs, new_size, true);\n-\t\t\tif (offset < cifsi->netfs.zero_point)\n-\t\t\t\tcifsi->netfs.zero_point = offset;\n+\t\t\tif (offset < netfs_read_zero_point(&cifsi->netfs))\n+\t\t\t\tnetfs_write_zero_point(&cifsi->netfs, offset);\n \t\t\tfscache_resize_cookie(cifs_inode_cookie(inode), new_size);\n \t\t}\n \t}\n@@ -3500,13 +3500,13 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,\n \t * EOF update will end up in the wrong place.\n \t */\n \ti_size = i_size_read(inode);\n-\tremote_i_size = netfs_inode(inode)->remote_i_size;\n+\tremote_i_size = netfs_read_remote_i_size(netfs_inode(inode));\n \tif (end > remote_i_size && i_size > remote_i_size) {\n \t\tunsigned long long extend_to = umin(end, i_size);\n \t\trc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,\n \t\t\t\t cfile->fid.volatile_fid, cfile->pid, extend_to);\n \t\tif (rc >= 0)\n-\t\t\tnetfs_inode(inode)->remote_i_size = extend_to;\n+\t\t\tnetfs_write_remote_i_size(netfs_inode(inode), extend_to);\n \t}\n \n unlock:\n@@ -3788,7 +3788,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,\n \t\tgoto out_2;\n \n \ttruncate_pagecache_range(inode, off, old_eof);\n-\tictx->zero_point = old_eof;\n+\tnetfs_write_zero_point(ictx, old_eof);\n \tnetfs_wait_for_outstanding_io(inode);\n \n \trc = smb2_copychunk_range(xid, cfile, cfile, off + len,\n@@ -3806,7 +3806,7 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,\n \n \ttruncate_setsize(inode, new_eof);\n \tnetfs_resize_file(&cifsi->netfs, new_eof, true);\n-\tictx->zero_point = new_eof;\n+\tnetfs_write_zero_point(ictx, new_eof);\n \tfscache_resize_cookie(cifs_inode_cookie(inode), new_eof);\n out_2:\n \tfilemap_invalidate_unlock(inode->i_mapping);\n@@ -3855,7 +3855,7 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,\n \trc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len);\n \tif (rc < 0)\n \t\tgoto out_2;\n-\tcifsi->netfs.zero_point = new_eof;\n+\tnetfs_write_zero_point(&cifsi->netfs, new_eof);\n \n \trc = smb3_zero_data(file, tcon, off, len, xid);\n \tif (rc < 0)\ndiff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c\nindex 5188218c25be..8892fdd39474 100644\n--- a/fs/smb/client/smb2pdu.c\n+++ b/fs/smb/client/smb2pdu.c\n@@ -4709,7 +4709,7 @@ smb2_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)\n \t} else {\n \t\tsize_t trans = rdata->subreq.transferred + rdata->got_bytes;\n \t\tif (trans < rdata->subreq.len &&\n-\t\t rdata->subreq.start + trans >= ictx->remote_i_size) {\n+\t\t rdata->subreq.start + trans >= netfs_read_remote_i_size(ictx)) {\n \t\t\t__set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags);\n \t\t\trdata->result = 0;\n \t\t}\ndiff --git a/include/linux/netfs.h b/include/linux/netfs.h\nindex 62a528f90666..d72bc2f11734 100644\n--- a/include/linux/netfs.h\n+++ b/include/linux/netfs.h\n@@ -62,8 +62,8 @@ struct netfs_inode {\n \tstruct fscache_cookie\t*cache;\n #endif\n \tstruct mutex\t\twb_lock;\t/* Writeback serialisation */\n-\tloff_t\t\t\tremote_i_size;\t/* Size of the remote file */\n-\tloff_t\t\t\tzero_point;\t/* Size after which we assume there's no data\n+\tloff_t\t\t\t_remote_i_size;\t/* Size of the remote file */\n+\tloff_t\t\t\t_zero_point;\t/* Size after which we assume there's no data\n \t\t\t\t\t\t * on the server */\n \tatomic_t\t\tio_count;\t/* Number of outstanding reqs */\n \tunsigned long\t\tflags;\n@@ -474,6 +474,260 @@ static inline struct netfs_inode *netfs_inode(struct inode *inode)\n \treturn container_of(inode, struct netfs_inode, inode);\n }\n \n+/**\n+ * netfs_read_remote_i_size - Read remote_i_size safely\n+ * @ictx: The inode context to access\n+ *\n+ * Read remote_i_size safely without the potential for tearing on 32-bit\n+ * arches.\n+ *\n+ * NOTE: in a 32bit arch with a preemptable kernel and an UP compile the\n+ * i_size_read/write must be atomic with respect to the local cpu (unlike with\n+ * preempt disabled), but they don't need to be atomic with respect to other\n+ * cpus like in true SMP (so they need either to either locally disable irq\n+ * around the read or for example on x86 they can be still implemented as a\n+ * cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit\n+ * archs it makes no difference if preempt is enabled or not.\n+ */\n+static inline unsigned long long netfs_read_remote_i_size(const struct netfs_inode *ictx)\n+{\n+\tunsigned long long remote_i_size;\n+\n+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)\n+\tconst struct inode *inode = &ictx->inode;\n+\tunsigned int seq;\n+\n+\tdo {\n+\t\tseq = read_seqcount_begin(&inode->i_size_seqcount);\n+\t\tremote_i_size = ictx->_remote_i_size;\n+\t} while (read_seqcount_retry(&inode->i_size_seqcount, seq));\n+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)\n+\tpreempt_disable();\n+\tremote_i_size = ictx->_remote_i_size;\n+\tpreempt_enable();\n+#else\n+\t/* Pairs with smp_store_release() in netfs_write_remote_i_size() */\n+\tremote_i_size = smp_load_acquire(&ictx->_remote_i_size);\n+#endif\n+\treturn remote_i_size;\n+}\n+\n+/*\n+ * netfs_write_remote_i_size - Set remote_i_size safely\n+ * @ictx: The inode context to access\n+ * @remote_i_size: The new value for the size of the file on the server\n+ *\n+ * Set remote_i_size safely without the potential for tearing on 32-bit arches.\n+ *\n+ * NOTE: unlike netfs_read_remote_i_size(), netfs_write_remote_i_size() does\n+ * need locking around it (normally i_rwsem), otherwise on 32bit/SMP an update\n+ * of i_size_seqcount can be lost, resulting in subsequent i_size_read() calls\n+ * spinning forever.\n+ */\n+static inline void netfs_write_remote_i_size(struct netfs_inode *ictx,\n+\t\t\t\t\t unsigned long long remote_i_size)\n+{\n+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)\n+\tstruct inode *inode = &ictx->inode;\n+\n+\tpreempt_disable();\n+\twrite_seqcount_begin(&inode->i_size_seqcount);\n+\tictx->_remote_i_size = remote_i_size;\n+\twrite_seqcount_end(&inode->i_size_seqcount);\n+\tpreempt_enable();\n+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)\n+\tpreempt_disable();\n+\tictx->_remote_i_size = remote_i_size;\n+\tpreempt_enable();\n+#else\n+\t/*\n+\t * Pairs with smp_load_acquire() in netfs_read_remote_i_size() to\n+\t * ensure changes related to inode size (such as page contents) are\n+\t * visible before we see the changed inode size.\n+\t */\n+\tsmp_store_release(&ictx->_remote_i_size, remote_i_size);\n+#endif\n+}\n+\n+/**\n+ * netfs_read_zero_point - Read zero_point safely\n+ * @ictx: The inode context to access\n+ *\n+ * Read zero_point safely without the potential for tearing on 32-bit\n+ * arches.\n+ *\n+ * NOTE: in a 32bit arch with a preemptable kernel and an UP compile the\n+ * i_size_read/write must be atomic with respect to the local cpu (unlike with\n+ * preempt disabled), but they don't need to be atomic with respect to other\n+ * cpus like in true SMP (so they need either to either locally disable irq\n+ * around the read or for example on x86 they can be still implemented as a\n+ * cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit\n+ * archs it makes no difference if preempt is enabled or not.\n+ */\n+static inline unsigned long long netfs_read_zero_point(const struct netfs_inode *ictx)\n+{\n+\tunsigned long long zero_point;\n+\n+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)\n+\tconst struct inode *inode = &ictx->inode;\n+\tunsigned int seq;\n+\n+\tdo {\n+\t\tseq = read_seqcount_begin(&inode->i_size_seqcount);\n+\t\tzero_point = ictx->_zero_point;\n+\t} while (read_seqcount_retry(&inode->i_size_seqcount, seq));\n+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)\n+\tpreempt_disable();\n+\tzero_point = ictx->_zero_point;\n+\tpreempt_enable();\n+#else\n+\t/* Pairs with smp_store_release() in netfs_write_zero_point() */\n+\tzero_point = smp_load_acquire(&ictx->_zero_point);\n+#endif\n+\treturn zero_point;\n+}\n+\n+/*\n+ * netfs_write_zero_point - Set zero_point safely\n+ * @ictx: The inode context to access\n+ * @zero_point: The new value for the point beyond which the server has no data\n+ *\n+ * Set zero_point safely without the potential for tearing on 32-bit arches.\n+ *\n+ * NOTE: unlike netfs_read_zero_point(), netfs_write_zero_point() does need\n+ * locking around it (normally i_rwsem), otherwise on 32bit/SMP an update of\n+ * i_size_seqcount can be lost, resulting in subsequent read calls spinning\n+ * forever.\n+ */\n+static inline void netfs_write_zero_point(struct netfs_inode *ictx,\n+\t\t\t\t\t unsigned long long zero_point)\n+{\n+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)\n+\tstruct inode *inode = &ictx->inode;\n+\n+\tpreempt_disable();\n+\twrite_seqcount_begin(&inode->i_size_seqcount);\n+\tictx->_zero_point = zero_point;\n+\twrite_seqcount_end(&inode->i_size_seqcount);\n+\tpreempt_enable();\n+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)\n+\tpreempt_disable();\n+\tictx->_zero_point = zero_point;\n+\tpreempt_enable();\n+#else\n+\t/*\n+\t * Pairs with smp_load_acquire() in netfs_read_zero_point() to\n+\t * ensure changes related to inode size (such as page contents) are\n+\t * visible before we see the changed inode size.\n+\t */\n+\tsmp_store_release(&ictx->_zero_point, zero_point);\n+#endif\n+}\n+\n+/**\n+ * netfs_push_back_zero_point - Push back the zero point if unknown data now beyond it\n+ * ictx: The inode context to access\n+ * to: The end of a new region of unknown data\n+ *\n+ * Move back the zero_point if we cause a region of unknown data to appear\n+ * beyond it (such as doing a copy_file_range).\n+ */\n+static inline void netfs_push_back_zero_point(struct netfs_inode *ictx,\n+\t\t\t\t\t unsigned long long to)\n+{\n+\tif (to > netfs_read_zero_point(ictx))\n+\t\tnetfs_write_zero_point(ictx, to);\n+}\n+\n+/**\n+ * netfs_read_sizes - Read remote_i_size and zero_point safely\n+ * @ictx: The inode context to access\n+ * @remote_i_size: Where to return the size of the file on the server\n+ * @zero_point: Where to return the the point beyond which the server has no data\n+ *\n+ * Read remote_i_size and zero_point safely without the potential for tearing\n+ * on 32-bit arches.\n+ *\n+ * NOTE: in a 32bit arch with a preemptable kernel and an UP compile the\n+ * i_size_read/write must be atomic with respect to the local cpu (unlike with\n+ * preempt disabled), but they don't need to be atomic with respect to other\n+ * cpus like in true SMP (so they need either to either locally disable irq\n+ * around the read or for example on x86 they can be still implemented as a\n+ * cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit\n+ * archs it makes no difference if preempt is enabled or not.\n+ */\n+static inline void netfs_read_sizes(const struct netfs_inode *ictx,\n+\t\t\t\t unsigned long long *remote_i_size,\n+\t\t\t\t unsigned long long *zero_point)\n+{\n+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)\n+\tconst struct inode *inode = &ictx->inode;\n+\tunsigned int seq;\n+\n+\tdo {\n+\t\tseq = read_seqcount_begin(&inode->i_size_seqcount);\n+\t\t*remote_i_size = ictx->_remote_i_size;\n+\t\t*zero_point = ictx->_zero_point;\n+\t} while (read_seqcount_retry(&inode->i_size_seqcount, seq));\n+\treturn zero_point;\n+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)\n+\tunsigned long long zero_point;\n+\n+\tpreempt_disable();\n+\t*remote_i_size = ictx->_remote_i_size;\n+\t*zero_point = ictx->_zero_point;\n+\tpreempt_enable();\n+#else\n+\t/* Pairs with smp_store_release() in netfs_write_zero_point() */\n+\t*remote_i_size = smp_load_acquire(&ictx->_remote_i_size);\n+\t*zero_point = smp_load_acquire(&ictx->_zero_point);\n+#endif\n+}\n+\n+/*\n+ * netfs_write_sizes - Set remote_i_size and zero_point safely\n+ * @ictx: The inode context to access\n+ * @remote_i_size: The new value for the size of the file on the server\n+ * @zero_point: The new value for the point beyond which the server has no data\n+ *\n+ * Set both remote_i_size and zero_point safely without the potential for\n+ * tearing on 32-bit arches.\n+ *\n+ * NOTE: unlike netfs_read_zero_point(), netfs_write_zero_point() does need\n+ * locking around it (normally i_rwsem), otherwise on 32bit/SMP an update of\n+ * i_size_seqcount can be lost, resulting in subsequent read calls spinning\n+ * forever.\n+ */\n+static inline void netfs_write_sizes(struct netfs_inode *ictx,\n+\t\t\t\t unsigned long long remote_i_size,\n+\t\t\t\t unsigned long long zero_point)\n+{\n+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)\n+\tstruct inode *inode = &ictx->inode;\n+\n+\tpreempt_disable();\n+\twrite_seqcount_begin(&inode->i_size_seqcount);\n+\tictx->_remote_i_size = remote_i_size;\n+\tictx->_zero_point = zero_point;\n+\twrite_seqcount_end(&inode->i_size_seqcount);\n+\tpreempt_enable();\n+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)\n+\tpreempt_disable();\n+\tictx->_remote_i_size = remote_i_size;\n+\tictx->_zero_point = zero_point;\n+\tpreempt_enable();\n+#else\n+\t/*\n+\t * Pairs with smp_load_acquire() in netfs_read_remote_i_size and\n+\t * netfs_read_zero_point() to ensure changes related to inode size\n+\t * (such as page contents) are visible before we see the changed inode\n+\t * size.\n+\t */\n+\tsmp_store_release(&ictx->_remote_i_size, remote_i_size);\n+\tsmp_store_release(&ictx->_zero_point, zero_point);\n+#endif\n+}\n+\n /**\n * netfs_inode_init - Initialise a netfslib inode context\n * @ctx: The netfs inode to initialise\n@@ -488,8 +742,8 @@ static inline void netfs_inode_init(struct netfs_inode *ctx,\n \t\t\t\t bool use_zero_point)\n {\n \tctx->ops = ops;\n-\tctx->remote_i_size = i_size_read(&ctx->inode);\n-\tctx->zero_point = LLONG_MAX;\n+\tctx->_remote_i_size = i_size_read(&ctx->inode);\n+\tctx->_zero_point = LLONG_MAX;\n \tctx->flags = 0;\n \tatomic_set(&ctx->io_count, 0);\n #if IS_ENABLED(CONFIG_FSCACHE)\n@@ -498,7 +752,7 @@ static inline void netfs_inode_init(struct netfs_inode *ctx,\n \tmutex_init(&ctx->wb_lock);\n \t/* ->releasepage() drives zero_point */\n \tif (use_zero_point) {\n-\t\tctx->zero_point = ctx->remote_i_size;\n+\t\tctx->_zero_point = ctx->_remote_i_size;\n \t\tmapping_set_release_always(ctx->inode.i_mapping);\n \t}\n }\n@@ -511,13 +765,40 @@ static inline void netfs_inode_init(struct netfs_inode *ctx,\n *\n * Inform the netfs lib that a file got resized so that it can adjust its state.\n */\n-static inline void netfs_resize_file(struct netfs_inode *ctx, loff_t new_i_size,\n+static inline void netfs_resize_file(struct netfs_inode *ictx,\n+\t\t\t\t unsigned long long new_i_size,\n \t\t\t\t bool changed_on_server)\n {\n+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)\n+\tstruct inode *inode = &ictx->inode;\n+\n+\tpreempt_disable();\n+\twrite_seqcount_begin(&inode->i_size_seqcount);\n+\tif (changed_on_server)\n+\t\tictx->_remote_i_size = new_i_size;\n+\tif (new_i_size < ictx->_zero_point)\n+\t\tictx->_zero_point = new_i_size;\n+\twrite_seqcount_end(&inode->i_size_seqcount);\n+\tpreempt_enable();\n+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)\n+\tpreempt_disable();\n \tif (changed_on_server)\n-\t\tctx->remote_i_size = new_i_size;\n-\tif (new_i_size < ctx->zero_point)\n-\t\tctx->zero_point = new_i_size;\n+\t\tictx->_remote_i_size = new_i_size;\n+\tif (new_i_size < ictx->_zero_point)\n+\t\tictx->_zero_point = new_i_size;\n+\tpreempt_enable();\n+#else\n+\t/*\n+\t * Pairs with smp_load_acquire() in netfs_read_remote_i_size and\n+\t * netfs_read_zero_point() to ensure changes related to inode size\n+\t * (such as page contents) are visible before we see the changed inode\n+\t * size.\n+\t */\n+\tif (changed_on_server)\n+\t\tsmp_store_release(&ictx->_remote_i_size, new_i_size);\n+\tif (new_i_size < ictx->_zero_point)\n+\t\tsmp_store_release(&ictx->_zero_point, new_i_size);\n+#endif\n }\n \n /**\n", "prefixes": [ "09/11" ] }