aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLong Li <longli@microsoft.com>2019-03-15 03:55:00 -0400
committerSteve French <stfrench@microsoft.com>2019-03-22 23:36:54 -0400
commit0b0dfd59216755cfa5a47eab2811efaa4589db68 (patch)
tree0b2ff94078470eba4bb0152a616c1033a4e4113a
parentd53e292f0f505783d0219f58f8f8f294f45f4ee6 (diff)
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>
-rw-r--r--fs/cifs/file.c71
1 files changed, 41 insertions, 30 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 2aa3e62af764..89006e044973 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -3361,44 +3361,55 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata,
3361 struct TCP_Server_Info *server = 3361 struct TCP_Server_Info *server =
3362 tlink_tcon(rdata->cfile->tlink)->ses->server; 3362 tlink_tcon(rdata->cfile->tlink)->ses->server;
3363 3363
3364 /*
3365 * Wait for credits to resend this rdata.
3366 * Note: we are attempting to resend the whole rdata not in segments
3367 */
3368 do { 3364 do {
3369 rc = server->ops->wait_mtu_credits(server, rdata->bytes, 3365 if (rdata->cfile->invalidHandle) {
3366 rc = cifs_reopen_file(rdata->cfile, true);
3367 if (rc == -EAGAIN)
3368 continue;
3369 else if (rc)
3370 break;
3371 }
3372
3373 /*
3374 * Wait for credits to resend this rdata.
3375 * Note: we are attempting to resend the whole rdata not in
3376 * segments
3377 */
3378 do {
3379 rc = server->ops->wait_mtu_credits(server, rdata->bytes,
3370 &rsize, &credits); 3380 &rsize, &credits);
3371 3381
3372 if (rc) 3382 if (rc)
3373 goto out; 3383 goto fail;
3374 3384
3375 if (rsize < rdata->bytes) { 3385 if (rsize < rdata->bytes) {
3376 add_credits_and_wake_if(server, &credits, 0); 3386 add_credits_and_wake_if(server, &credits, 0);
3377 msleep(1000); 3387 msleep(1000);
3378 } 3388 }
3379 } while (rsize < rdata->bytes); 3389 } while (rsize < rdata->bytes);
3390 rdata->credits = credits;
3380 3391
3381 rdata->credits = credits; 3392 rc = adjust_credits(server, &rdata->credits, rdata->bytes);
3382 rc = -EAGAIN; 3393 if (!rc) {
3383 while (rc == -EAGAIN) { 3394 if (rdata->cfile->invalidHandle)
3384 rc = 0; 3395 rc = -EAGAIN;
3385 if (rdata->cfile->invalidHandle) 3396 else
3386 rc = cifs_reopen_file(rdata->cfile, true); 3397 rc = server->ops->async_readv(rdata);
3387 if (!rc) 3398 }
3388 rc = server->ops->async_readv(rdata);
3389 }
3390 3399
3391 if (!rc) { 3400 /* If the read was successfully sent, we are done */
3392 /* Add to aio pending list */ 3401 if (!rc) {
3393 list_add_tail(&rdata->list, rdata_list); 3402 /* Add to aio pending list */
3394 return 0; 3403 list_add_tail(&rdata->list, rdata_list);
3395 } 3404 return 0;
3405 }
3396 3406
3397 add_credits_and_wake_if(server, &rdata->credits, 0); 3407 /* Roll back credits and retry if needed */
3398out: 3408 add_credits_and_wake_if(server, &rdata->credits, 0);
3399 kref_put(&rdata->refcount, 3409 } while (rc == -EAGAIN);
3400 cifs_uncached_readdata_release);
3401 3410
3411fail:
3412 kref_put(&rdata->refcount, cifs_uncached_readdata_release);
3402 return rc; 3413 return rc;
3403} 3414}
3404 3415