summaryrefslogtreecommitdiff
path: root/fs/smb/client/smb2ops.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2025-10-24 09:25:31 +0100
committerSteve French <stfrench@microsoft.com>2025-12-05 17:11:43 -0600
commitf80ac7eda1cf5205aaa2b676827ae1e312a5a894 (patch)
tree84ab90c4dcb3f23f0c7c03ce5cbe2263073da7e0 /fs/smb/client/smb2ops.c
parent3a7b6d0afe6e01d054c9334cf1203953a0f72a1e (diff)
cifs: Add a tracepoint to log EIO errors
Add a tracepoint to log EIO errors and give it the capacity to convey up to two integers of information. This is then wrapped with three functions: int smb_EIO(enum smb_eio_trace trace) int smb_EIO1(enum smb_eio_trace trace, unsigned long info) int smb_EIO2(enum smb_eio_trace trace, unsigned long info, unsigned long info2) depending on how many bits of info are desired to be logged with any particular trace. The functions all return -EIO and can be used in place of -EIO. The trace argument is an enum value that gets translated to a string when the trace is printed. This makes is easier to log EIO instances when the client is under high load than turning on a printk wrapper such as cifs_dbg(). Granted, EIO could have its own separate EIO printing since EIO shouldn't happen. Signed-off-by: David Howells <dhowells@redhat.com> Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org> cc: linux-cifs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/smb/client/smb2ops.c')
-rw-r--r--fs/smb/client/smb2ops.c41
1 files changed, 25 insertions, 16 deletions
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 760edb98ed64..3328d6a89038 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -1046,7 +1046,8 @@ move_smb2_ea_to_cifs(char *dst, size_t dst_size,
if (src_size < 8 + name_len + 1 + value_len) {
cifs_dbg(FYI, "EA entry goes beyond length of list\n");
- rc = -EIO;
+ rc = smb_EIO2(smb_eio_trace_ea_overrun,
+ src_size, 8 + name_len + 1 + value_len);
goto out;
}
@@ -1607,7 +1608,7 @@ replay_again:
}
if (!ses || !server) {
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_null_pointers);
goto free_vars;
}
@@ -1942,7 +1943,7 @@ retry:
if (unlikely(ret_data_len != sizeof(*cc_rsp))) {
cifs_tcon_dbg(VFS, "Copychunk invalid response: size %u/%zu\n",
ret_data_len, sizeof(*cc_rsp));
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_copychunk_inv_rsp, ret_data_len);
goto out;
}
@@ -1952,11 +1953,18 @@ retry:
if (rc == 0) {
/* Check if server claimed to write more than we asked */
- if (unlikely(!bytes_written || bytes_written > copy_bytes ||
- !chunks_written || chunks_written > chunks)) {
- cifs_tcon_dbg(VFS, "Copychunk invalid response: bytes written %u/%u, chunks written %u/%u\n",
- bytes_written, copy_bytes, chunks_written, chunks);
- rc = -EIO;
+ if (unlikely(!bytes_written || bytes_written > copy_bytes)) {
+ cifs_tcon_dbg(VFS, "Copychunk invalid response: bytes written %u/%u\n",
+ bytes_written, copy_bytes);
+ rc = smb_EIO2(smb_eio_trace_copychunk_overcopy_b,
+ bytes_written, copy_bytes);
+ goto out;
+ }
+ if (unlikely(!chunks_written || chunks_written > chunks)) {
+ cifs_tcon_dbg(VFS, "Copychunk invalid response: chunks written %u/%u\n",
+ chunks_written, chunks);
+ rc = smb_EIO2(smb_eio_trace_copychunk_overcopy_c,
+ chunks_written, chunks);
goto out;
}
@@ -3127,7 +3135,7 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
}
if (!rc && !dfs_rsp)
- rc = -EIO;
+ rc = smb_EIO(smb_eio_trace_dfsref_no_rsp);
if (rc) {
if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP)
cifs_tcon_dbg(FYI, "%s: ioctl error: rc=%d\n", __func__, rc);
@@ -4555,7 +4563,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
buffer, 0, 0, size);
if (!cifs_copy_iter_to_folioq(&old->rq_iter, size, buffer)) {
- rc = -EIO;
+ rc = smb_EIO1(smb_eio_trace_tx_copy_iter_to_buf, size);
goto err_free;
}
}
@@ -4656,7 +4664,8 @@ cifs_copy_folioq_to_iter(struct folio_queue *folioq, size_t data_size,
n = copy_folio_to_iter(folio, skip, len, iter);
if (n != len) {
cifs_dbg(VFS, "%s: something went wrong\n", __func__);
- return -EIO;
+ return smb_EIO2(smb_eio_trace_rx_copy_to_iter,
+ n, len);
}
data_size -= n;
skip = 0;
@@ -4739,7 +4748,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
/* data_offset is beyond the end of smallbuf */
cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
__func__, data_offset);
- rdata->result = -EIO;
+ rdata->result = smb_EIO1(smb_eio_trace_rx_overlong, data_offset);
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
@@ -4758,7 +4767,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
/* data offset is beyond the 1st page of response */
cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
__func__, data_offset);
- rdata->result = -EIO;
+ rdata->result = smb_EIO1(smb_eio_trace_rx_overpage, data_offset);
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
@@ -4768,7 +4777,7 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
if (data_len > buffer_len - pad_len) {
/* data_len is corrupt -- discard frame */
- rdata->result = -EIO;
+ rdata->result = smb_EIO1(smb_eio_trace_rx_bad_datalen, data_len);
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else
@@ -4793,12 +4802,12 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
WARN_ONCE(buffer, "read data can be either in buf or in buffer");
copied = copy_to_iter(buf + data_offset, data_len, &rdata->subreq.io_iter);
if (copied == 0)
- return -EIO;
+ return smb_EIO2(smb_eio_trace_rx_copy_to_iter, copied, data_len);
rdata->got_bytes = copied;
} else {
/* read response payload cannot be in both buf and pages */
WARN_ONCE(1, "buf can not contain only a part of read data");
- rdata->result = -EIO;
+ rdata->result = smb_EIO(smb_eio_trace_rx_both_buf);
if (is_offloaded)
mid->mid_state = MID_RESPONSE_MALFORMED;
else