mptcp: refactor push_pending logic

To support redundant package schedulers more easily, this patch refactors
__mptcp_push_pending() logic from:

For each dfrag:
	While sends succeed:
		Call the scheduler (selects subflow and msk->snd_burst)
		Update subflow locks (push/release/acquire as needed)
		Send the dfrag data with mptcp_sendmsg_frag()
		Update already_sent, snd_nxt, snd_burst
	Update msk->first_pending
Push/release on final subflow

->

While first_pending isn't empty:
	Call the scheduler (selects subflow and msk->snd_burst)
	Update subflow locks (push/release/acquire as needed)
	For each pending dfrag:
		While sends succeed:
			Send the dfrag data with mptcp_sendmsg_frag()
			Update already_sent, snd_nxt, snd_burst
		Update msk->first_pending
		Break if required by msk->snd_burst / etc
	Push/release on final subflow

Refactors __mptcp_subflow_push_pending logic from:

For each dfrag:
	While sends succeed:
		Call the scheduler (selects subflow and msk->snd_burst)
		Send the dfrag data with mptcp_subflow_delegate(), break
		Send the dfrag data with mptcp_sendmsg_frag()
		Update dfrag->already_sent, msk->snd_nxt, msk->snd_burst
	Update msk->first_pending

->

While first_pending isn't empty:
	Call the scheduler (selects subflow and msk->snd_burst)
	Send the dfrag data with mptcp_subflow_delegate(), break
	Send the dfrag data with mptcp_sendmsg_frag()
	For each pending dfrag:
		While sends succeed:
			Send the dfrag data with mptcp_sendmsg_frag()
			Update already_sent, snd_nxt, snd_burst
		Update msk->first_pending
		Break if required by msk->snd_burst / etc

Move the duplicate code from __mptcp_push_pending() and
__mptcp_subflow_push_pending() into a new helper function, named
__subflow_push_pending(). Simplify __mptcp_push_pending() and
__mptcp_subflow_push_pending() by invoking this helper.

Also move the burst check conditions out of the function
mptcp_subflow_get_send(), check them in __subflow_push_pending() in
the inner "for each pending dfrag" loop.

Reviewed-by: Mat Martineau <martineau@kernel.org>
Signed-off-by: Geliang Tang <geliang.tang@suse.com>
Signed-off-by: Mat Martineau <martineau@kernel.org>
Link: https://lore.kernel.org/r/20230821-upstream-net-next-20230818-v1-1-0c860fb256a8@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Geliang Tang 2023-08-21 15:25:12 -07:00 committed by Jakub Kicinski
parent 9817363372
commit c5b4297dee

View File

