Skip to content

Commit e93da92

Browse files
Paolo Abenikuba-moo
authored andcommitted
mptcp: implement wmem reservation
This leverages the previous commit to reserve the wmem required for the sendmsg() operation when the msk socket lock is first acquired. Some heuristics are used to get a reasonable [over] estimation of the whole memory required. If we can't forward alloc such amount fallback to a reasonable small chunk, otherwise enter the wait for memory path. When sendmsg() needs more memory it looks at wmem_reserved first and if that is exhausted, move more space from sk_forward_alloc. The reserved memory is not persistent and is released at the next socket unlock via the release_cb(). Overall this will simplify the next patch. Acked-by: Florian Westphal <[email protected]> Signed-off-by: Paolo Abeni <[email protected]> Reviewed-by: Mat Martineau <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent ad80b0f commit e93da92

File tree

2 files changed

+86
-7
lines changed

2 files changed

+86
-7
lines changed

net/mptcp/protocol.c

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,81 @@ static bool mptcp_frag_can_collapse_to(const struct mptcp_sock *msk,
873873
df->data_seq + df->data_len == msk->write_seq;
874874
}
875875

876+
static int mptcp_wmem_with_overhead(int size)
877+
{
878+
return size + ((sizeof(struct mptcp_data_frag) * size) >> PAGE_SHIFT);
879+
}
880+
881+
static void __mptcp_wmem_reserve(struct sock *sk, int size)
882+
{
883+
int amount = mptcp_wmem_with_overhead(size);
884+
struct mptcp_sock *msk = mptcp_sk(sk);
885+
886+
WARN_ON_ONCE(msk->wmem_reserved);
887+
if (amount <= sk->sk_forward_alloc)
888+
goto reserve;
889+
890+
/* under memory pressure try to reserve at most a single page
891+
* otherwise try to reserve the full estimate and fallback
892+
* to a single page before entering the error path
893+
*/
894+
if ((tcp_under_memory_pressure(sk) && amount > PAGE_SIZE) ||
895+
!sk_wmem_schedule(sk, amount)) {
896+
if (amount <= PAGE_SIZE)
897+
goto nomem;
898+
899+
amount = PAGE_SIZE;
900+
if (!sk_wmem_schedule(sk, amount))
901+
goto nomem;
902+
}
903+
904+
reserve:
905+
msk->wmem_reserved = amount;
906+
sk->sk_forward_alloc -= amount;
907+
return;
908+
909+
nomem:
910+
/* we will wait for memory on next allocation */
911+
msk->wmem_reserved = -1;
912+
}
913+
914+
static void __mptcp_update_wmem(struct sock *sk)
915+
{
916+
struct mptcp_sock *msk = mptcp_sk(sk);
917+
918+
if (!msk->wmem_reserved)
919+
return;
920+
921+
if (msk->wmem_reserved < 0)
922+
msk->wmem_reserved = 0;
923+
if (msk->wmem_reserved > 0) {
924+
sk->sk_forward_alloc += msk->wmem_reserved;
925+
msk->wmem_reserved = 0;
926+
}
927+
}
928+
929+
static bool mptcp_wmem_alloc(struct sock *sk, int size)
930+
{
931+
struct mptcp_sock *msk = mptcp_sk(sk);
932+
933+
/* check for pre-existing error condition */
934+
if (msk->wmem_reserved < 0)
935+
return false;
936+
937+
if (msk->wmem_reserved >= size)
938+
goto account;
939+
940+
if (!sk_wmem_schedule(sk, size))
941+
return false;
942+
943+
sk->sk_forward_alloc -= size;
944+
msk->wmem_reserved += size;
945+
946+
account:
947+
msk->wmem_reserved -= size;
948+
return true;
949+
}
950+
876951
static void dfrag_uncharge(struct sock *sk, int len)
877952
{
878953
sk_mem_uncharge(sk, len);
@@ -930,7 +1005,7 @@ static void mptcp_clean_una(struct sock *sk)
9301005
}
9311006

9321007
out:
933-
if (cleaned)
1008+
if (cleaned && tcp_under_memory_pressure(sk))
9341009
sk_mem_reclaim_partial(sk);
9351010
}
9361011

@@ -1307,7 +1382,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
13071382
if (msg->msg_flags & ~(MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL))
13081383
return -EOPNOTSUPP;
13091384

1310-
lock_sock(sk);
1385+
mptcp_lock_sock(sk, __mptcp_wmem_reserve(sk, len));
13111386

13121387
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
13131388

@@ -1356,11 +1431,12 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
13561431
offset = dfrag->offset + dfrag->data_len;
13571432
psize = pfrag->size - offset;
13581433
psize = min_t(size_t, psize, msg_data_left(msg));
1359-
if (!sk_wmem_schedule(sk, psize + frag_truesize))
1434+
if (!mptcp_wmem_alloc(sk, psize + frag_truesize))
13601435
goto wait_for_memory;
13611436

13621437
if (copy_page_from_iter(dfrag->page, offset, psize,
13631438
&msg->msg_iter) != psize) {
1439+
msk->wmem_reserved += psize + frag_truesize;
13641440
ret = -EFAULT;
13651441
goto out;
13661442
}
@@ -1376,7 +1452,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
13761452
* Note: we charge such data both to sk and ssk
13771453
*/
13781454
sk_wmem_queued_add(sk, frag_truesize);
1379-
sk->sk_forward_alloc -= frag_truesize;
13801455
if (!dfrag_collapsed) {
13811456
get_page(dfrag->page);
13821457
list_add_tail(&dfrag->list, &msk->rtx_queue);
@@ -2003,6 +2078,7 @@ static int __mptcp_init_sock(struct sock *sk)
20032078
INIT_WORK(&msk->work, mptcp_worker);
20042079
msk->out_of_order_queue = RB_ROOT;
20052080
msk->first_pending = NULL;
2081+
msk->wmem_reserved = 0;
20062082

20072083
msk->ack_hint = NULL;
20082084
msk->first = NULL;
@@ -2197,6 +2273,7 @@ static void __mptcp_destroy_sock(struct sock *sk)
21972273

21982274
sk->sk_prot->destroy(sk);
21992275

2276+
WARN_ON_ONCE(msk->wmem_reserved);
22002277
sk_stream_kill_queues(sk);
22012278
xfrm_sk_free_policy(sk);
22022279
sk_refcnt_debug_release(sk);
@@ -2542,13 +2619,14 @@ static int mptcp_getsockopt(struct sock *sk, int level, int optname,
25422619

25432620
#define MPTCP_DEFERRED_ALL (TCPF_WRITE_TIMER_DEFERRED)
25442621

2545-
/* this is very alike tcp_release_cb() but we must handle differently a
2546-
* different set of events
2547-
*/
2622+
/* processes deferred events and flush wmem */
25482623
static void mptcp_release_cb(struct sock *sk)
25492624
{
25502625
unsigned long flags, nflags;
25512626

2627+
/* clear any wmem reservation and errors */
2628+
__mptcp_update_wmem(sk);
2629+
25522630
do {
25532631
flags = sk->sk_tsq_flags;
25542632
if (!(flags & MPTCP_DEFERRED_ALL))

net/mptcp/protocol.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ struct mptcp_sock {
218218
u64 ack_seq;
219219
u64 rcv_wnd_sent;
220220
u64 rcv_data_fin_seq;
221+
int wmem_reserved;
221222
struct sock *last_snd;
222223
int snd_burst;
223224
int old_wspace;

0 commit comments

Comments
 (0)