History

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

Long Li committed 7 years ago

Commit 0b0dfd51 parent d53e2921 file · +41 −30Browse files

Unified · Split

fs/cifs/file.c+41−30
@@ -3361,44 +3361,55 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata, · 3360 unmodified lines
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