@ -1386,14 +1386,6 @@ static struct sock *mptcp_subflow_get_send(struct mptcp_sock *msk)
sk_stream_memory_free(msk->first) ? msk->first : NULL; sk_stream_memory_free(msk->first) ? msk->first : NULL;
} }
/* re-use last subflow, if the burst allow that */
if (msk->last_snd && msk->snd_burst > 0 &&
sk_stream_memory_free(msk->last_snd) &&
mptcp_subflow_active(mptcp_subflow_ctx(msk->last_snd))) {
mptcp_set_timeout(sk);
return msk->last_snd;
}
/* pick the subflow with the lower wmem/wspace ratio */ /* pick the subflow with the lower wmem/wspace ratio */
for (i = 0; i < SSK_MODE_MAX; ++i) { for (i = 0; i < SSK_MODE_MAX; ++i) {
send_info[i].ssk = NULL; send_info[i].ssk = NULL;
@ -1499,6 +1491,48 @@ void mptcp_check_and_set_pending(struct sock *sk)
mptcp_sk(sk)->push_pending |= BIT(MPTCP_PUSH_PENDING); mptcp_sk(sk)->push_pending |= BIT(MPTCP_PUSH_PENDING);
} }
static int __subflow_push_pending(struct sock *sk, struct sock *ssk,
struct mptcp_sendmsg_info *info)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct mptcp_data_frag *dfrag;
int len, copied = 0, err = 0;
while ((dfrag = mptcp_send_head(sk))) {
info->sent = dfrag->already_sent;
info->limit = dfrag->data_len;
len = dfrag->data_len - dfrag->already_sent;
while (len > 0) {
int ret = 0;
ret = mptcp_sendmsg_frag(sk, ssk, dfrag, info);
if (ret <= 0) {
err = copied ? : ret;
goto out;
}
info->sent += ret;
copied += ret;
len -= ret;
mptcp_update_post_push(msk, dfrag, ret);
}
WRITE_ONCE(msk->first_pending, mptcp_send_next(sk));
if (msk->snd_burst <= 0 ||
!sk_stream_memory_free(ssk) ||
!mptcp_subflow_active(mptcp_subflow_ctx(ssk))) {
err = copied;
goto out;
}
mptcp_set_timeout(sk);
}
err = copied;
out:
return err;
}
void __mptcp_push_pending(struct sock *sk, unsigned int flags) void __mptcp_push_pending(struct sock *sk, unsigned int flags)
{ {
struct sock *prev_ssk = NULL, *ssk = NULL; struct sock *prev_ssk = NULL, *ssk = NULL;
@ -1507,49 +1541,36 @@ void __mptcp_push_pending(struct sock *sk, unsigned int flags)
.flags = flags, .flags = flags,
}; };
bool do_check_data_fin = false; bool do_check_data_fin = false;
struct mptcp_data_frag *dfrag;
int len;
while ((dfrag = mptcp_send_head(sk))) { while (mptcp_send_head(sk)) {
info.sent = dfrag->already_sent; int ret = 0;
info.limit = dfrag->data_len;
len = dfrag->data_len - dfrag->already_sent;
while (len > 0) {
int ret = 0;
prev_ssk = ssk; prev_ssk = ssk;
ssk = mptcp_subflow_get_send(msk); ssk = mptcp_subflow_get_send(msk);
/* First check. If the ssk has changed since /* First check. If the ssk has changed since
* the last round, release prev_ssk * the last round, release prev_ssk
*/ */
if (ssk != prev_ssk && prev_ssk) if (ssk != prev_ssk && prev_ssk)
mptcp_push_release(prev_ssk, &info); mptcp_push_release(prev_ssk, &info);
if (!ssk) if (!ssk)
goto out; goto out;
/* Need to lock the new subflow only if different /* Need to lock the new subflow only if different
* from the previous one, otherwise we are still * from the previous one, otherwise we are still
* helding the relevant lock * helding the relevant lock
*/ */
if (ssk != prev_ssk) if (ssk != prev_ssk)
lock_sock(ssk); lock_sock(ssk);
ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info); ret = __subflow_push_pending(sk, ssk, &info);
if (ret <= 0) { if (ret <= 0) {
if (ret == -EAGAIN) if (ret == -EAGAIN)
continue; continue;
mptcp_push_release(ssk, &info); mptcp_push_release(ssk, &info);
goto out; goto out;
}
do_check_data_fin = true;
info.sent += ret;
len -= ret;
mptcp_update_post_push(msk, dfrag, ret);
} }
WRITE_ONCE(msk->first_pending, mptcp_send_next(sk)); do_check_data_fin = true;
} }
/* at this point we held the socket lock for the last subflow we used */ /* at this point we held the socket lock for the last subflow we used */
@ -1570,42 +1591,30 @@ static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk, bool
struct mptcp_sendmsg_info info = { struct mptcp_sendmsg_info info = {
.data_lock_held = true, .data_lock_held = true,
}; };
struct mptcp_data_frag *dfrag;
struct sock *xmit_ssk; struct sock *xmit_ssk;
int len, copied = 0; int copied = 0;
info.flags = 0; info.flags = 0;
while ((dfrag = mptcp_send_head(sk))) { while (mptcp_send_head(sk)) {
info.sent = dfrag->already_sent; int ret = 0;
info.limit = dfrag->data_len;
len = dfrag->data_len - dfrag->already_sent;
while (len > 0) {
int ret = 0;
/* check for a different subflow usage only after /* check for a different subflow usage only after
* spooling the first chunk of data * spooling the first chunk of data
*/ */
xmit_ssk = first ? ssk : mptcp_subflow_get_send(msk); xmit_ssk = first ? ssk : mptcp_subflow_get_send(msk);
if (!xmit_ssk) if (!xmit_ssk)
goto out; goto out;
if (xmit_ssk != ssk) { if (xmit_ssk != ssk) {
mptcp_subflow_delegate(mptcp_subflow_ctx(xmit_ssk), mptcp_subflow_delegate(mptcp_subflow_ctx(xmit_ssk),
MPTCP_DELEGATE_SEND); MPTCP_DELEGATE_SEND);
goto out; goto out;
}
ret = mptcp_sendmsg_frag(sk, ssk, dfrag, &info);
if (ret <= 0)
goto out;
info.sent += ret;
copied += ret;
len -= ret;
first = false;
mptcp_update_post_push(msk, dfrag, ret);
} }
WRITE_ONCE(msk->first_pending, mptcp_send_next(sk));
ret = __subflow_push_pending(sk, ssk, &info);
first = false;
if (ret <= 0)
break;
copied += ret;
} }
out: out: