All of lore.kernel.org
 help / color / mirror / Atom feed
* [bug report] smb: client: batch SRV_COPYCHUNK entries to cut roundtrips
@ 2025-09-18  9:44 Dan Carpenter
  2025-09-18 20:19 ` Henrique Carvalho
  0 siblings, 1 reply; 3+ messages in thread
From: Dan Carpenter @ 2025-09-18  9:44 UTC (permalink / raw)
  To: Henrique Carvalho; +Cc: linux-cifs

Hello Henrique Carvalho,

Commit 4e3acdf94c89 ("smb: client: batch SRV_COPYCHUNK entries to cut
roundtrips") from Sep 16, 2025 (linux-next), leads to the following
Smatch static checker warning:

	fs/smb/client/smb2ops.c:1937 smb2_copychunk_range()
	error: uninitialized symbol 'ret_data_len'.

fs/smb/client/smb2ops.c
    1844 static ssize_t
    1845 smb2_copychunk_range(const unsigned int xid,
    1846                      struct cifsFileInfo *src_file,
    1847                      struct cifsFileInfo *dst_file,
    1848                      u64 src_off,
    1849                      u64 len,
    1850                      u64 dst_off)
    1851 {
    1852         int rc = 0;
    1853         unsigned int ret_data_len;
    1854         struct copychunk_ioctl *cc_req = NULL;
    1855         struct copychunk_ioctl_rsp *cc_rsp = NULL;
    1856         struct cifs_tcon *tcon;
    1857         struct copychunk *chunk;
    1858         u32 chunks, chunk_count, chunk_bytes;
    1859         u32 copy_bytes, copy_bytes_left;
    1860         u32 chunks_written, bytes_written;
    1861         u64 total_bytes_left = len;
    1862         u64 src_off_prev, dst_off_prev;
    1863         u32 retries = 0;
    1864 
    1865         tcon = tlink_tcon(dst_file->tlink);
    1866 
    1867         trace_smb3_copychunk_enter(xid, src_file->fid.volatile_fid,
    1868                                    dst_file->fid.volatile_fid, tcon->tid,
    1869                                    tcon->ses->Suid, src_off, dst_off, len);
    1870 
    1871 retry:
    1872         chunk_count = calc_chunk_count(tcon, total_bytes_left);
    1873         if (!chunk_count) {
    1874                 rc = -EOPNOTSUPP;
    1875                 goto cchunk_out;
    1876         }
    1877 
    1878         cc_req = kzalloc(struct_size(cc_req, Chunks, chunk_count), GFP_KERNEL);
    1879         if (!cc_req) {
    1880                 rc = -ENOMEM;
    1881                 goto cchunk_out;
    1882         }
    1883 
    1884         /* Request a key from the server to identify the source of the copy */
    1885         rc = SMB2_request_res_key(xid,
    1886                                   tlink_tcon(src_file->tlink),
    1887                                   src_file->fid.persistent_fid,
    1888                                   src_file->fid.volatile_fid,
    1889                                   cc_req);
    1890 
    1891         /* Note: request_res_key sets res_key null only if rc != 0 */
    1892         if (rc)
    1893                 goto cchunk_out;
    1894 
    1895         while (total_bytes_left > 0) {
    1896 
    1897                 /* Store previous offsets to allow rewind */
    1898                 src_off_prev = src_off;
    1899                 dst_off_prev = dst_off;
    1900 
    1901                 trace_smb3_copychunk_iter(xid, src_file->fid.volatile_fid,
    1902                                           dst_file->fid.volatile_fid, tcon->tid,
    1903                                           tcon->ses->Suid, src_off, dst_off, len);
    1904 
    1905                 chunks = 0;
    1906                 copy_bytes = 0;
    1907                 copy_bytes_left = umin(total_bytes_left, tcon->max_bytes_copy);
    1908                 while (copy_bytes_left > 0 && chunks < chunk_count) {
    1909                         chunk = &cc_req->Chunks[chunks++];
    1910 
    1911                         chunk->SourceOffset = cpu_to_le64(src_off);
    1912                         chunk->TargetOffset = cpu_to_le64(dst_off);
    1913 
    1914                         chunk_bytes = umin(copy_bytes_left, tcon->max_bytes_chunk);
    1915 
    1916                         chunk->Length = cpu_to_le32(chunk_bytes);
    1917                         chunk->Reserved = 0;
    1918 
    1919                         src_off += chunk_bytes;
    1920                         dst_off += chunk_bytes;
    1921 
    1922                         copy_bytes_left -= chunk_bytes;
    1923                         copy_bytes += chunk_bytes;
    1924                 }
    1925 
    1926                 cc_req->ChunkCount = cpu_to_le32(chunks);
    1927                 /* Buffer is zeroed, no need to set pcchunk->Reserved = 0 */
    1928 
    1929                 /* Request server copy to target from src identified by key */
    1930                 kfree(cc_rsp);
    1931                 cc_rsp = NULL;
    1932                 rc = SMB2_ioctl(xid, tcon, dst_file->fid.persistent_fid,
    1933                         dst_file->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
    1934                         (char *)cc_req, struct_size(cc_req, Chunks, chunks),
    1935                         CIFSMaxBufSize, (char **)&cc_rsp, &ret_data_len);
    1936 
--> 1937                 if (ret_data_len != sizeof(struct copychunk_ioctl_rsp)) {
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Using unintialized variables doesn't work because runtime checkers like
UBSan will complain as well as static checkers.

But the other issue is that this code treats -EINVAL as having a special
meaning.  -EINVAL is the most common error code.  All the places which
treat -EINVAL as having a special meaning end up buggy in the end.  Mostly
they start out buggy, but even the ones which aren't buggy from the start
end up buggy over time.

    1938                         cifs_tcon_dbg(VFS, "Copychunk invalid response: response size does not match expected size\n");
    1939                         rc = -EIO;
    1940                         goto cchunk_out;
    1941                 }
    1942 
    1943                 if (rc == 0) {
    1944                         bytes_written = le32_to_cpu(cc_rsp->TotalBytesWritten);
    1945                         if (bytes_written == 0) {
    1946                                 cifs_tcon_dbg(VFS, "Copychunk invalid response: no bytes copied\n");
    1947                                 rc = -EIO;
    1948                                 goto cchunk_out;
    1949                         }
    1950                         /* Check if server claimed to write more than we asked */
    1951                         if (bytes_written > copy_bytes) {
    1952                                 cifs_tcon_dbg(VFS, "Copychunk invalid response: unexpected value for TotalBytesWritten\n");
    1953                                 rc = -EIO;
    1954                                 goto cchunk_out;
    1955                         }
    1956 
    1957                         chunks_written = le32_to_cpu(cc_rsp->ChunksWritten);
    1958                         if (chunks_written > chunks) {
    1959                                 cifs_tcon_dbg(VFS, "Copychunk invalid response: Invalid num chunks written\n");
    1960                                 rc = -EIO;
    1961                                 goto cchunk_out;
    1962                         }
    1963 
    1964                         /* Partial write: rewind */
    1965                         if (bytes_written < copy_bytes) {
    1966                                 u32 delta = copy_bytes - bytes_written;
    1967 
    1968                                 src_off -= delta;
    1969                                 dst_off -= delta;
    1970                         }
    1971 
    1972                         total_bytes_left -= bytes_written;
    1973 
    1974                 } else if (rc == -EINVAL) {
    1975                         /*
    1976                          * Check if server is not asking us to reduce size.
    1977                          *
    1978                          * Note: As per MS-SMB2 2.2.32.1, the values returned
    1979                          * in cc_rsp are not strictly lower than what existed
    1980                          * before.
    1981                          *
    1982                          */
    1983                         if (le32_to_cpu(cc_rsp->ChunksWritten) < tcon->max_chunks) {
    1984                                 cifs_tcon_dbg(VFS, "Copychunk MaxChunks updated: %u -> %u\n",
    1985                                               tcon->max_chunks,
    1986                                               le32_to_cpu(cc_rsp->ChunksWritten));
    1987                                 tcon->max_chunks = le32_to_cpu(cc_rsp->ChunksWritten);
    1988                         }
    1989                         if (le32_to_cpu(cc_rsp->ChunkBytesWritten) < tcon->max_bytes_chunk) {
    1990                                 cifs_tcon_dbg(VFS, "Copychunk MaxBytesChunk updated: %u -> %u\n",
    1991                                               tcon->max_bytes_chunk,
    1992                                               le32_to_cpu(cc_rsp->ChunkBytesWritten));
    1993                                 tcon->max_bytes_chunk = le32_to_cpu(cc_rsp->ChunkBytesWritten);
    1994                         }
    1995                         if (le32_to_cpu(cc_rsp->TotalBytesWritten) < tcon->max_bytes_copy) {
    1996                                 cifs_tcon_dbg(VFS, "Copychunk MaxBytesCopy updated: %u -> %u\n",
    1997                                               tcon->max_bytes_copy,
    1998                                               le32_to_cpu(cc_rsp->TotalBytesWritten));
    1999                                 tcon->max_bytes_copy = le32_to_cpu(cc_rsp->TotalBytesWritten);
    2000                         }
    2001 
    2002                         trace_smb3_copychunk_err(xid, src_file->fid.volatile_fid,
    2003                                                  dst_file->fid.volatile_fid, tcon->tid,
    2004                                                  tcon->ses->Suid, src_off, dst_off, len, rc);
    2005 
    2006                         /* Rewind */
    2007                         if (retries++ < 2) {
    2008                                 src_off = src_off_prev;
    2009                                 dst_off = dst_off_prev;
    2010                                 kfree(cc_req);
    2011                                 cc_req = NULL;
    2012                                 goto retry;
    2013                         } else
    2014                                 goto cchunk_out;
    2015                 } else { /* Unexpected */
    2016                         trace_smb3_copychunk_err(xid, src_file->fid.volatile_fid,
    2017                                                  dst_file->fid.volatile_fid, tcon->tid,
    2018                                                  tcon->ses->Suid, src_off, dst_off, len, rc);
    2019                         goto cchunk_out;
    2020                 }
    2021         }
    2022 
    2023         trace_smb3_copychunk_done(xid, src_file->fid.volatile_fid,
    2024                                   dst_file->fid.volatile_fid, tcon->tid,
    2025                                   tcon->ses->Suid, src_off, dst_off, len);
    2026 
    2027 cchunk_out:
    2028         kfree(cc_req);
    2029         kfree(cc_rsp);
    2030         if (rc)
    2031                 return rc;
    2032         else
    2033                 return len;
    2034 }

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [bug report] smb: client: batch SRV_COPYCHUNK entries to cut roundtrips
  2025-09-18  9:44 [bug report] smb: client: batch SRV_COPYCHUNK entries to cut roundtrips Dan Carpenter
@ 2025-09-18 20:19 ` Henrique Carvalho
  2025-09-18 20:59   ` Henrique Carvalho
  0 siblings, 1 reply; 3+ messages in thread
From: Henrique Carvalho @ 2025-09-18 20:19 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: linux-cifs

Hi Dan,

Thanks for the report.

On 9/18/25 6:44 AM, Dan Carpenter wrote:
> Hello Henrique Carvalho,
>
> Commit 4e3acdf94c89 ("smb: client: batch SRV_COPYCHUNK entries to cut
> roundtrips") from Sep 16, 2025 (linux-next), leads to the following
> Smatch static checker warning:
>
> 	fs/smb/client/smb2ops.c:1937 smb2_copychunk_range()
> 	error: uninitialized symbol 'ret_data_len'.
>
> --> 1937                 if (ret_data_len != sizeof(struct copychunk_ioctl_rsp)) {
>                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> Using unintialized variables doesn't work because runtime checkers like
> UBSan will complain as well as static checkers.

I will update the patch to initialize ret_data_len.

> But the other issue is that this code treats -EINVAL as having a special
> meaning.  -EINVAL is the most common error code.  All the places which
> treat -EINVAL as having a special meaning end up buggy in the end.  Mostly
> they start out buggy, but even the ones which aren't buggy from the start
> end up buggy over time.

-EINVAL is mapped from the SMB2 server returned error
STATUS_INVALID_PARAMETER, so I don't know if there is anything that can
be done here.

After your email, I considered returning -EOPNOTSUPP instead to trigger
kernel-side copy fallback, but returning -EINVAL also seems to have the
practical advantage of having a successful copy, but with fewer network
roundtrips (apparently due to userspace fallback, but I haven't digged
too much into it).

If there's consensus that changing this error mapping would improve the
overall robustness of the code path, I'm open to that approach.

-- 
Henrique
SUSE Labs

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [bug report] smb: client: batch SRV_COPYCHUNK entries to cut roundtrips
  2025-09-18 20:19 ` Henrique Carvalho
@ 2025-09-18 20:59   ` Henrique Carvalho
  0 siblings, 0 replies; 3+ messages in thread
From: Henrique Carvalho @ 2025-09-18 20:59 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: linux-cifs

On 9/18/25 5:19 PM, Henrique Carvalho wrote:
> Hi Dan,
> 
> Thanks for the report.
> 
> On 9/18/25 6:44 AM, Dan Carpenter wrote:
>> Hello Henrique Carvalho,
>>
>> Commit 4e3acdf94c89 ("smb: client: batch SRV_COPYCHUNK entries to cut
>> roundtrips") from Sep 16, 2025 (linux-next), leads to the following
>> Smatch static checker warning:
>>
>> 	fs/smb/client/smb2ops.c:1937 smb2_copychunk_range()
>> 	error: uninitialized symbol 'ret_data_len'.
>>
>> --> 1937                 if (ret_data_len != sizeof(struct copychunk_ioctl_rsp)) {
>>                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> Using unintialized variables doesn't work because runtime checkers like
>> UBSan will complain as well as static checkers.
> 
> I will update the patch to initialize ret_data_len.
> 
>> But the other issue is that this code treats -EINVAL as having a special
>> meaning.  -EINVAL is the most common error code.  All the places which
>> treat -EINVAL as having a special meaning end up buggy in the end.  Mostly
>> they start out buggy, but even the ones which aren't buggy from the start
>> end up buggy over time.
> 
> -EINVAL is mapped from the SMB2 server returned error
> STATUS_INVALID_PARAMETER, so I don't know if there is anything that can
> be done here.
> 
> After your email, I considered returning -EOPNOTSUPP instead to trigger
> kernel-side copy fallback, but returning -EINVAL also seems to have the
> practical advantage of having a successful copy, but with fewer network
> roundtrips (apparently due to userspace fallback, but I haven't digged
> too much into it).

Correction: -EOPNOTSUPP seems to result in fewer network roundtrips for
big files. If anyone thinks this is worth digging more into, please let
me know.

But returning either errno will *not* result in an error to userpace in
case of cp.

> 
> If there's consensus that changing this error mapping would improve the
> overall robustness of the code path, I'm open to that approach.
> 

-- 
Henrique
SUSE Labs

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-09-18 21:02 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-18  9:44 [bug report] smb: client: batch SRV_COPYCHUNK entries to cut roundtrips Dan Carpenter
2025-09-18 20:19 ` Henrique Carvalho
2025-09-18 20:59   ` Henrique Carvalho

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.