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

Commit 0380ed9b authored by Pavel Shilovsky's avatar Pavel Shilovsky Committed by Greg Kroah-Hartman
Browse files

CIFS: Fix credits calculations for reads with errors



commit 8004c78c68e894e4fd5ac3c22cc22eb7dc24cabc upstream.

Currently we mark MID as malformed if we get an error from server
in a read response. This leads to not properly processing credits
in the readv callback. Fix this by marking such a response as
normal received response and process it appropriately.

Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarPavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: default avatarRonnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 07b9e5e3
Loading
Loading
Loading
Loading
+23 −12
Original line number Diff line number Diff line
@@ -1458,18 +1458,26 @@ cifs_discard_remaining_data(struct TCP_Server_Info *server)
}

static int
cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid,
		     bool malformed)
{
	int length;
	struct cifs_readdata *rdata = mid->callback_data;

	length = cifs_discard_remaining_data(server);
	dequeue_mid(mid, rdata->result);
	dequeue_mid(mid, malformed);
	mid->resp_buf = server->smallbuf;
	server->smallbuf = NULL;
	return length;
}

static int
cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
	struct cifs_readdata *rdata = mid->callback_data;

	return  __cifs_readv_discard(server, mid, rdata->result);
}

int
cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
@@ -1511,12 +1519,23 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
		return -1;
	}

	/* set up first two iov for signature check and to get credits */
	rdata->iov[0].iov_base = buf;
	rdata->iov[0].iov_len = 4;
	rdata->iov[1].iov_base = buf + 4;
	rdata->iov[1].iov_len = server->total_read - 4;
	cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
		 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
	cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
		 rdata->iov[1].iov_base, rdata->iov[1].iov_len);

	/* Was the SMB read successful? */
	rdata->result = server->ops->map_error(buf, false);
	if (rdata->result != 0) {
		cifs_dbg(FYI, "%s: server returned error %d\n",
			 __func__, rdata->result);
		return cifs_readv_discard(server, mid);
		/* normal error on read response */
		return __cifs_readv_discard(server, mid, false);
	}

	/* Is there enough to get to the rest of the READ_RSP header? */
@@ -1560,14 +1579,6 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
		server->total_read += length;
	}

	/* set up first iov for signature check */
	rdata->iov[0].iov_base = buf;
	rdata->iov[0].iov_len = 4;
	rdata->iov[1].iov_base = buf + 4;
	rdata->iov[1].iov_len = server->total_read - 4;
	cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n",
		 rdata->iov[0].iov_base, server->total_read);

	/* how much data is in the response? */
#ifdef CONFIG_CIFS_SMB_DIRECT
	use_rdma_mr = rdata->mr;