From: "David Hildenbrand (Arm)" <david@kernel.org>
To: Lorenzo Stoakes <ljs@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
Vlastimil Babka <vbabka@kernel.org>,
Mike Rapoport <rppt@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Michal Hocko <mhocko@suse.com>,
"Matthew Wilcox (Oracle)" <willy@infradead.org>,
Jan Kara <jack@suse.cz>,
Andrew Morton <akpm@linux-foundation.org>,
Zi Yan <ziy@nvidia.com>,
Baolin Wang <baolin.wang@linux.alibaba.com>,
Nico Pache <nico.pache@linux.dev>,
Ryan Roberts <ryan.roberts@arm.com>, Dev Jain <dev.jain@arm.com>,
Barry Song <baohua@kernel.org>,
Lance Yang <lance.yang@linux.dev>,
Usama Arif <usama.arif@linux.dev>,
Kiryl Shutsemau <kas@kernel.org>,
Matthew Brost <matthew.brost@intel.com>,
Joshua Hahn <joshua.hahnjy@gmail.com>,
Byungchul Park <byungchul@sk.com>,
Gregory Price <gourry@gourry.net>,
Ying Huang <ying.huang@linux.alibaba.com>,
Alistair Popple <apopple@nvidia.com>,
Peter Xu <peterx@redhat.com>,
Johannes Weiner <hannes@cmpxchg.org>,
Song Liu <songliubraving@fb.com>,
Rik van Riel <riel@surriel.com>,
Miklos Szeredi <miklos@szeredi.hu>,
Alexander Viro <viro@zeniv.linux.org.uk>,
Christian Brauner <brauner@kernel.org>,
Hugh Dickins <hughd@google.com>, Will Deacon <will@kernel.org>,
"Aneesh Kumar K.V" <aneesh.kumar@kernel.org>,
Nick Piggin <npiggin@gmail.com>,
Peter Zijlstra <peterz@infradead.org>,
Arnd Bergmann <arnd@arndb.de>, Jason Gunthorpe <jgg@ziepe.ca>,
Kevin Tian <kevin.tian@intel.com>,
"Joerg Roedel (AMD)" <joro@8bytes.org>,
Robin Murphy <robin.murphy@arm.com>,
Steve Sistare <steven.sistare@oracle.com>,
John Hubbard <jhubbard@nvidia.com>,
"Jose A. Perez de Azpillaga" <azpijr@gmail.com>,
Josef Bacik <josef@toxicpanda.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
Neal Cardwell <ncardwell@google.com>,
Kuniyuki Iwashima <kuniyu@google.com>,
Linus Torvalds <torvalds@linux-foundation.org>
Cc: "David Hildenbrand (Arm)" <david@kernel.org>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
linux-fsdevel@vger.kernel.org, fuse-devel@lists.linux.dev,
linux-arch@vger.kernel.org, iommu@lists.linux.dev,
netdev@vger.kernel.org, stable@vger.kernel.org
Subject: [PATCH v3 7/9] RFC: net: limit folio refcount when rearranging skb frags
Date: Tue, 10 Nov 2026 21:35:47 +0100 [thread overview]
Message-ID: <20261110-refcount_overflow_stable-v3-7-318625d63a98@kernel.org> (raw)
In-Reply-To: <20261110-refcount_overflow_stable-v3-0-318625d63a98@kernel.org>
Various networking features take additional references to frag pages
that are still referenced elsewhere when rearranging skb frags, for
example software GSO segmentation, TCP receive coalescing of clones, SACK
shifting and MTU probing. This is an effective way for multiplying folio
references held by an skb, allowing for exceeding folio refcount limits.
This is not specific to large pagecache folios, but with them it is a
lot easier to reach the refcount limit, as page table mappings can cheaply
create many references.
Let's use skb_frag_try_ref() and skb_frags_try_ref() in skb_segment(),
skb_try_coalesce(), skb_shift() and tcp_clone_payload(). All of these can
already fail, and their callers handle that.
skb_split() can still add one reference when splitting a frag. But each
split also allocates a new skb that is charged to the socket, reaching
the refcount limit that way would require a lot of socket memory, and the
references go away once the data was acked, so it's not that relevant in
practice. Making skb_split() fail is more involved, so let's leave it alone
for now.
Fixes: 800d8c63b2e9 ("shmem: add huge pages support")
Fixes: 99cb0dbd47a1 ("mm,thp: add read-only THP support for (non-shmem) FS")
Fixes: 793917d997df ("mm/readahead: Add large folio readahead")
Cc: stable@vger.kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
net/core/skbuff.c | 32 +++++++++++++++++++++-----------
net/ipv4/tcp_output.c | 8 +++++---
2 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 1d44e9a4152e5..f473c74956b8b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4326,7 +4326,8 @@ static int skb_prepare_for_shift(struct sk_buff *skb)
* the length of the skb, from skb to tgt. Returns number bytes shifted.
* It's up to caller to free skb if everything was shifted.
*
- * If @tgt runs out of frags, the whole operation is aborted.
+ * If @tgt runs out of frags, or we cannot take an additional frag reference,
+ * the whole operation is aborted.
*
* Skb cannot include anything else but paged data while tgt is allowed
* to have non-paged data as well.
@@ -4409,7 +4410,9 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen)
} else {
skb_frag_page_copy(fragto, fragfrom);
- skb_frag_ref(tgt, to);
+ /* Nothing has been committed yet. */
+ if (!skb_frag_try_ref(tgt, to))
+ return 0;
skb_frag_off_copy(fragto, fragfrom);
skb_frag_size_set(fragto, todo);
@@ -5148,7 +5151,10 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
if (!skb_shinfo(nskb)->nr_frags)
nskb->pp_recycle = frag_skb->pp_recycle;
*nskb_frag = (i < 0) ? skb_head_frag_to_page_desc(frag_skb) : *frag;
- skb_frag_ref(nskb, skb_shinfo(nskb)->nr_frags);
+ if (!skb_frag_try_ref(nskb, skb_shinfo(nskb)->nr_frags)) {
+ err = -ENOMEM;
+ goto err;
+ }
size = skb_frag_size(nskb_frag);
if (pos < offset) {
@@ -6289,7 +6295,8 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
bool *fragstolen, int *delta_truesize)
{
struct skb_shared_info *to_shinfo, *from_shinfo;
- int i, delta, len = from->len;
+ int delta, len = from->len;
+ bool cloned;
*fragstolen = false;
@@ -6362,6 +6369,15 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
WARN_ON_ONCE(delta < len);
+ /*
+ * A clone keeps referencing its frags, so we need our own references.
+ * Nothing was added to @to yet: we only steal the head of @from above
+ * if it is not locked, and the head of a clone is always locked.
+ */
+ cloned = skb_cloned(from);
+ if (cloned && !skb_frags_try_ref(from))
+ return false;
+
memcpy(to_shinfo->frags + to_shinfo->nr_frags,
from_shinfo->frags,
from_shinfo->nr_frags * sizeof(skb_frag_t));
@@ -6369,15 +6385,9 @@ bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from,
if (from_shinfo->nr_frags)
to_shinfo->flags |= from_shinfo->flags & SKBFL_SHARED_FRAG;
- if (!skb_cloned(from))
+ if (!cloned)
from_shinfo->nr_frags = 0;
- /* if the skb is not cloned this does nothing
- * since we set nr_frags to 0.
- */
- for (i = 0; i < from_shinfo->nr_frags; i++)
- skb_frag_ref(from, i);
-
to->truesize += delta;
to->len += len;
to->data_len += len;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index cf3ddc055d48d..043838d996404 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2710,10 +2710,12 @@ static int tcp_clone_payload(struct sock *sk, struct sk_buff *to,
}
commit:
WARN_ON_ONCE(len != probe_size);
- for (i = 0; i < nr_frags; i++)
- skb_frag_ref(to, i);
-
skb_shinfo(to)->nr_frags = nr_frags;
+ if (!skb_frags_try_ref(to)) {
+ skb_shinfo(to)->nr_frags = 0;
+ return -ENOMEM;
+ }
+
to->truesize += probe_size;
to->len += probe_size;
to->data_len += probe_size;
--
2.56.0
next prev parent reply other threads:[~2026-11-10 20:38 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 20:35 [PATCH v3 0/9] mm: limit pagecache folio refcount David Hildenbrand (Arm)
2026-11-10 20:35 ` [PATCH v3 1/9] mm: limit pagecache folio refcount when mapping pages David Hildenbrand (Arm)
2026-11-10 20:35 ` [PATCH v3 2/9] mm: limit pagecache folio refcount when splicing into pipes David Hildenbrand (Arm)
2026-11-10 20:35 ` [PATCH v3 3/9] mm/mmu_gather: flush pending references early before the folio limit David Hildenbrand (Arm)
2026-11-10 20:35 ` [PATCH v3 4/9] iommufd: fix cleanup when adding memfd folio pins fails David Hildenbrand (Arm)
2026-11-10 20:35 ` [PATCH v3 5/9] mm/gup: limit pagecache folio refcount when grabbing references David Hildenbrand (Arm)
2026-11-10 20:35 ` [PATCH v3 6/9] RFC: net: limit folio refcount when copying skb frag references David Hildenbrand (Arm)
2026-11-10 20:35 ` David Hildenbrand (Arm) [this message]
2026-11-10 20:35 ` [PATCH v3 8/9] RFC: net: limit folio refcount when splicing pages into skbs David Hildenbrand (Arm)
2026-11-10 20:35 ` [PATCH v3 9/9] RFC: net: limit folio refcount when splicing from sockets David Hildenbrand (Arm)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261110-refcount_overflow_stable-v3-7-318625d63a98@kernel.org \
--to=david@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=aneesh.kumar@kernel.org \
--cc=apopple@nvidia.com \
--cc=arnd@arndb.de \
--cc=azpijr@gmail.com \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=brauner@kernel.org \
--cc=byungchul@sk.com \
--cc=davem@davemloft.net \
--cc=dev.jain@arm.com \
--cc=edumazet@kernel.org \
--cc=fuse-devel@lists.linux.dev \
--cc=gourry@gourry.net \
--cc=hannes@cmpxchg.org \
--cc=horms@kernel.org \
--cc=hughd@google.com \
--cc=iommu@lists.linux.dev \
--cc=jack@suse.cz \
--cc=jgg@ziepe.ca \
--cc=jhubbard@nvidia.com \
--cc=joro@8bytes.org \
--cc=josef@toxicpanda.com \
--cc=joshua.hahnjy@gmail.com \
--cc=kas@kernel.org \
--cc=kevin.tian@intel.com \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=lance.yang@linux.dev \
--cc=liam@infradead.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=matthew.brost@intel.com \
--cc=mhocko@suse.com \
--cc=miklos@szeredi.hu \
--cc=ncardwell@google.com \
--cc=netdev@vger.kernel.org \
--cc=nico.pache@linux.dev \
--cc=npiggin@gmail.com \
--cc=pabeni@redhat.com \
--cc=peterx@redhat.com \
--cc=peterz@infradead.org \
--cc=riel@surriel.com \
--cc=robin.murphy@arm.com \
--cc=rppt@kernel.org \
--cc=ryan.roberts@arm.com \
--cc=songliubraving@fb.com \
--cc=stable@vger.kernel.org \
--cc=steven.sistare@oracle.com \
--cc=surenb@google.com \
--cc=torvalds@linux-foundation.org \
--cc=usama.arif@linux.dev \
--cc=vbabka@kernel.org \
--cc=viro@zeniv.linux.org.uk \
--cc=will@kernel.org \
--cc=willy@infradead.org \
--cc=ying.huang@linux.alibaba.com \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®