mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 23:52:08 +02:00
cifs: make retry logic in read/write path consistent with other paths
Today in most other code paths in cifs.ko, the decision of whether to retry a command depends on two mount options: retrans and hard. However, the read/write code paths diverged from this and would only retry if the error returned was -EAGAIN. However, there are other replayable errors in cifs.ko, for which is_replayable_errors helper was written. This change makes read/write codepaths consistent with other code-paths. This change also does the following: 1. The SMB2 read/write code diverged significantly (presumably since they were changed during netfs refactor at different times). This changes the response verification logic to be consistent. 2. Moves the netfs tracepoints to slightly different locations in order to make debugging easier. Cc: David Howells <dhowells@redhat.com> Signed-off-by: Shyam Prasad N <sprasad@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
a5ca32d031
commit
2c1238a747
|
|
@ -1507,6 +1507,8 @@ struct cifs_io_subrequest {
|
|||
int result;
|
||||
bool have_xid;
|
||||
bool replay;
|
||||
unsigned int retries; /* number of retries so far */
|
||||
unsigned int cur_sleep; /* time to sleep before replay */
|
||||
struct kvec iov[2];
|
||||
struct TCP_Server_Info *server;
|
||||
#ifdef CONFIG_CIFS_SMB_DIRECT
|
||||
|
|
|
|||
|
|
@ -4650,9 +4650,19 @@ smb2_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
|
||||
iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes);
|
||||
rc = smb2_verify_signature(&rqst, server);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
cifs_tcon_dbg(VFS, "SMB signature verification returned error = %d\n",
|
||||
rc);
|
||||
rc);
|
||||
rdata->subreq.error = rc;
|
||||
rdata->result = rc;
|
||||
|
||||
if (is_replayable_error(rc)) {
|
||||
trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_retry_needed);
|
||||
__set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags);
|
||||
} else
|
||||
trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_bad);
|
||||
} else
|
||||
trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress);
|
||||
}
|
||||
/* FIXME: should this be counted toward the initiating task? */
|
||||
task_io_account_read(rdata->got_bytes);
|
||||
|
|
@ -4728,6 +4738,14 @@ smb2_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
if (rdata->got_bytes)
|
||||
__set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags);
|
||||
}
|
||||
|
||||
/* see if we need to retry */
|
||||
if (is_replayable_error(rdata->result) &&
|
||||
smb2_should_replay(tcon,
|
||||
&rdata->retries,
|
||||
&rdata->cur_sleep))
|
||||
rdata->replay = true;
|
||||
|
||||
trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.value,
|
||||
server->credits, server->in_flight,
|
||||
0, cifs_trace_rw_credits_read_response_clear);
|
||||
|
|
@ -4776,7 +4794,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
|
|||
rc = smb2_new_read_req(
|
||||
(void **) &buf, &total_len, &io_parms, rdata, 0, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto out;
|
||||
|
||||
if (smb3_encryption_required(io_parms.tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
|
@ -4788,6 +4806,13 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
|
|||
|
||||
shdr = (struct smb2_hdr *)buf;
|
||||
|
||||
if (rdata->replay) {
|
||||
/* Back-off before retry */
|
||||
if (rdata->cur_sleep)
|
||||
msleep(rdata->cur_sleep);
|
||||
smb2_set_replay(server, &rqst);
|
||||
}
|
||||
|
||||
if (rdata->credits.value > 0) {
|
||||
shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(io_parms.length,
|
||||
SMB2_MAX_BUFFER_SIZE));
|
||||
|
|
@ -4823,6 +4848,17 @@ smb2_async_readv(struct cifs_io_subrequest *rdata)
|
|||
|
||||
async_readv_out:
|
||||
cifs_small_buf_release(buf);
|
||||
|
||||
out:
|
||||
/* if the send error is retryable, let netfs know about it */
|
||||
if (is_replayable_error(rc) &&
|
||||
smb2_should_replay(tcon,
|
||||
&rdata->retries,
|
||||
&rdata->cur_sleep)) {
|
||||
trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_retry_needed);
|
||||
__set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -4936,14 +4972,20 @@ smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
|
||||
switch (mid->mid_state) {
|
||||
case MID_RESPONSE_RECEIVED:
|
||||
trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_progress);
|
||||
credits.value = le16_to_cpu(rsp->hdr.CreditRequest);
|
||||
credits.instance = server->reconnect_instance;
|
||||
result = smb2_check_receive(mid, server, 0);
|
||||
if (result != 0) {
|
||||
trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_bad);
|
||||
if (is_replayable_error(result)) {
|
||||
trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_retry_needed);
|
||||
__set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags);
|
||||
} else {
|
||||
wdata->subreq.error = result;
|
||||
trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_bad);
|
||||
}
|
||||
break;
|
||||
}
|
||||
trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_progress);
|
||||
|
||||
written = le32_to_cpu(rsp->DataLength);
|
||||
/*
|
||||
|
|
@ -4958,7 +5000,7 @@ smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
cifs_stats_bytes_written(tcon, written);
|
||||
|
||||
if (written < wdata->subreq.len) {
|
||||
wdata->result = -ENOSPC;
|
||||
result = -ENOSPC;
|
||||
} else if (written > 0) {
|
||||
wdata->subreq.len = written;
|
||||
__set_bit(NETFS_SREQ_MADE_PROGRESS, &wdata->subreq.flags);
|
||||
|
|
@ -5000,6 +5042,7 @@ smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
}
|
||||
#endif
|
||||
if (result) {
|
||||
wdata->result = result;
|
||||
cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
|
||||
trace_smb3_write_err(wdata->rreq->debug_id,
|
||||
wdata->subreq.debug_index,
|
||||
|
|
@ -5022,6 +5065,14 @@ smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|||
server->credits, server->in_flight,
|
||||
0, cifs_trace_rw_credits_write_response_clear);
|
||||
wdata->credits.value = 0;
|
||||
|
||||
/* see if we need to retry */
|
||||
if (is_replayable_error(wdata->result) &&
|
||||
smb2_should_replay(tcon,
|
||||
&wdata->retries,
|
||||
&wdata->cur_sleep))
|
||||
wdata->replay = true;
|
||||
|
||||
cifs_write_subrequest_terminated(wdata, result ?: written);
|
||||
release_mid(server, mid);
|
||||
trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0,
|
||||
|
|
@ -5140,8 +5191,12 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (wdata->subreq.retry_count > 0)
|
||||
if (wdata->replay) {
|
||||
/* Back-off before retry */
|
||||
if (wdata->cur_sleep)
|
||||
msleep(wdata->cur_sleep);
|
||||
smb2_set_replay(server, &rqst);
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "async write at %llu %u bytes iter=%zx\n",
|
||||
io_parms->offset, io_parms->length, iov_iter_count(&wdata->subreq.io_iter));
|
||||
|
|
@ -5187,6 +5242,16 @@ smb2_async_writev(struct cifs_io_subrequest *wdata)
|
|||
async_writev_out:
|
||||
cifs_small_buf_release(req);
|
||||
out:
|
||||
/* if the send error is retryable, let netfs know about it */
|
||||
if (is_replayable_error(rc) &&
|
||||
smb2_should_replay(tcon,
|
||||
&wdata->retries,
|
||||
&wdata->cur_sleep)) {
|
||||
wdata->replay = true;
|
||||
trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_retry_needed);
|
||||
__set_bit(NETFS_SREQ_NEED_RETRY, &wdata->subreq.flags);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
trace_smb3_rw_credits(wdata->rreq->debug_id,
|
||||
wdata->subreq.debug_index,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user