Commit d53e292f authored by Long Li's avatar Long Li Committed by Steve French

CIFS: Fix an issue with re-sending wdata when transport returning -EAGAIN

When sending a wdata, 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 a5ed1e96
...@@ -2632,43 +2632,56 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, ...@@ -2632,43 +2632,56 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
struct TCP_Server_Info *server = struct TCP_Server_Info *server =
tlink_tcon(wdata->cfile->tlink)->ses->server; tlink_tcon(wdata->cfile->tlink)->ses->server;
/*
* Wait for credits to resend this wdata.
* Note: we are attempting to resend the whole wdata not in segments
*/
do { do {
rc = server->ops->wait_mtu_credits(server, wdata->bytes, &wsize, if (wdata->cfile->invalidHandle) {
&credits); rc = cifs_reopen_file(wdata->cfile, false);
if (rc == -EAGAIN)
continue;
else if (rc)
break;
}
if (rc)
goto out;
if (wsize < wdata->bytes) { /*
add_credits_and_wake_if(server, &credits, 0); * Wait for credits to resend this wdata.
msleep(1000); * Note: we are attempting to resend the whole wdata not in
} * segments
} while (wsize < wdata->bytes); */
do {
rc = server->ops->wait_mtu_credits(server, wdata->bytes,
&wsize, &credits);
if (rc)
goto fail;
if (wsize < wdata->bytes) {
add_credits_and_wake_if(server, &credits, 0);
msleep(1000);
}
} while (wsize < wdata->bytes);
wdata->credits = credits;
wdata->credits = credits; rc = adjust_credits(server, &wdata->credits, wdata->bytes);
rc = -EAGAIN;
while (rc == -EAGAIN) { if (!rc) {
rc = 0; if (wdata->cfile->invalidHandle)
if (wdata->cfile->invalidHandle) rc = -EAGAIN;
rc = cifs_reopen_file(wdata->cfile, false); else
if (!rc) rc = server->ops->async_writev(wdata,
rc = server->ops->async_writev(wdata,
cifs_uncached_writedata_release); cifs_uncached_writedata_release);
} }
if (!rc) { /* If the write was successfully sent, we are done */
list_add_tail(&wdata->list, wdata_list); if (!rc) {
return 0; list_add_tail(&wdata->list, wdata_list);
} return 0;
}
add_credits_and_wake_if(server, &wdata->credits, 0); /* Roll back credits and retry if needed */
out: add_credits_and_wake_if(server, &wdata->credits, 0);
kref_put(&wdata->refcount, cifs_uncached_writedata_release); } while (rc == -EAGAIN);
fail:
kref_put(&wdata->refcount, cifs_uncached_writedata_release);
return rc; return rc;
} }
...@@ -2896,12 +2909,12 @@ static void collect_uncached_write_data(struct cifs_aio_ctx *ctx) ...@@ -2896,12 +2909,12 @@ static void collect_uncached_write_data(struct cifs_aio_ctx *ctx)
wdata->bytes, &tmp_from, wdata->bytes, &tmp_from,
ctx->cfile, cifs_sb, &tmp_list, ctx->cfile, cifs_sb, &tmp_list,
ctx); ctx);
kref_put(&wdata->refcount,
cifs_uncached_writedata_release);
} }
list_splice(&tmp_list, &ctx->list); list_splice(&tmp_list, &ctx->list);
kref_put(&wdata->refcount,
cifs_uncached_writedata_release);
goto restart_loop; goto restart_loop;
} }
} }
......
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