* [PATCH v2 0/4] cifs: follow-on fixes after fscache_resize_cookie() consolidation
@ 2026-07-31 15:34 Frank Sorenson
2026-07-31 15:34 ` [PATCH v2 1/4] cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC Frank Sorenson
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Frank Sorenson @ 2026-07-31 15:34 UTC (permalink / raw)
To: linux-cifs, pc, stfrench, hehuiwen
After commit fa724e235cfd ("cifs: add fscache_resize_cookie() to
cifs_setsize()") consolidated fscache cookie resizing into cifs_setsize(),
two further fixes are needed and two dead-code blocks became removable.
Patch 1 fixes cifs_do_truncate() (O_TRUNC via cifs_open()). That path
runs without i_rwsem, so it cannot use the locked resize path.
cifs_invalidate_cache() is the correct alternative: it works without the
lock and ensures stale cached data is not served once the cookie is later
activated.
Patch 2 addresses a race identified during review: cifs_setsize() calls
fscache_resize_cookie() without i_rwsem, but another concurrent open may
already have the cookie active (IS_CACHING set), making fscache_resize_cookie()
a real operation requiring the lock. The fix strips fscache_resize_cookie()
from cifs_setsize() and introduces cifs_resize_file_locked(), which
temporarily activates the cookie with fscache_use_cookie(), performs the
resize under i_rwsem, then deactivates it. Callers that already hold
i_rwsem (cifs_file_set_size, smb2_duplicate_extents, smb3_simple_falloc)
switch to the wrapper; cifs_do_truncate() continues to use cifs_setsize()
followed by cifs_invalidate_cache() as established in patch 1.
Patches 3 and 4 remove dead code. Patch 3 removes a caller-side
truncate_setsize() + fscache_resize_cookie() block from
cifs_remap_file_range() that became redundant once smb2_duplicate_extents()
started performing the full size update via cifs_setsize() under the
i_rwsem held by lock_two_nondirectories(). Patch 4 removes equivalent
dead blocks from cifs_setattr_unix() and cifs_setattr_nounix(): since
cifs_file_set_size() calls cifs_setsize() on success, i_size always equals
attrs->ia_size on the success path, making the subsequent size-inequality
blocks unreachable.
v2:
- Added patch 2 (cifs_resize_file_locked): based on review feedback
(Huiwen He) that the fscache cookie is not guaranteed to be quiescent
in cifs_do_truncate() - another concurrent open may already have it
active. The fix strips fscache_resize_cookie() from cifs_setsize() and
adds a locked wrapper for callers that hold i_rwsem.
- Patch 1 commit message updated: the original rationale (cookie is
always quiescent in cifs_do_truncate) was incorrect; the correct reason
is that i_rwsem cannot be held in that path.
- Patches 2-3 from v1 renumbered to 3-4 to place fixes before cleanups.
- Patches 3-4: add Reviewed-by from Huiwen He; otherwise unchanged from v1.
- All patches: add Reviewed-by from Paulo Alcantara.
Frank Sorenson (4):
cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC
cifs: add cifs_resize_file_locked() to guard fscache_resize_cookie()
under i_rwsem
cifs: remove redundant size-update block in cifs_remap_file_range()
cifs: remove dead size-update blocks in cifs_setattr_unix/nounix
fs/smb/client/cifsfs.c | 6 +-----
fs/smb/client/cifsfs.h | 1 +
fs/smb/client/file.c | 1 +
fs/smb/client/inode.c | 41 ++++++++++++++++++++++-------------------
fs/smb/client/smb2ops.c | 9 +++------
5 files changed, 28 insertions(+), 30 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/4] cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC
2026-07-31 15:34 [PATCH v2 0/4] cifs: follow-on fixes after fscache_resize_cookie() consolidation Frank Sorenson
@ 2026-07-31 15:34 ` Frank Sorenson
2026-07-31 22:37 ` David Howells
2026-07-31 15:34 ` [PATCH v2 2/4] cifs: add cifs_resize_file_locked() to guard fscache_resize_cookie() under i_rwsem Frank Sorenson
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Frank Sorenson @ 2026-07-31 15:34 UTC (permalink / raw)
To: linux-cifs, pc, stfrench, hehuiwen; +Cc: stable, David Howells, Paulo Alcantara
cifs_do_truncate() is invoked from cifs_open() without i_rwsem, so it
cannot use cifs_resize_file_locked() to perform a proper fscache cookie
resize. Instead, add cifs_invalidate_cache() after cifs_setsize().
cifs_invalidate_cache() calls fscache_invalidate(), which works without
holding i_rwsem: it unconditionally increments inval_counter and sets
FSCACHE_COOKIE_NO_DATA_TO_READ, ensuring that stale cached data is not
served once the cookie is later activated by fscache_use_cookie().
Truncation to zero leaves no valid cached data, making invalidation the
correct semantic here.
Fixes: fa724e235cfd ("cifs: add fscache_resize_cookie() to cifs_setsize()")
Cc: stable@vger.kernel.org
Cc: David Howells <dhowells@redhat.com>
Cc: Paulo Alcantara <pc@manguebit.com>
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
---
fs/smb/client/file.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index ac89c1ba56b1..389083f9ce00 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -1016,6 +1016,7 @@ static int cifs_do_truncate(const unsigned int xid, struct dentry *dentry)
if (!rc) {
netfs_resize_file(&cinode->netfs, 0, true);
cifs_setsize(inode, 0);
+ cifs_invalidate_cache(inode, 0);
}
}
if (cfile)
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 2/4] cifs: add cifs_resize_file_locked() to guard fscache_resize_cookie() under i_rwsem
2026-07-31 15:34 [PATCH v2 0/4] cifs: follow-on fixes after fscache_resize_cookie() consolidation Frank Sorenson
2026-07-31 15:34 ` [PATCH v2 1/4] cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC Frank Sorenson
@ 2026-07-31 15:34 ` Frank Sorenson
2026-08-02 14:53 ` Huiwen He
2026-07-31 15:34 ` [PATCH v2 3/4] cifs: remove redundant size-update block in cifs_remap_file_range() Frank Sorenson
2026-07-31 15:35 ` [PATCH v2 4/4] cifs: remove dead size-update blocks in cifs_setattr_unix/nounix Frank Sorenson
3 siblings, 1 reply; 9+ messages in thread
From: Frank Sorenson @ 2026-07-31 15:34 UTC (permalink / raw)
To: linux-cifs, pc, stfrench, hehuiwen; +Cc: stable, David Howells, Paulo Alcantara
cifs_setsize() calls fscache_resize_cookie() without holding i_rwsem.
When the fscache cookie is active (FSCACHE_COOKIE_IS_CACHING is set),
fscache_resize_cookie() performs a real resize that requires i_rwsem
held exclusively. If another file descriptor has the same inode open,
fscache_use_cookie() was already called from that cifs_open(), making
the cookie active. In that case, calling cifs_setsize() from
cifs_do_truncate() (invoked from cifs_open() without i_rwsem) races
against concurrent fscache I/O.
Strip fscache_resize_cookie() from cifs_setsize(), making it a pure
size/page-cache helper. Add cifs_resize_file_locked() for callers
that already hold i_rwsem: it calls netfs_resize_file() and
cifs_setsize(), then temporarily activates the cookie with
fscache_use_cookie() to perform the resize under the lock, then
deactivates it with cifs_fscache_unuse_inode_cookie(). Using
fscache_use_cookie() before the resize ensures correctness whether or
not another fd already holds the cookie active.
Switch cifs_file_set_size(), smb2_duplicate_extents(), and both size-
extension branches of smb3_simple_falloc() to the new wrapper; those
paths already hold i_rwsem via VFS setattr, lock_two_nondirectories(),
or cifs_fallocate() respectively. cifs_do_truncate() continues to
call cifs_setsize() followed by cifs_invalidate_cache(), since it runs
without i_rwsem.
Fixes: fa724e235cfd ("cifs: add fscache_resize_cookie() to cifs_setsize()")
Cc: stable@vger.kernel.org
Cc: David Howells <dhowells@redhat.com>
Cc: Paulo Alcantara <pc@manguebit.com>
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
---
fs/smb/client/cifsfs.h | 1 +
fs/smb/client/inode.c | 24 +++++++++++++++++++++---
fs/smb/client/smb2ops.c | 9 +++------
3 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
index 854e672a4e37..651670c19c2b 100644
--- a/fs/smb/client/cifsfs.h
+++ b/fs/smb/client/cifsfs.h
@@ -147,6 +147,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, struct file *src_file,
long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg);
void cifs_setsize(struct inode *inode, loff_t offset);
+void cifs_resize_file_locked(struct inode *inode, loff_t offset);
struct fs_context;
struct smb3_fs_context;
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 0afff761aab9..eaf27a9cf4f5 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -3059,7 +3059,26 @@ void cifs_setsize(struct inode *inode, loff_t offset)
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
truncate_pagecache(inode, offset);
netfs_wait_for_outstanding_io(inode);
- fscache_resize_cookie(cifs_inode_cookie(inode), offset);
+}
+
+void cifs_resize_file_locked(struct inode *inode, loff_t offset)
+{
+ struct fscache_cookie *cookie = cifs_inode_cookie(inode);
+
+ lockdep_assert_held_write(&inode->i_rwsem);
+
+ netfs_resize_file(netfs_inode(inode), offset, true);
+ cifs_setsize(inode, offset);
+
+ if (!cookie)
+ return;
+
+ fscache_use_cookie(cookie, true);
+ fscache_resize_cookie(cookie, offset);
+ cifs_fscache_unuse_inode_cookie(inode, true);
}
int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
@@ -3125,10 +3144,8 @@ int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
cifs_put_tlink(tlink);
set_size_out:
- if (rc == 0) {
- netfs_resize_file(&cifsInode->netfs, size, true);
- cifs_setsize(inode, size);
- }
+ if (rc == 0)
+ cifs_resize_file_locked(inode, size);
return rc;
}
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 192649fec25d..0e872d58fae7 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2222,8 +2222,7 @@ smb2_duplicate_extents(const unsigned int xid,
rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
if (rc)
goto duplicate_extents_out;
- netfs_resize_file(netfs_inode(inode), dest_off + len, true);
- cifs_setsize(inode, dest_off + len);
+ cifs_resize_file_locked(inode, dest_off + len);
}
rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
trgtfile->fid.volatile_fid,
@@ -3776,8 +3775,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
}
new_eof = off + len;
- netfs_resize_file(&cifsi->netfs, new_eof, true);
- cifs_setsize(inode, new_eof);
+ cifs_resize_file_locked(inode, new_eof);
qrc = SMB2_query_info(xid, tcon,
cfile->fid.persistent_fid,
@@ -3825,8 +3823,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
if (rc)
goto out;
- netfs_resize_file(&cifsi->netfs, new_eof, true);
- cifs_setsize(inode, new_eof);
+ cifs_resize_file_locked(inode, new_eof);
qrc = SMB2_query_info(xid, tcon,
cfile->fid.persistent_fid,
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 3/4] cifs: remove redundant size-update block in cifs_remap_file_range()
2026-07-31 15:34 [PATCH v2 0/4] cifs: follow-on fixes after fscache_resize_cookie() consolidation Frank Sorenson
2026-07-31 15:34 ` [PATCH v2 1/4] cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC Frank Sorenson
2026-07-31 15:34 ` [PATCH v2 2/4] cifs: add cifs_resize_file_locked() to guard fscache_resize_cookie() under i_rwsem Frank Sorenson
@ 2026-07-31 15:34 ` Frank Sorenson
2026-07-31 15:35 ` [PATCH v2 4/4] cifs: remove dead size-update blocks in cifs_setattr_unix/nounix Frank Sorenson
3 siblings, 0 replies; 9+ messages in thread
From: Frank Sorenson @ 2026-07-31 15:34 UTC (permalink / raw)
To: linux-cifs, pc, stfrench, hehuiwen
cifs_remap_file_range() acquires i_rwsem on both inodes via
lock_two_nondirectories() before calling smb2_duplicate_extents().
cifs_setsize() (called inside smb2_duplicate_extents() when the clone
extends the file) therefore already runs under the lock, meaning the
fscache_resize_cookie() added to cifs_setsize() by commit fa724e235cfd
("cifs: add fscache_resize_cookie() to cifs_setsize()") is correctly
serialised for this path without further changes.
That same commit made the caller-side block:
if (rc == 0 && new_size > i_size) {
truncate_setsize(target_inode, new_size);
fscache_resize_cookie(cifs_inode_cookie(target_inode), new_size);
}
redundant: smb2_duplicate_extents() already performs the full size update
via cifs_setsize() when the operation extends the file. Remove the
now-dead block.
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
---
fs/smb/client/cifsfs.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 1788d93a2522..1060ac5f9fff 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -1464,11 +1464,7 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
if (target_tcon->ses->server->ops->duplicate_extents) {
rc = target_tcon->ses->server->ops->duplicate_extents(xid,
smb_file_src, smb_file_target, off, len, destoff);
- if (rc == 0 && new_size > i_size) {
- truncate_setsize(target_inode, new_size);
- fscache_resize_cookie(cifs_inode_cookie(target_inode),
- new_size);
- } else if (rc == -EOPNOTSUPP) {
+ if (rc == -EOPNOTSUPP) {
/*
* copy_file_range syscall man page indicates EINVAL
* is returned e.g when "fd_in and fd_out refer to the
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 4/4] cifs: remove dead size-update blocks in cifs_setattr_unix/nounix
2026-07-31 15:34 [PATCH v2 0/4] cifs: follow-on fixes after fscache_resize_cookie() consolidation Frank Sorenson
` (2 preceding siblings ...)
2026-07-31 15:34 ` [PATCH v2 3/4] cifs: remove redundant size-update block in cifs_remap_file_range() Frank Sorenson
@ 2026-07-31 15:35 ` Frank Sorenson
3 siblings, 0 replies; 9+ messages in thread
From: Frank Sorenson @ 2026-07-31 15:35 UTC (permalink / raw)
To: linux-cifs, pc, stfrench, hehuiwen
Commit 110fee6b9bb5 ("smb: client: fix missing timestamp updates with
O_TRUNC") introduced cifs_file_set_size(), which calls netfs_resize_file()
and cifs_setsize() on success. cifs_setsize() calls i_size_write(),
updating i_size to the new value. The subsequent blocks in both
cifs_setattr_unix() and cifs_setattr_nounix():
if ((attrs->ia_valid & ATTR_SIZE) &&
attrs->ia_size != i_size_read(inode)) {
truncate_setsize(inode, attrs->ia_size);
netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
}
are therefore unreachable on the success path: attrs->ia_size ==
i_size_read(inode) always holds after cifs_file_set_size() succeeds.
On the failure path, execution jumps to out/cifs_setattr_exit before
reaching these blocks.
truncate_setsize() and netfs_resize_file() are redundant with what
cifs_file_set_size() already did; fscache_resize_cookie() was moved there
by commit fa724e235cfd ("cifs: add fscache_resize_cookie() to
cifs_setsize()"). Remove both dead blocks.
Fixes: 110fee6b9bb5 ("smb: client: fix missing timestamp updates with O_TRUNC")
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
---
fs/smb/client/inode.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index eaf27a9cf4f5..10a3322e89aa 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -3306,13 +3306,6 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
if (rc)
goto out;
- if ((attrs->ia_valid & ATTR_SIZE) &&
- attrs->ia_size != i_size_read(inode)) {
- truncate_setsize(inode, attrs->ia_size);
- netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
- fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
- }
-
setattr_copy(&nop_mnt_idmap, inode, attrs);
mark_inode_dirty(inode);
@@ -3518,13 +3511,6 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (rc)
goto cifs_setattr_exit;
- if ((attrs->ia_valid & ATTR_SIZE) &&
- attrs->ia_size != i_size_read(inode)) {
- truncate_setsize(inode, attrs->ia_size);
- netfs_resize_file(&cifsInode->netfs, attrs->ia_size, true);
- fscache_resize_cookie(cifs_inode_cookie(inode), attrs->ia_size);
- }
-
setattr_copy(&nop_mnt_idmap, inode, attrs);
mark_inode_dirty(inode);
--
2.55.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/4] cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC
2026-07-31 15:34 ` [PATCH v2 1/4] cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC Frank Sorenson
@ 2026-07-31 22:37 ` David Howells
2026-08-02 11:56 ` Frank Sorenson
0 siblings, 1 reply; 9+ messages in thread
From: David Howells @ 2026-07-31 22:37 UTC (permalink / raw)
To: Frank Sorenson
Cc: dhowells, linux-cifs, pc, stfrench, hehuiwen, stable,
Paulo Alcantara
Frank Sorenson <sorenson@redhat.com> wrote:
> cifs_do_truncate() is invoked from cifs_open() without i_rwsem, so it
> cannot use cifs_resize_file_locked() to perform a proper fscache cookie
> resize. Instead, add cifs_invalidate_cache() after cifs_setsize().
>
> cifs_invalidate_cache() calls fscache_invalidate(), which works without
> holding i_rwsem: it unconditionally increments inval_counter and sets
> FSCACHE_COOKIE_NO_DATA_TO_READ, ensuring that stale cached data is not
> served once the cookie is later activated by fscache_use_cookie().
> Truncation to zero leaves no valid cached data, making invalidation the
> correct semantic here.
What happens if there's a concurrent read or write in another thread?
truncate(), buffered read/write and direct read/write() will play reasonably
with each other through a combination of i_rwsem and the stuff in
fs/netfs/locking.c.
But apart from that, I think that invalidating the cache should work. It may
be slower, but since you're getting rid of all the data anyway...
David
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/4] cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC
2026-07-31 22:37 ` David Howells
@ 2026-08-02 11:56 ` Frank Sorenson
2026-08-02 14:44 ` Huiwen He
0 siblings, 1 reply; 9+ messages in thread
From: Frank Sorenson @ 2026-08-02 11:56 UTC (permalink / raw)
To: David Howells; +Cc: linux-cifs, pc, stfrench, hehuiwen, stable, Paulo Alcantara
On 7/31/26 5:37 PM, David Howells wrote:
> Frank Sorenson <sorenson@redhat.com> wrote:
>
>> cifs_do_truncate() is invoked from cifs_open() without i_rwsem, so it
>> cannot use cifs_resize_file_locked() to perform a proper fscache cookie
>> resize. Instead, add cifs_invalidate_cache() after cifs_setsize().
>>
>> cifs_invalidate_cache() calls fscache_invalidate(), which works without
>> holding i_rwsem: it unconditionally increments inval_counter and sets
>> FSCACHE_COOKIE_NO_DATA_TO_READ, ensuring that stale cached data is not
>> served once the cookie is later activated by fscache_use_cookie().
>> Truncation to zero leaves no valid cached data, making invalidation the
>> correct semantic here.
> What happens if there's a concurrent read or write in another thread?
> truncate(), buffered read/write and direct read/write() will play reasonably
> with each other through a combination of i_rwsem and the stuff in
> fs/netfs/locking.c.
>
> But apart from that, I think that invalidating the cache should work. It may
> be slower, but since you're getting rid of all the data anyway...
>
> David
The lockless call is pre-existing; this patch just adds the
fscache_invalidate on top of it and doesn't worsen it, since it's safe
to call without i_rwsem. Fixing the concurrent I/O issue properly is
out of scope for this series.
Frank
--
Frank Sorenson
sorenson@redhat.com
Principal Software Maintenance Engineer, filesystems
Red Hat
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/4] cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC
2026-08-02 11:56 ` Frank Sorenson
@ 2026-08-02 14:44 ` Huiwen He
0 siblings, 0 replies; 9+ messages in thread
From: Huiwen He @ 2026-08-02 14:44 UTC (permalink / raw)
To: sorenson, David Howells; +Cc: linux-cifs, pc, stfrench, stable, Paulo Alcantara
LGTM. This is safe with or without the inode lock. The pre-existing
O_TRUNC locking issue can be addressed separately.
Huiwen
在 2026/8/2 19:56, Frank Sorenson 写道:
>
> On 7/31/26 5:37 PM, David Howells wrote:
>> Frank Sorenson <sorenson@redhat.com> wrote:
>>
>>> cifs_do_truncate() is invoked from cifs_open() without i_rwsem, so it
>>> cannot use cifs_resize_file_locked() to perform a proper fscache cookie
>>> resize. Instead, add cifs_invalidate_cache() after cifs_setsize().
>>>
>>> cifs_invalidate_cache() calls fscache_invalidate(), which works without
>>> holding i_rwsem: it unconditionally increments inval_counter and sets
>>> FSCACHE_COOKIE_NO_DATA_TO_READ, ensuring that stale cached data is not
>>> served once the cookie is later activated by fscache_use_cookie().
>>> Truncation to zero leaves no valid cached data, making invalidation the
>>> correct semantic here.
>> What happens if there's a concurrent read or write in another thread?
>> truncate(), buffered read/write and direct read/write() will play
>> reasonably
>> with each other through a combination of i_rwsem and the stuff in
>> fs/netfs/locking.c.
>>
>> But apart from that, I think that invalidating the cache should work.
>> It may
>> be slower, but since you're getting rid of all the data anyway...
>>
>> David
>
> The lockless call is pre-existing; this patch just adds the
> fscache_invalidate on top of it and doesn't worsen it, since it's safe
> to call without i_rwsem. Fixing the concurrent I/O issue properly is
> out of scope for this series.
>
>
> Frank
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 2/4] cifs: add cifs_resize_file_locked() to guard fscache_resize_cookie() under i_rwsem
2026-07-31 15:34 ` [PATCH v2 2/4] cifs: add cifs_resize_file_locked() to guard fscache_resize_cookie() under i_rwsem Frank Sorenson
@ 2026-08-02 14:53 ` Huiwen He
0 siblings, 0 replies; 9+ messages in thread
From: Huiwen He @ 2026-08-02 14:53 UTC (permalink / raw)
To: Frank Sorenson, linux-cifs, pc, stfrench
Cc: stable, David Howells, Paulo Alcantara
LGTM
Huiwen
在 2026/7/31 23:34, Frank Sorenson 写道:
> cifs_setsize() calls fscache_resize_cookie() without holding i_rwsem.
> When the fscache cookie is active (FSCACHE_COOKIE_IS_CACHING is set),
> fscache_resize_cookie() performs a real resize that requires i_rwsem
> held exclusively. If another file descriptor has the same inode open,
> fscache_use_cookie() was already called from that cifs_open(), making
> the cookie active. In that case, calling cifs_setsize() from
> cifs_do_truncate() (invoked from cifs_open() without i_rwsem) races
> against concurrent fscache I/O.
>
> Strip fscache_resize_cookie() from cifs_setsize(), making it a pure
> size/page-cache helper. Add cifs_resize_file_locked() for callers
> that already hold i_rwsem: it calls netfs_resize_file() and
> cifs_setsize(), then temporarily activates the cookie with
> fscache_use_cookie() to perform the resize under the lock, then
> deactivates it with cifs_fscache_unuse_inode_cookie(). Using
> fscache_use_cookie() before the resize ensures correctness whether or
> not another fd already holds the cookie active.
>
> Switch cifs_file_set_size(), smb2_duplicate_extents(), and both size-
> extension branches of smb3_simple_falloc() to the new wrapper; those
> paths already hold i_rwsem via VFS setattr, lock_two_nondirectories(),
> or cifs_fallocate() respectively. cifs_do_truncate() continues to
> call cifs_setsize() followed by cifs_invalidate_cache(), since it runs
> without i_rwsem.
>
> Fixes: fa724e235cfd ("cifs: add fscache_resize_cookie() to cifs_setsize()")
> Cc: stable@vger.kernel.org
> Cc: David Howells <dhowells@redhat.com>
> Cc: Paulo Alcantara <pc@manguebit.com>
> Signed-off-by: Frank Sorenson <sorenson@redhat.com>
> Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
> ---
> fs/smb/client/cifsfs.h | 1 +
> fs/smb/client/inode.c | 24 +++++++++++++++++++++---
> fs/smb/client/smb2ops.c | 9 +++------
> 3 files changed, 23 insertions(+), 11 deletions(-)
>
> diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h
> index 854e672a4e37..651670c19c2b 100644
> --- a/fs/smb/client/cifsfs.h
> +++ b/fs/smb/client/cifsfs.h
> @@ -147,6 +147,7 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, struct file *src_file,
>
> long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg);
> void cifs_setsize(struct inode *inode, loff_t offset);
> +void cifs_resize_file_locked(struct inode *inode, loff_t offset);
>
> struct fs_context;
> struct smb3_fs_context;
> diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
> index 0afff761aab9..eaf27a9cf4f5 100644
> --- a/fs/smb/client/inode.c
> +++ b/fs/smb/client/inode.c
> @@ -3059,7 +3059,26 @@ void cifs_setsize(struct inode *inode, loff_t offset)
> inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
> truncate_pagecache(inode, offset);
> netfs_wait_for_outstanding_io(inode);
> - fscache_resize_cookie(cifs_inode_cookie(inode), offset);
> +}
> +
> +void cifs_resize_file_locked(struct inode *inode, loff_t offset)
> +{
> + struct fscache_cookie *cookie = cifs_inode_cookie(inode);
> +
> + lockdep_assert_held_write(&inode->i_rwsem);
> +
> + netfs_resize_file(netfs_inode(inode), offset, true);
> + cifs_setsize(inode, offset);
> +
> + if (!cookie)
> + return;
> +
> + fscache_use_cookie(cookie, true);
> + fscache_resize_cookie(cookie, offset);
> + cifs_fscache_unuse_inode_cookie(inode, true);
> }
>
> int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
> @@ -3125,10 +3144,8 @@ int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
> cifs_put_tlink(tlink);
>
> set_size_out:
> - if (rc == 0) {
> - netfs_resize_file(&cifsInode->netfs, size, true);
> - cifs_setsize(inode, size);
> - }
> + if (rc == 0)
> + cifs_resize_file_locked(inode, size);
>
> return rc;
> }
> diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
> index 192649fec25d..0e872d58fae7 100644
> --- a/fs/smb/client/smb2ops.c
> +++ b/fs/smb/client/smb2ops.c
> @@ -2222,8 +2222,7 @@ smb2_duplicate_extents(const unsigned int xid,
> rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
> if (rc)
> goto duplicate_extents_out;
> - netfs_resize_file(netfs_inode(inode), dest_off + len, true);
> - cifs_setsize(inode, dest_off + len);
> + cifs_resize_file_locked(inode, dest_off + len);
> }
> rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
> trgtfile->fid.volatile_fid,
> @@ -3776,8 +3775,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
> }
>
> new_eof = off + len;
> - netfs_resize_file(&cifsi->netfs, new_eof, true);
> - cifs_setsize(inode, new_eof);
> + cifs_resize_file_locked(inode, new_eof);
>
> qrc = SMB2_query_info(xid, tcon,
> cfile->fid.persistent_fid,
> @@ -3825,8 +3823,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
> if (rc)
> goto out;
>
> - netfs_resize_file(&cifsi->netfs, new_eof, true);
> - cifs_setsize(inode, new_eof);
> + cifs_resize_file_locked(inode, new_eof);
>
> qrc = SMB2_query_info(xid, tcon,
> cfile->fid.persistent_fid,
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-08-02 14:53 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-31 15:34 [PATCH v2 0/4] cifs: follow-on fixes after fscache_resize_cookie() consolidation Frank Sorenson
2026-07-31 15:34 ` [PATCH v2 1/4] cifs: use cifs_invalidate_cache() in cifs_do_truncate() for O_TRUNC Frank Sorenson
2026-07-31 22:37 ` David Howells
2026-08-02 11:56 ` Frank Sorenson
2026-08-02 14:44 ` Huiwen He
2026-07-31 15:34 ` [PATCH v2 2/4] cifs: add cifs_resize_file_locked() to guard fscache_resize_cookie() under i_rwsem Frank Sorenson
2026-08-02 14:53 ` Huiwen He
2026-07-31 15:34 ` [PATCH v2 3/4] cifs: remove redundant size-update block in cifs_remap_file_range() Frank Sorenson
2026-07-31 15:35 ` [PATCH v2 4/4] cifs: remove dead size-update blocks in cifs_setattr_unix/nounix Frank Sorenson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox