Commit 0b0dfd59 authored by Long Li's avatar Long Li Committed by Steve French

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: default avatarLong Li <longli@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
Reviewed-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
parent d53e292f
...@@ -3361,44 +3361,55 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata, ...@@ -3361,44 +3361,55 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata,
struct TCP_Server_Info *server = struct TCP_Server_Info *server =
tlink_tcon(rdata->cfile->tlink)->ses->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 { 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); &rsize, &credits);
if (rc) if (rc)
goto out; goto fail;
if (rsize < rdata->bytes) { if (rsize < rdata->bytes) {
add_credits_and_wake_if(server, &credits, 0); add_credits_and_wake_if(server, &credits, 0);
msleep(1000); msleep(1000);
} }
} while (rsize < rdata->bytes); } while (rsize < rdata->bytes);
rdata->credits = credits;
rdata->credits = credits; rc = adjust_credits(server, &rdata->credits, rdata->bytes);
rc = -EAGAIN; if (!rc) {
while (rc == -EAGAIN) { if (rdata->cfile->invalidHandle)
rc = 0; rc = -EAGAIN;
if (rdata->cfile->invalidHandle) else
rc = cifs_reopen_file(rdata->cfile, true); rc = server->ops->async_readv(rdata);
if (!rc) }
rc = server->ops->async_readv(rdata);
}
if (!rc) { /* If the read was successfully sent, we are done */
/* Add to aio pending list */ if (!rc) {
list_add_tail(&rdata->list, rdata_list); /* Add to aio pending list */
return 0; list_add_tail(&rdata->list, rdata_list);
} return 0;
}
add_credits_and_wake_if(server, &rdata->credits, 0); /* Roll back credits and retry if needed */
out: add_credits_and_wake_if(server, &rdata->credits, 0);
kref_put(&rdata->refcount, } while (rc == -EAGAIN);
cifs_uncached_readdata_release);
fail:
kref_put(&rdata->refcount, cifs_uncached_readdata_release);
return rc; return rc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment