Skip to content

Commit

Permalink
CIFS: Fix an issue with re-sending rdata when transport returning -EA…
Browse files Browse the repository at this point in the history
…GAIN

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 <[email protected]>
Signed-off-by: Steve French <[email protected]>
Reviewed-by: Pavel Shilovsky <[email protected]>
  • Loading branch information
longlimsft authored and Steve French committed Mar 23, 2019
1 parent d53e292 commit 0b0dfd5
Showing 1 changed file with 41 additions and 30 deletions.
71 changes: 41 additions & 30 deletions fs/cifs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
} while (rsize < rdata->bytes);
if (rsize < rdata->bytes) {
add_credits_and_wake_if(server, &credits, 0);
msleep(1000);
}
} while (rsize < rdata->bytes);
rdata->credits = credits;

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);
}
rc = adjust_credits(server, &rdata->credits, rdata->bytes);
if (!rc) {
if (rdata->cfile->invalidHandle)
rc = -EAGAIN;
else
rc = server->ops->async_readv(rdata);
}

if (!rc) {
/* Add to aio pending list */
list_add_tail(&rdata->list, rdata_list);
return 0;
}
/* 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;
}

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;
}

Expand Down

0 comments on commit 0b0dfd5

Please sign in to comment.