diff options
| author | Long Li <longli@microsoft.com> | 2019-03-15 03:55:00 -0400 |
|---|---|---|
| committer | Steve French <stfrench@microsoft.com> | 2019-03-22 23:36:54 -0400 |
| commit | 0b0dfd59216755cfa5a47eab2811efaa4589db68 (patch) | |
| tree | 0b2ff94078470eba4bb0152a616c1033a4e4113a | |
| parent | d53e292f0f505783d0219f58f8f8f294f45f4ee6 (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.c | 71 |
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 */ |
| 3398 | out: | 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 | ||
| 3411 | fail: | ||
| 3412 | kref_put(&rdata->refcount, cifs_uncached_readdata_release); | ||
| 3402 | return rc; | 3413 | return rc; |
| 3403 | } | 3414 | } |
| 3404 | 3415 | ||
