* Re: [PATCH] cifs: fix i_size inconsistency in smb2_duplicate_extents() on FSCTL failure
2026-08-20 21:14 [PATCH] cifs: fix i_size inconsistency in smb2_duplicate_extents() on FSCTL failure Frank Sorenson
@ 2026-08-21 1:02 ` Namjae Jeon
2026-08-21 3:34 ` Frank Sorenson
2026-08-23 12:23 ` kernel test robot
2026-08-23 12:23 ` kernel test robot
2 siblings, 1 reply; 5+ messages in thread
From: Namjae Jeon @ 2026-08-21 1:02 UTC (permalink / raw)
To: Frank Sorenson; +Cc: linux-cifs, pc, stable
On Fri, Aug 21, 2026 at 6:14 AM Frank Sorenson <sorenson@redhat.com> wrote:
>
> smb2_duplicate_extents() pre-extends the target file before sending
> FSCTL_DUPLICATE_EXTENTS_TO_FILE. If the FSCTL fails (e.g. ENOSPC,
> byte-range lock conflict, unsupported file combination), the server
> and client i_size are left reflecting the larger size while the data
> in the extended range was never cloned.
>
> Save the original i_size before pre-extension and restore it on FSCTL
> failure. If rollback fails, force revalidation instead.
>
> Fixes: cfc63fc8126a ("smb3: fix cached file size problems in duplicate extents (reflink)")
> Cc: stable@vger.kernel.org
> Signed-off-by: Frank Sorenson <sorenson@redhat.com>
> ---
> fs/smb/client/smb2ops.c | 21 ++++++++++++++++++++-
> 1 file changed, 20 insertions(+), 1 deletion(-)
>
> diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
> index 7d6738ffcb80..38bd344a9740 100644
> --- a/fs/smb/client/smb2ops.c
> +++ b/fs/smb/client/smb2ops.c
> @@ -2200,6 +2200,7 @@ smb2_duplicate_extents(const unsigned int xid,
> struct duplicate_extents_to_file dup_ext_buf;
> struct timespec64 ts;
> struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink);
> + loff_t orig_size;
> u64 asize;
>
> /* server fileays advertise duplicate extent support with this flag */
> @@ -2218,7 +2219,8 @@ smb2_duplicate_extents(const unsigned int xid,
> trgtfile->fid.volatile_fid, tcon->tid,
> tcon->ses->Suid, src_off, dest_off, len);
> inode = d_inode(trgtfile->dentry);
> - if (inode->i_size < dest_off + len) {
> + orig_size = i_size_read(inode);
> + if (orig_size < dest_off + len) {
> rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
> if (rc)
> goto duplicate_extents_out;
> @@ -2235,6 +2237,23 @@ smb2_duplicate_extents(const unsigned int xid,
> if (ret_data_len > 0)
> cifs_dbg(FYI, "Non-zero response length in duplicate extents\n");
>
> + if (rc && i_size_read(inode) > orig_size) {
> + int rrc;
> +
> + /*
> + * FSCTL failed after we pre-extended the file. Attempt to
> + * restore the original size so the caller sees a consistent
> + * file rather than a larger file with uncloned content.
> + */
> + rrc = smb2_set_file_size(xid, tcon, trgtfile, orig_size, false);
orig_size is only the locally cached size, and
lock_two_nondirectories() does not prevent another SMB client from
modifying the file. If the FSCTL fails, this rollback may truncate the
server-side file to a stale, smaller size and delete data written by
that client.
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] cifs: fix i_size inconsistency in smb2_duplicate_extents() on FSCTL failure
2026-08-21 1:02 ` Namjae Jeon
@ 2026-08-21 3:34 ` Frank Sorenson
0 siblings, 0 replies; 5+ messages in thread
From: Frank Sorenson @ 2026-08-21 3:34 UTC (permalink / raw)
To: Namjae Jeon; +Cc: linux-cifs, pc, stable
On 8/20/26 8:02 PM, Namjae Jeon wrote:
> On Fri, Aug 21, 2026 at 6:14 AM Frank Sorenson <sorenson@redhat.com> wrote:
>> smb2_duplicate_extents() pre-extends the target file before sending
>> FSCTL_DUPLICATE_EXTENTS_TO_FILE. If the FSCTL fails (e.g. ENOSPC,
>> byte-range lock conflict, unsupported file combination), the server
>> and client i_size are left reflecting the larger size while the data
>> in the extended range was never cloned.
>>
>> Save the original i_size before pre-extension and restore it on FSCTL
>> failure. If rollback fails, force revalidation instead.
>>
>> Fixes: cfc63fc8126a ("smb3: fix cached file size problems in duplicate extents (reflink)")
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Frank Sorenson <sorenson@redhat.com>
>> ---
>> fs/smb/client/smb2ops.c | 21 ++++++++++++++++++++-
>> 1 file changed, 20 insertions(+), 1 deletion(-)
>>
>> diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
>> index 7d6738ffcb80..38bd344a9740 100644
>> --- a/fs/smb/client/smb2ops.c
>> +++ b/fs/smb/client/smb2ops.c
>> @@ -2200,6 +2200,7 @@ smb2_duplicate_extents(const unsigned int xid,
>> struct duplicate_extents_to_file dup_ext_buf;
>> struct timespec64 ts;
>> struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink);
>> + loff_t orig_size;
>> u64 asize;
>>
>> /* server fileays advertise duplicate extent support with this flag */
>> @@ -2218,7 +2219,8 @@ smb2_duplicate_extents(const unsigned int xid,
>> trgtfile->fid.volatile_fid, tcon->tid,
>> tcon->ses->Suid, src_off, dest_off, len);
>> inode = d_inode(trgtfile->dentry);
>> - if (inode->i_size < dest_off + len) {
>> + orig_size = i_size_read(inode);
>> + if (orig_size < dest_off + len) {
>> rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
>> if (rc)
>> goto duplicate_extents_out;
>> @@ -2235,6 +2237,23 @@ smb2_duplicate_extents(const unsigned int xid,
>> if (ret_data_len > 0)
>> cifs_dbg(FYI, "Non-zero response length in duplicate extents\n");
>>
>> + if (rc && i_size_read(inode) > orig_size) {
>> + int rrc;
>> +
>> + /*
>> + * FSCTL failed after we pre-extended the file. Attempt to
>> + * restore the original size so the caller sees a consistent
>> + * file rather than a larger file with uncloned content.
>> + */
>> + rrc = smb2_set_file_size(xid, tcon, trgtfile, orig_size, false);
> orig_size is only the locally cached size, and
> lock_two_nondirectories() does not prevent another SMB client from
> modifying the file. If the FSCTL fails, this rollback may truncate the
> server-side file to a stale, smaller size and delete data written by
> that client.
Hmm, yes... it's a fundamental problem; we only have the locally cached
size.
So if the FSCTL fails, we need to force revalidation and invalidate the
cache.
--
Frank Sorenson
sorenson@redhat.com
Principal Software Maintenance Engineer, filesystems
Red Hat
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] cifs: fix i_size inconsistency in smb2_duplicate_extents() on FSCTL failure
2026-08-20 21:14 [PATCH] cifs: fix i_size inconsistency in smb2_duplicate_extents() on FSCTL failure Frank Sorenson
2026-08-21 1:02 ` Namjae Jeon
@ 2026-08-23 12:23 ` kernel test robot
2026-08-23 12:23 ` kernel test robot
2 siblings, 0 replies; 5+ messages in thread
From: kernel test robot @ 2026-08-23 12:23 UTC (permalink / raw)
To: Frank Sorenson, linux-cifs; +Cc: llvm, oe-kbuild-all, pc, linkinjeon, stable
Hi Frank,
kernel test robot noticed the following build errors:
[auto build test ERROR on brauner-vfs/vfs.all]
[also build test ERROR on cifs/for-next linus/master v7.2 next-20260821]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Frank-Sorenson/cifs-fix-i_size-inconsistency-in-smb2_duplicate_extents-on-FSCTL-failure/20260820-161443
base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link: https://lore.kernel.org/r/20260820211443.1472310-1-sorenson%40redhat.com
patch subject: [PATCH] cifs: fix i_size inconsistency in smb2_duplicate_extents() on FSCTL failure
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20260823/202608230943.9VnBMLk2-lkp@intel.com/config)
compiler: clang version 22.1.3 (https://github.com/llvm/llvm-project e9846648fd6183ee6d8cbdb4502213fcf902a211)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260823/202608230943.9VnBMLk2-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202608230943.9VnBMLk2-lkp@intel.com/
All errors (new ones prefixed by >>):
>> fs/smb/client/smb2ops.c:2251:4: error: call to undeclared function 'cifs_resize_file_locked'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
2251 | cifs_resize_file_locked(inode, orig_size);
| ^
1 error generated.
vim +/cifs_resize_file_locked +2251 fs/smb/client/smb2ops.c
2188
2189 static int
2190 smb2_duplicate_extents(const unsigned int xid,
2191 struct cifsFileInfo *srcfile,
2192 struct cifsFileInfo *trgtfile, u64 src_off,
2193 u64 len, u64 dest_off)
2194 {
2195 int rc;
2196 int qrc;
2197 unsigned int ret_data_len;
2198 struct inode *inode;
2199 struct smb2_file_all_info file_inf;
2200 struct duplicate_extents_to_file dup_ext_buf;
2201 struct timespec64 ts;
2202 struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink);
2203 loff_t orig_size;
2204 u64 asize;
2205
2206 /* server fileays advertise duplicate extent support with this flag */
2207 if ((le32_to_cpu(tcon->fsAttrInfo.Attributes) &
2208 FILE_SUPPORTS_BLOCK_REFCOUNTING) == 0)
2209 return -EOPNOTSUPP;
2210
2211 dup_ext_buf.VolatileFileHandle = srcfile->fid.volatile_fid;
2212 dup_ext_buf.PersistentFileHandle = srcfile->fid.persistent_fid;
2213 dup_ext_buf.SourceFileOffset = cpu_to_le64(src_off);
2214 dup_ext_buf.TargetFileOffset = cpu_to_le64(dest_off);
2215 dup_ext_buf.ByteCount = cpu_to_le64(len);
2216 cifs_dbg(FYI, "Duplicate extents: src off %lld dst off %lld len %lld\n",
2217 src_off, dest_off, len);
2218 trace_smb3_clone_enter(xid, srcfile->fid.volatile_fid,
2219 trgtfile->fid.volatile_fid, tcon->tid,
2220 tcon->ses->Suid, src_off, dest_off, len);
2221 inode = d_inode(trgtfile->dentry);
2222 orig_size = i_size_read(inode);
2223 if (orig_size < dest_off + len) {
2224 rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
2225 if (rc)
2226 goto duplicate_extents_out;
2227 netfs_resize_file(netfs_inode(inode), dest_off + len, true);
2228 cifs_setsize(inode, dest_off + len);
2229 }
2230 rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
2231 trgtfile->fid.volatile_fid,
2232 FSCTL_DUPLICATE_EXTENTS_TO_FILE,
2233 (char *)&dup_ext_buf,
2234 sizeof(struct duplicate_extents_to_file),
2235 CIFSMaxBufSize, NULL,
2236 &ret_data_len);
2237
2238 if (ret_data_len > 0)
2239 cifs_dbg(FYI, "Non-zero response length in duplicate extents\n");
2240
2241 if (rc && i_size_read(inode) > orig_size) {
2242 int rrc;
2243
2244 /*
2245 * FSCTL failed after we pre-extended the file. Attempt to
2246 * restore the original size so the caller sees a consistent
2247 * file rather than a larger file with uncloned content.
2248 */
2249 rrc = smb2_set_file_size(xid, tcon, trgtfile, orig_size, false);
2250 if (rrc == 0)
> 2251 cifs_resize_file_locked(inode, orig_size);
2252 else {
2253 CIFS_I(inode)->time = 0; /* force reval */
2254 cifs_invalidate_cache(inode, 0);
2255 }
2256 }
2257
2258 if (rc == 0) {
2259 qrc = SMB2_query_info(xid, tcon, trgtfile->fid.persistent_fid,
2260 trgtfile->fid.volatile_fid, &file_inf);
2261 spin_lock(&inode->i_lock);
2262 if (qrc == 0) {
2263 asize = le64_to_cpu(file_inf.AllocationSize);
2264 CIFS_I(inode)->time = jiffies;
2265 if (file_inf.LastWriteTime) {
2266 ts = cifs_NTtimeToUnix(file_inf.LastWriteTime);
2267 inode_set_mtime_to_ts(inode, ts);
2268 }
2269 if (file_inf.ChangeTime) {
2270 ts = cifs_NTtimeToUnix(file_inf.ChangeTime);
2271 inode_set_ctime_to_ts(inode, ts);
2272 }
2273 if (file_inf.LastAccessTime) {
2274 ts = cifs_NTtimeToUnix(file_inf.LastAccessTime);
2275 inode_set_atime_to_ts(inode, ts);
2276 }
2277 inode->i_blocks = CIFS_INO_BLOCKS(asize);
2278 } else {
2279 CIFS_I(inode)->time = 0; /* force reval */
2280 }
2281 spin_unlock(&inode->i_lock);
2282 }
2283
2284 duplicate_extents_out:
2285 if (rc)
2286 trace_smb3_clone_err(xid, srcfile->fid.volatile_fid,
2287 trgtfile->fid.volatile_fid,
2288 tcon->tid, tcon->ses->Suid, src_off,
2289 dest_off, len, rc);
2290 else
2291 trace_smb3_clone_done(xid, srcfile->fid.volatile_fid,
2292 trgtfile->fid.volatile_fid, tcon->tid,
2293 tcon->ses->Suid, src_off, dest_off, len);
2294 return rc;
2295 }
2296
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] cifs: fix i_size inconsistency in smb2_duplicate_extents() on FSCTL failure
2026-08-20 21:14 [PATCH] cifs: fix i_size inconsistency in smb2_duplicate_extents() on FSCTL failure Frank Sorenson
2026-08-21 1:02 ` Namjae Jeon
2026-08-23 12:23 ` kernel test robot
@ 2026-08-23 12:23 ` kernel test robot
2 siblings, 0 replies; 5+ messages in thread
From: kernel test robot @ 2026-08-23 12:23 UTC (permalink / raw)
To: Frank Sorenson, linux-cifs; +Cc: oe-kbuild-all, pc, linkinjeon, stable
Hi Frank,
kernel test robot noticed the following build errors:
[auto build test ERROR on brauner-vfs/vfs.all]
[also build test ERROR on cifs/for-next linus/master v7.2 next-20260821]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Frank-Sorenson/cifs-fix-i_size-inconsistency-in-smb2_duplicate_extents-on-FSCTL-failure/20260820-161443
base: https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git vfs.all
patch link: https://lore.kernel.org/r/20260820211443.1472310-1-sorenson%40redhat.com
patch subject: [PATCH] cifs: fix i_size inconsistency in smb2_duplicate_extents() on FSCTL failure
config: parisc-defconfig (https://download.01.org/0day-ci/archive/20260823/202608230427.RQarhMR6-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 16.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260823/202608230427.RQarhMR6-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202608230427.RQarhMR6-lkp@intel.com/
All errors (new ones prefixed by >>):
fs/smb/client/smb2ops.c: In function 'smb2_duplicate_extents':
>> fs/smb/client/smb2ops.c:2251:25: error: implicit declaration of function 'cifs_resize_file_locked' [-Wimplicit-function-declaration]
2251 | cifs_resize_file_locked(inode, orig_size);
| ^~~~~~~~~~~~~~~~~~~~~~~
vim +/cifs_resize_file_locked +2251 fs/smb/client/smb2ops.c
2188
2189 static int
2190 smb2_duplicate_extents(const unsigned int xid,
2191 struct cifsFileInfo *srcfile,
2192 struct cifsFileInfo *trgtfile, u64 src_off,
2193 u64 len, u64 dest_off)
2194 {
2195 int rc;
2196 int qrc;
2197 unsigned int ret_data_len;
2198 struct inode *inode;
2199 struct smb2_file_all_info file_inf;
2200 struct duplicate_extents_to_file dup_ext_buf;
2201 struct timespec64 ts;
2202 struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink);
2203 loff_t orig_size;
2204 u64 asize;
2205
2206 /* server fileays advertise duplicate extent support with this flag */
2207 if ((le32_to_cpu(tcon->fsAttrInfo.Attributes) &
2208 FILE_SUPPORTS_BLOCK_REFCOUNTING) == 0)
2209 return -EOPNOTSUPP;
2210
2211 dup_ext_buf.VolatileFileHandle = srcfile->fid.volatile_fid;
2212 dup_ext_buf.PersistentFileHandle = srcfile->fid.persistent_fid;
2213 dup_ext_buf.SourceFileOffset = cpu_to_le64(src_off);
2214 dup_ext_buf.TargetFileOffset = cpu_to_le64(dest_off);
2215 dup_ext_buf.ByteCount = cpu_to_le64(len);
2216 cifs_dbg(FYI, "Duplicate extents: src off %lld dst off %lld len %lld\n",
2217 src_off, dest_off, len);
2218 trace_smb3_clone_enter(xid, srcfile->fid.volatile_fid,
2219 trgtfile->fid.volatile_fid, tcon->tid,
2220 tcon->ses->Suid, src_off, dest_off, len);
2221 inode = d_inode(trgtfile->dentry);
2222 orig_size = i_size_read(inode);
2223 if (orig_size < dest_off + len) {
2224 rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
2225 if (rc)
2226 goto duplicate_extents_out;
2227 netfs_resize_file(netfs_inode(inode), dest_off + len, true);
2228 cifs_setsize(inode, dest_off + len);
2229 }
2230 rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
2231 trgtfile->fid.volatile_fid,
2232 FSCTL_DUPLICATE_EXTENTS_TO_FILE,
2233 (char *)&dup_ext_buf,
2234 sizeof(struct duplicate_extents_to_file),
2235 CIFSMaxBufSize, NULL,
2236 &ret_data_len);
2237
2238 if (ret_data_len > 0)
2239 cifs_dbg(FYI, "Non-zero response length in duplicate extents\n");
2240
2241 if (rc && i_size_read(inode) > orig_size) {
2242 int rrc;
2243
2244 /*
2245 * FSCTL failed after we pre-extended the file. Attempt to
2246 * restore the original size so the caller sees a consistent
2247 * file rather than a larger file with uncloned content.
2248 */
2249 rrc = smb2_set_file_size(xid, tcon, trgtfile, orig_size, false);
2250 if (rrc == 0)
> 2251 cifs_resize_file_locked(inode, orig_size);
2252 else {
2253 CIFS_I(inode)->time = 0; /* force reval */
2254 cifs_invalidate_cache(inode, 0);
2255 }
2256 }
2257
2258 if (rc == 0) {
2259 qrc = SMB2_query_info(xid, tcon, trgtfile->fid.persistent_fid,
2260 trgtfile->fid.volatile_fid, &file_inf);
2261 spin_lock(&inode->i_lock);
2262 if (qrc == 0) {
2263 asize = le64_to_cpu(file_inf.AllocationSize);
2264 CIFS_I(inode)->time = jiffies;
2265 if (file_inf.LastWriteTime) {
2266 ts = cifs_NTtimeToUnix(file_inf.LastWriteTime);
2267 inode_set_mtime_to_ts(inode, ts);
2268 }
2269 if (file_inf.ChangeTime) {
2270 ts = cifs_NTtimeToUnix(file_inf.ChangeTime);
2271 inode_set_ctime_to_ts(inode, ts);
2272 }
2273 if (file_inf.LastAccessTime) {
2274 ts = cifs_NTtimeToUnix(file_inf.LastAccessTime);
2275 inode_set_atime_to_ts(inode, ts);
2276 }
2277 inode->i_blocks = CIFS_INO_BLOCKS(asize);
2278 } else {
2279 CIFS_I(inode)->time = 0; /* force reval */
2280 }
2281 spin_unlock(&inode->i_lock);
2282 }
2283
2284 duplicate_extents_out:
2285 if (rc)
2286 trace_smb3_clone_err(xid, srcfile->fid.volatile_fid,
2287 trgtfile->fid.volatile_fid,
2288 tcon->tid, tcon->ses->Suid, src_off,
2289 dest_off, len, rc);
2290 else
2291 trace_smb3_clone_done(xid, srcfile->fid.volatile_fid,
2292 trgtfile->fid.volatile_fid, tcon->tid,
2293 tcon->ses->Suid, src_off, dest_off, len);
2294 return rc;
2295 }
2296
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 5+ messages in thread