Commit cfe76fdb authored by Stefan Metzmacher's avatar Stefan Metzmacher Committed by Steve French
Browse files

smb: server: let recv_done() consistently call put_recvmsg/smb_direct_disconnect_rdma_connection



We should call put_recvmsg() before smb_direct_disconnect_rdma_connection()
in order to call it before waking up the callers.

In all error cases we should call smb_direct_disconnect_rdma_connection()
in order to avoid stale connections.

Cc: Namjae Jeon <linkinjeon@kernel.org>
Cc: Steve French <smfrench@gmail.com>
Cc: Tom Talpey <tom@talpey.com>
Cc: linux-cifs@vger.kernel.org
Cc: samba-technical@lists.samba.org
Fixes: 0626e664 ("cifsd: add server handler for central processing and tranport layers")
Signed-off-by: default avatarStefan Metzmacher <metze@samba.org>
Acked-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent afb4108c
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -521,13 +521,13 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
	t = recvmsg->transport;

	if (wc->status != IB_WC_SUCCESS || wc->opcode != IB_WC_RECV) {
		put_recvmsg(t, recvmsg);
		if (wc->status != IB_WC_WR_FLUSH_ERR) {
			pr_err("Recv error. status='%s (%d)' opcode=%d\n",
			       ib_wc_status_msg(wc->status), wc->status,
			       wc->opcode);
			smb_direct_disconnect_rdma_connection(t);
		}
		put_recvmsg(t, recvmsg);
		return;
	}

@@ -542,6 +542,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
	case SMB_DIRECT_MSG_NEGOTIATE_REQ:
		if (wc->byte_len < sizeof(struct smb_direct_negotiate_req)) {
			put_recvmsg(t, recvmsg);
			smb_direct_disconnect_rdma_connection(t);
			return;
		}
		t->negotiation_requested = true;
@@ -549,7 +550,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
		t->status = SMB_DIRECT_CS_CONNECTED;
		enqueue_reassembly(t, recvmsg, 0);
		wake_up_interruptible(&t->wait_status);
		break;
		return;
	case SMB_DIRECT_MSG_DATA_TRANSFER: {
		struct smb_direct_data_transfer *data_transfer =
			(struct smb_direct_data_transfer *)recvmsg->packet;
@@ -559,6 +560,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
		if (wc->byte_len <
		    offsetof(struct smb_direct_data_transfer, padding)) {
			put_recvmsg(t, recvmsg);
			smb_direct_disconnect_rdma_connection(t);
			return;
		}

@@ -567,6 +569,7 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
			if (wc->byte_len < sizeof(struct smb_direct_data_transfer) +
			    (u64)data_length) {
				put_recvmsg(t, recvmsg);
				smb_direct_disconnect_rdma_connection(t);
				return;
			}

@@ -609,11 +612,16 @@ static void recv_done(struct ib_cq *cq, struct ib_wc *wc)
		if (is_receive_credit_post_required(receive_credits, avail_recvmsg_count))
			mod_delayed_work(smb_direct_wq,
					 &t->post_recv_credits_work, 0);
		break;
		return;
	}
	default:
		break;
	}

	/*
	 * This is an internal error!
	 */
	WARN_ON_ONCE(recvmsg->type != SMB_DIRECT_MSG_DATA_TRANSFER);
	put_recvmsg(t, recvmsg);
	smb_direct_disconnect_rdma_connection(t);
}

static int smb_direct_post_recv(struct smb_direct_transport *t,