Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b0dfd59 authored by Long Li's avatar Long Li Committed by Steve French
Browse files

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: default avatarLong Li <longli@microsoft.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
Reviewed-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
parent d53e292f
Loading
Loading
Loading
Loading
+41 −30
Original line number Diff line number Diff line
@@ -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;

	do {
		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
		 * 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;
				goto fail;

			if (rsize < rdata->bytes) {
				add_credits_and_wake_if(server, &credits, 0);
				msleep(1000);
			}
		} while (rsize < rdata->bytes);

		rdata->credits = credits;
	rc = -EAGAIN;
	while (rc == -EAGAIN) {
		rc = 0;

		rc = adjust_credits(server, &rdata->credits, rdata->bytes);
		if (!rc) {
			if (rdata->cfile->invalidHandle)
			rc = cifs_reopen_file(rdata->cfile, true);
		if (!rc)
				rc = -EAGAIN;
			else
				rc = server->ops->async_readv(rdata);
		}

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

		/* Roll back credits and retry if needed */
		add_credits_and_wake_if(server, &rdata->credits, 0);
out:
	kref_put(&rdata->refcount,
		cifs_uncached_readdata_release);
	} while (rc == -EAGAIN);

fail:
	kref_put(&rdata->refcount, cifs_uncached_readdata_release);
	return rc;
}