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

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

CIFS: Fix an issue with re-sending wdata when transport returning -EAGAIN



When sending a wdata, 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 a5ed1e96
Loading
Loading
Loading
Loading
+45 −32
Original line number Diff line number Diff line
@@ -2632,43 +2632,56 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list,
	struct TCP_Server_Info *server =
		tlink_tcon(wdata->cfile->tlink)->ses->server;

	do {
		if (wdata->cfile->invalidHandle) {
			rc = cifs_reopen_file(wdata->cfile, false);
			if (rc == -EAGAIN)
				continue;
			else if (rc)
				break;
		}


		/*
		 * Wait for credits to resend this wdata.
	 * Note: we are attempting to resend the whole wdata not in segments
		 * Note: we are attempting to resend the whole wdata not in
		 * segments
		 */
		do {
		rc = server->ops->wait_mtu_credits(server, wdata->bytes, &wsize,
						   &credits);

			rc = server->ops->wait_mtu_credits(server, wdata->bytes,
						&wsize, &credits);
			if (rc)
			goto out;
				goto fail;

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

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

		rc = adjust_credits(server, &wdata->credits, wdata->bytes);

		if (!rc) {
			if (wdata->cfile->invalidHandle)
			rc = cifs_reopen_file(wdata->cfile, false);
		if (!rc)
				rc = -EAGAIN;
			else
				rc = server->ops->async_writev(wdata,
					cifs_uncached_writedata_release);
		}

		/* If the write was successfully sent, we are done */
		if (!rc) {
			list_add_tail(&wdata->list, wdata_list);
			return 0;
		}

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

fail:
	kref_put(&wdata->refcount, cifs_uncached_writedata_release);
	return rc;
}

@@ -2896,12 +2909,12 @@ static void collect_uncached_write_data(struct cifs_aio_ctx *ctx)
						wdata->bytes, &tmp_from,
						ctx->cfile, cifs_sb, &tmp_list,
						ctx);
				}

				list_splice(&tmp_list, &ctx->list);

					kref_put(&wdata->refcount,
						cifs_uncached_writedata_release);
				}

				list_splice(&tmp_list, &ctx->list);
				goto restart_loop;
			}
		}