CIFS: Fix an issue with re-sending rdata when transport returning -EAGAIN
When sending a rdata, transport may return -EAGAIN. In this case we should re-obtain credits because the session may have been reconnected. Change in v2: adjust_credits before re-sending Signed-off-by: Long Li <longli@microsoft.com> Signed-off-by: Steve French <stfrench@microsoft.com> Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
This commit is contained in:
parent
d53e292f0f
commit
0b0dfd5921
|
@ -3361,44 +3361,55 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata,
|
|||
struct TCP_Server_Info *server =
|
||||
tlink_tcon(rdata->cfile->tlink)->ses->server;
|
||||
|
||||
/*
|
||||
* Wait for credits to resend this rdata.
|
||||
* Note: we are attempting to resend the whole rdata not in segments
|
||||
*/
|
||||
do {
|
||||
rc = server->ops->wait_mtu_credits(server, rdata->bytes,
|
||||
if (rdata->cfile->invalidHandle) {
|
||||
rc = cifs_reopen_file(rdata->cfile, true);
|
||||
if (rc == -EAGAIN)
|
||||
continue;
|
||||
else if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for credits to resend this rdata.
|
||||
* Note: we are attempting to resend the whole rdata not in
|
||||
* segments
|
||||
*/
|
||||
do {
|
||||
rc = server->ops->wait_mtu_credits(server, rdata->bytes,
|
||||
&rsize, &credits);
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
if (rsize < rdata->bytes) {
|
||||
add_credits_and_wake_if(server, &credits, 0);
|
||||
msleep(1000);
|
||||
if (rsize < rdata->bytes) {
|
||||
add_credits_and_wake_if(server, &credits, 0);
|
||||
msleep(1000);
|
||||
}
|
||||
} while (rsize < rdata->bytes);
|
||||
rdata->credits = credits;
|
||||
|
||||
rc = adjust_credits(server, &rdata->credits, rdata->bytes);
|
||||
if (!rc) {
|
||||
if (rdata->cfile->invalidHandle)
|
||||
rc = -EAGAIN;
|
||||
else
|
||||
rc = server->ops->async_readv(rdata);
|
||||
}
|
||||
} while (rsize < rdata->bytes);
|
||||
|
||||
rdata->credits = credits;
|
||||
rc = -EAGAIN;
|
||||
while (rc == -EAGAIN) {
|
||||
rc = 0;
|
||||
if (rdata->cfile->invalidHandle)
|
||||
rc = cifs_reopen_file(rdata->cfile, true);
|
||||
if (!rc)
|
||||
rc = server->ops->async_readv(rdata);
|
||||
}
|
||||
/* If the read was successfully sent, we are done */
|
||||
if (!rc) {
|
||||
/* Add to aio pending list */
|
||||
list_add_tail(&rdata->list, rdata_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!rc) {
|
||||
/* Add to aio pending list */
|
||||
list_add_tail(&rdata->list, rdata_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
add_credits_and_wake_if(server, &rdata->credits, 0);
|
||||
out:
|
||||
kref_put(&rdata->refcount,
|
||||
cifs_uncached_readdata_release);
|
||||
/* Roll back credits and retry if needed */
|
||||
add_credits_and_wake_if(server, &rdata->credits, 0);
|
||||
} while (rc == -EAGAIN);
|
||||
|
||||
fail:
|
||||
kref_put(&rdata->refcount, cifs_uncached_readdata_release);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue