Netdev List
 help / color / mirror / Atom feed
* [PATCH v4 net 3/6] xsk: provide sufficient space in pool->tx_descs
From: Maciej Fijalkowski @ 2026-07-19 13:56 UTC (permalink / raw)
  To: netdev
  Cc: bpf, magnus.karlsson, stfomichev, kuba, pabeni, horms, bjorn,
	kerneljasonxing, Maciej Fijalkowski, Jason Xing
In-Reply-To: <20260719135609.147823-1-maciej.fijalkowski@intel.com>

The temporary Tx descriptor array in an XSK buffer pool is currently
sized from the Tx ring of the socket that creates the pool.

This is insufficient for shared-UMEM Tx. A later socket may have a
larger Tx ring and submit a valid multi-buffer packet containing more
descriptors than the first socket's ring, while still remaining within
the device's xdp_zc_max_segs limit.

A packet-framed batch parser bounded by the temporary array cannot reach
the end-of-packet descriptor in that case. It leaves the packet on the
Tx ring and encounters the same packet on every subsequent attempt,
stalling Tx processing for that socket.

Size the temporary descriptor array to the larger of the first Tx ring
and the device's xdp_zc_max_segs capability. This keeps the array large
enough to inspect one maximum-sized valid packet. Larger shared Tx rings
do not require further resizing, as they can be processed over multiple
batches.

Following commit will actually address the data path side.

Fixes: d5581966040f ("xsk: support ZC Tx multi-buffer in batch API")
Reviewed-by: Jason Xing <kernelxing@tencent.com>
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
---
 include/net/xsk_buff_pool.h |  6 ++++--
 net/xdp/xsk.c               | 10 +++++++---
 net/xdp/xsk_buff_pool.c     | 12 ++++++++----
 3 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/include/net/xsk_buff_pool.h b/include/net/xsk_buff_pool.h
index ccb3b350001f..f5e737a83055 100644
--- a/include/net/xsk_buff_pool.h
+++ b/include/net/xsk_buff_pool.h
@@ -102,12 +102,14 @@ struct xsk_buff_pool {
 
 /* AF_XDP core. */
 struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
-						struct xdp_umem *umem);
+						struct xdp_umem *umem,
+						u32 max_segs);
 int xp_assign_dev(struct xsk_buff_pool *pool, struct net_device *dev,
 		  u16 queue_id, u16 flags);
 int xp_assign_dev_shared(struct xsk_buff_pool *pool, struct xdp_sock *umem_xs,
 			 struct net_device *dev, u16 queue_id);
-int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs);
+int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs,
+		      u32 max_segs);
 void xp_destroy(struct xsk_buff_pool *pool);
 void xp_get_pool(struct xsk_buff_pool *pool);
 bool xp_put_pool(struct xsk_buff_pool *pool);
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 12a845d012f6..091792d1d82d 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -1525,7 +1525,8 @@ static int xsk_bind(struct socket *sock, struct sockaddr_unsized *addr, int addr
 			 * and/or device.
 			 */
 			xs->pool = xp_create_and_assign_umem(xs,
-							     umem_xs->umem);
+							     umem_xs->umem,
+							     dev->xdp_zc_max_segs);
 			if (!xs->pool) {
 				err = -ENOMEM;
 				sockfd_put(sock);
@@ -1557,7 +1558,8 @@ static int xsk_bind(struct socket *sock, struct sockaddr_unsized *addr, int addr
 			 * utilizes
 			 */
 			if (xs->tx && !xs->pool->tx_descs) {
-				err = xp_alloc_tx_descs(xs->pool, xs);
+				err = xp_alloc_tx_descs(xs->pool, xs,
+							dev->xdp_zc_max_segs);
 				if (err) {
 					xp_put_pool(xs->pool);
 					xs->pool = NULL;
@@ -1575,7 +1577,9 @@ static int xsk_bind(struct socket *sock, struct sockaddr_unsized *addr, int addr
 		goto out_unlock;
 	} else {
 		/* This xsk has its own umem. */
-		xs->pool = xp_create_and_assign_umem(xs, xs->umem);
+		xs->pool = xp_create_and_assign_umem(xs, xs->umem,
+						     dev->xdp_zc_max_segs);
+
 		if (!xs->pool) {
 			err = -ENOMEM;
 			goto out_unlock;
diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c
index 1f28a9641571..12c9fb29af05 100644
--- a/net/xdp/xsk_buff_pool.c
+++ b/net/xdp/xsk_buff_pool.c
@@ -42,9 +42,12 @@ void xp_destroy(struct xsk_buff_pool *pool)
 	kvfree(pool);
 }
 
-int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs)
+int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs,
+		      u32 max_segs)
 {
-	pool->tx_descs = kvzalloc_objs(*pool->tx_descs, xs->tx->nentries);
+	u32 nentries = max(xs->tx->nentries, max_segs);
+
+	pool->tx_descs = kvzalloc_objs(*pool->tx_descs, nentries);
 	if (!pool->tx_descs)
 		return -ENOMEM;
 
@@ -52,7 +55,8 @@ int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs)
 }
 
 struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
-						struct xdp_umem *umem)
+						struct xdp_umem *umem,
+						u32 max_segs)
 {
 	bool unaligned = umem->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG;
 	struct xsk_buff_pool *pool;
@@ -69,7 +73,7 @@ struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
 		goto out;
 
 	if (xs->tx)
-		if (xp_alloc_tx_descs(pool, xs))
+		if (xp_alloc_tx_descs(pool, xs, max_segs))
 			goto out;
 
 	pool->chunk_mask = ~((u64)umem->chunk_size - 1);
-- 
2.43.0


^ permalink raw reply related

* [PATCH v4 net 4/6] xsk: reclaim invalid Tx descriptors in ZC batch path
From: Maciej Fijalkowski @ 2026-07-19 13:56 UTC (permalink / raw)
  To: netdev
  Cc: bpf, magnus.karlsson, stfomichev, kuba, pabeni, horms, bjorn,
	kerneljasonxing, Maciej Fijalkowski, Jason Xing
In-Reply-To: <20260719135609.147823-1-maciej.fijalkowski@intel.com>

The zero-copy Tx batch parser stops when it encounters an invalid
descriptor. If this happens after one or more continuation descriptors,
the Tx consumer can be advanced past fragments that are neither submitted
to the driver nor returned to userspace through the completion ring.

A similar problem occurs when a packet exceeds xdp_zc_max_segs. The
descriptors consumed up to the limit are released without completion, and
the remaining continuation descriptors can subsequently be interpreted
as the beginning of another packet.

Parse Tx batches in packet units and distinguish descriptors belonging to
complete valid packets from descriptors consumed while draining an
invalid or oversized packet. Return the former to the driver and append
the latter to the CQ address area so userspace can reclaim their UMEM
frames.

Treat a standalone invalid descriptor as a one-descriptor reclaim-only
packet. Advancing the Tx-ring consumer releases the ring slot, but does
not by itself return ownership of the referenced UMEM frame to userspace.

Once draining starts, continue until the packet's end-of-packet
descriptor is consumed. Preserve the drain state on the socket when EOP
has not yet been supplied, so draining can continue during a later call.
Leave incomplete but otherwise valid packets on the Tx ring.

Shared-UMEM pools using multi-buffer Tx also need packet-framed parsing.
Walk their Tx sockets one packet at a time, preserving the existing
per-socket fairness scheme, instead of using the legacy one-descriptor
fallback. Keep that fallback for shared pools that do not use
multi-buffer Tx. Since the drain state is maintained per socket and both
the singular and shared paths can resume an interrupted drain, changing
the socket list from singular to shared requires no special bind-time
transition.

CQ entries are positional, and drivers may complete only part of the Tx
work returned by xsk_tx_peek_release_desc_batch(). Therefore, reclaim-only
entries cannot be published immediately when earlier driver-visible
descriptors are still outstanding.

Track the number of driver-visible CQ entries preceding the reclaim
entries. Let xsk_tx_completed() publish partial hardware Tx completions,
and publish the reclaim entries only after every earlier Tx descriptor
has completed. Complete a reclaim-only batch immediately when there is no
driver-visible work in front of it, and prevent another Tx batch from
being appended while reclaim entries remain pending.

Also cap batch processing by the size of the pool's temporary descriptor
array, as Tx rings belonging to sockets sharing a UMEM may have different
sizes.

This ensures that every invalid Tx descriptor consumed by the ZC batch
path is either submitted to the driver as part of a valid packet or
returned to userspace without violating CQ completion ordering.

Fixes: cf24f5a5feea ("xsk: add support for AF_XDP multi-buffer on Tx path")
Reviewed-by: Jason Xing <kernelxing@tencent.com>
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
---
 Documentation/networking/af_xdp.rst |  54 ++++----
 include/net/xsk_buff_pool.h         |   3 +
 net/xdp/xsk.c                       | 187 +++++++++++++++++++++++++---
 net/xdp/xsk_buff_pool.c             |   1 +
 net/xdp/xsk_queue.h                 |  65 +++++++---
 5 files changed, 248 insertions(+), 62 deletions(-)

diff --git a/Documentation/networking/af_xdp.rst b/Documentation/networking/af_xdp.rst
index 50d92084a49c..cc3f0d16b28f 100644
--- a/Documentation/networking/af_xdp.rst
+++ b/Documentation/networking/af_xdp.rst
@@ -43,12 +43,13 @@ UMEM also has two rings: the FILL ring and the COMPLETION ring. The
 FILL ring is used by the application to send down addr for the kernel
 to fill in with RX packet data. References to these frames will then
 appear in the RX ring once each packet has been received. The
-COMPLETION ring, on the other hand, contains frame addr that the
-kernel has transmitted completely and can now be used again by user
-space, for either TX or RX. Thus, the frame addrs appearing in the
-COMPLETION ring are addrs that were previously transmitted using the
-TX ring. In summary, the RX and FILL rings are used for the RX path
-and the TX and COMPLETION rings are used for the TX path.
+COMPLETION ring, on the other hand, contains frame addresses from Tx
+descriptors that the kernel has finished processing and that can now be
+used again by user space, for either Tx or Rx. This includes frames whose
+transmission has completed as well as frames referenced by invalid Tx
+descriptors rejected by the kernel. A completion therefore returns
+ownership of a frame to user space, but does not by itself guarantee that
+the packet was successfully transmitted.
 
 The socket is then finally bound with a bind() call to a device and a
 specific queue id on that device, and it is not until bind is
@@ -169,14 +170,15 @@ chunks mode, then the incoming addr will be left untouched.
 UMEM Completion Ring
 ~~~~~~~~~~~~~~~~~~~~
 
-The COMPLETION Ring is used transfer ownership of UMEM frames from
+The COMPLETION Ring is used to transfer ownership of UMEM frames from
 kernel-space to user-space. Just like the FILL ring, UMEM indices are
-used.
-
-Frames passed from the kernel to user-space are frames that has been
-sent (TX ring) and can be used by user-space again.
-
-The user application consumes UMEM addrs from this ring.
+used. Frames passed from the kernel to user-space are frames referenced
+by Tx descriptors that the kernel has finished processing and can be
+used by user-space again. This includes both frames whose transmission
+has completed and frames referenced by invalid Tx descriptors that were
+rejected and reclaimed by the kernel. A completion entry does not
+guarantee successful packet transmission. The user application consumes
+UMEM addrs from this ring.
 
 
 RX Ring
@@ -504,21 +506,25 @@ will be treated as an invalid descriptor.
 These are the semantics for producing packets onto AF_XDP Tx ring
 consisting of multiple frames:
 
-* When an invalid descriptor is found, all the other
-  descriptors/frames of this packet are marked as invalid and not
-  completed. The next descriptor is treated as the start of a new
-  packet, even if this was not the intent (because we cannot guess
-  the intent). As before, if your program is producing invalid
-  descriptors you have a bug that must be fixed.
+* When an invalid descriptor is found, the complete packet is treated as
+  invalid. The kernel consumes descriptors through the descriptor marking
+  the end of the packet and returns all their frame addresses through the
+  COMPLETION ring. A standalone invalid descriptor is treated as a
+  one-descriptor invalid packet. The descriptor following the end of the
+  invalid packet is treated as the start of a new packet. As before, if
+  your program is producing invalid descriptors you have a bug that must
+  be fixed. Rejected descriptors are reported in the ``tx_invalid_descs``
+  statistic.
 
 * Zero length descriptors are treated as invalid descriptors.
 
 * For copy mode, the maximum supported number of frames in a packet is
-  equal to CONFIG_MAX_SKB_FRAGS + 1. If it is exceeded, all
-  descriptors accumulated so far are dropped and treated as
-  invalid. To produce an application that will work on any system
-  regardless of this config setting, limit the number of frags to 18,
-  as the minimum value of the config is 17.
+  equal to CONFIG_MAX_SKB_FRAGS + 1. If it is exceeded, all descriptors
+  through the end of the oversized packet are consumed, treated as invalid,
+  and their frame addresses are returned through the COMPLETION ring. To
+  produce an application that will work on any system regardless of this
+  config setting, limit the number of frags to 18, as the minimum value of
+  the config is 17.
 
 * For zero-copy mode, the limit is up to what the NIC HW
   supports. Usually at least five on the NICs we have checked. We
diff --git a/include/net/xsk_buff_pool.h b/include/net/xsk_buff_pool.h
index f5e737a83055..2bb1d122b1bc 100644
--- a/include/net/xsk_buff_pool.h
+++ b/include/net/xsk_buff_pool.h
@@ -78,6 +78,9 @@ struct xsk_buff_pool {
 	u32 chunk_size;
 	u32 chunk_shift;
 	u32 frame_len;
+	u32 tx_descs_nentries;
+	u32 reclaim_descs;
+	u32 tx_zc_pending_descs;
 	u32 xdp_zc_max_segs;
 	u8 tx_metadata_len; /* inherited from umem */
 	u8 cached_need_wakeup;
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 091792d1d82d..f906d51b6699 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -499,6 +499,23 @@ void __xsk_map_flush(struct list_head *flush_list)
 
 void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries)
 {
+	u32 reclaim_descs = READ_ONCE(pool->reclaim_descs);
+
+	if (unlikely(reclaim_descs)) {
+		u32 pending_descs = READ_ONCE(pool->tx_zc_pending_descs);
+
+		if (nb_entries < pending_descs) {
+			WRITE_ONCE(pool->tx_zc_pending_descs,
+				   pending_descs - nb_entries);
+			xskq_prod_submit_n(pool->cq, nb_entries);
+			return;
+		}
+
+		WRITE_ONCE(pool->tx_zc_pending_descs, 0);
+		nb_entries += reclaim_descs;
+		WRITE_ONCE(pool->reclaim_descs, 0);
+	}
+
 	xskq_prod_submit_n(pool->cq, nb_entries);
 }
 EXPORT_SYMBOL(xsk_tx_completed);
@@ -574,24 +591,157 @@ static u32 xsk_tx_peek_release_fallback(struct xsk_buff_pool *pool, u32 max_entr
 	return nb_pkts;
 }
 
+static void xsk_tx_commit_batch(struct xsk_buff_pool *pool,
+				struct xsk_tx_batch *batch)
+{
+	u32 nb_descs = xsk_tx_batch_cq_descs(batch);
+	u32 cq_cached_prod;
+
+	if (!nb_descs)
+		return;
+
+	cq_cached_prod = pool->cq->cached_prod;
+	xskq_prod_write_addr_batch(pool->cq, pool->tx_descs, nb_descs);
+
+	if (unlikely(batch->reclaim_descs)) {
+		u32 cq_pending_descs;
+
+		/* CQ is positional. Descriptors already written but not
+		 * submitted must complete before any reclaim-only descriptors
+		 * appended below.
+		 */
+		cq_pending_descs = cq_cached_prod - xskq_get_prod(pool->cq);
+
+		WRITE_ONCE(pool->tx_zc_pending_descs,
+			   batch->tx_descs + cq_pending_descs);
+		WRITE_ONCE(pool->reclaim_descs, batch->reclaim_descs);
+		if (unlikely(!pool->tx_zc_pending_descs))
+			xsk_tx_completed(pool, 0);
+	}
+}
+
+static struct xsk_tx_batch
+__xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, struct xdp_sock *xs,
+				 struct xdp_desc *descs, u32 max_descs)
+{
+	struct xsk_tx_batch batch = {};
+	u32 entries;
+
+	entries = xskq_cons_nb_entries(xs->tx, max_descs);
+	if (!entries)
+		return batch;
+
+	batch = xskq_cons_read_desc_batch(xs, pool, descs, max_descs);
+	if (!xsk_tx_batch_cq_descs(&batch)) {
+		xs->tx->queue_empty_descs++;
+	} else {
+		__xskq_cons_release(xs->tx);
+		xs->sk.sk_write_space(&xs->sk);
+	}
+	return batch;
+}
+
+static struct xsk_tx_batch
+xsk_tx_peek_release_shared_desc_batch(struct xsk_buff_pool *pool, u32 max_descs)
+{
+	u32 cq_descs_before, cq_descs_after;
+	struct xsk_tx_batch sum_batch = {};
+	bool budget_exhausted;
+	u32 per_socket_budget;
+	struct xdp_sock *xs;
+
+	/* The fairness quota must allow one maximum-sized valid packet. */
+	per_socket_budget = max_t(u32, MAX_PER_SOCKET_BUDGET,
+				  pool->xdp_zc_max_segs);
+
+again:
+	budget_exhausted = false;
+	cq_descs_before = xsk_tx_batch_cq_descs(&sum_batch);
+	list_for_each_entry_rcu(xs, &pool->xsk_tx_list, tx_list) {
+		u32 budget, budget_left, offset, remaining, used;
+		struct xsk_tx_batch curr_batch;
+
+		/* Once reclaim-only descriptors have been appended to the CQ
+		 * address area, do not append driver-visible Tx descriptors
+		 * from another socket after them. xsk_tx_completed() relies on
+		 * all driver-visible descriptors preceding all reclaim-only
+		 * descriptors in CQ order.
+		 */
+		if (sum_batch.reclaim_descs)
+			break;
+
+		/* be gentle when playing with pool->tx_descs */
+		offset = xsk_tx_batch_cq_descs(&sum_batch);
+		if (offset >= max_descs)
+			break;
+
+		if (xs->tx_budget_spent >= per_socket_budget) {
+			if (xskq_cons_nb_entries(xs->tx, 1))
+				budget_exhausted = true;
+			continue;
+		}
+
+		budget_left = per_socket_budget - xs->tx_budget_spent;
+		remaining = max_descs - offset;
+		budget = min(remaining, budget_left);
+
+		curr_batch = __xsk_tx_peek_release_desc_batch(pool, xs,
+							      pool->tx_descs + offset,
+							      budget);
+		used = xsk_tx_batch_cq_descs(&curr_batch);
+		if (!used) {
+			if (curr_batch.budget_limited && budget_left < remaining)
+				budget_exhausted = true;
+			continue;
+		}
+
+		xs->tx_budget_spent += used;
+		sum_batch.tx_descs += curr_batch.tx_descs;
+		sum_batch.reclaim_descs = curr_batch.reclaim_descs;
+	}
+
+	cq_descs_after = xsk_tx_batch_cq_descs(&sum_batch);
+
+	if (sum_batch.reclaim_descs || cq_descs_after >= max_descs)
+		return sum_batch;
+
+	/* Continue filling the batch while this pass made progress */
+	if (cq_descs_before != cq_descs_after)
+		goto again;
+
+	if (!budget_exhausted)
+		return sum_batch;
+
+	list_for_each_entry_rcu(xs, &pool->xsk_tx_list, tx_list)
+		xs->tx_budget_spent = 0;
+	goto again;
+}
+
 u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 nb_pkts)
 {
+	struct xsk_tx_batch batch = {};
 	struct xdp_sock *xs;
+	bool umem_shared;
 
 	rcu_read_lock();
-	if (!list_is_singular(&pool->xsk_tx_list)) {
-		/* Fallback to the non-batched version */
-		rcu_read_unlock();
-		return xsk_tx_peek_release_fallback(pool, nb_pkts);
-	}
+	if (unlikely(READ_ONCE(pool->reclaim_descs)))
+		goto out;
 
-	xs = list_first_or_null_rcu(&pool->xsk_tx_list, struct xdp_sock, tx_list);
-	if (!xs) {
-		nb_pkts = 0;
+	xs = list_first_or_null_rcu(&pool->xsk_tx_list, struct xdp_sock,
+				    tx_list);
+	if (!xs)
 		goto out;
-	}
 
-	nb_pkts = xskq_cons_nb_entries(xs->tx, nb_pkts);
+	nb_pkts = min(nb_pkts, pool->tx_descs_nentries);
+	if (!nb_pkts)
+		goto out;
+
+	umem_shared = !list_is_singular(&pool->xsk_tx_list);
+
+	if (umem_shared && !(pool->umem->flags & XDP_UMEM_SG_FLAG)) {
+		rcu_read_unlock();
+		return xsk_tx_peek_release_fallback(pool, nb_pkts);
+	}
 
 	/* This is the backpressure mechanism for the Tx path. Try to
 	 * reserve space in the completion queue for all packets, but
@@ -603,19 +753,16 @@ u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 nb_pkts)
 	if (!nb_pkts)
 		goto out;
 
-	nb_pkts = xskq_cons_read_desc_batch(xs->tx, pool, nb_pkts);
-	if (!nb_pkts) {
-		xs->tx->queue_empty_descs++;
-		goto out;
-	}
-
-	__xskq_cons_release(xs->tx);
-	xskq_prod_write_addr_batch(pool->cq, pool->tx_descs, nb_pkts);
-	xs->sk.sk_write_space(&xs->sk);
+	batch = umem_shared ?
+		xsk_tx_peek_release_shared_desc_batch(pool, nb_pkts) :
+		__xsk_tx_peek_release_desc_batch(pool, xs,
+						 pool->tx_descs,
+						 nb_pkts);
+	xsk_tx_commit_batch(pool, &batch);
 
 out:
 	rcu_read_unlock();
-	return nb_pkts;
+	return batch.tx_descs;
 }
 EXPORT_SYMBOL(xsk_tx_peek_release_desc_batch);
 
diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c
index 12c9fb29af05..a4089480b22b 100644
--- a/net/xdp/xsk_buff_pool.c
+++ b/net/xdp/xsk_buff_pool.c
@@ -51,6 +51,7 @@ int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs,
 	if (!pool->tx_descs)
 		return -ENOMEM;
 
+	pool->tx_descs_nentries = nentries;
 	return 0;
 }
 
diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h
index 3e3fbb73d23e..1bc42c8902f4 100644
--- a/net/xdp/xsk_queue.h
+++ b/net/xdp/xsk_queue.h
@@ -58,6 +58,17 @@ struct parsed_desc {
 	u32 valid;
 };
 
+struct xsk_tx_batch {
+	u32 tx_descs;
+	u32 reclaim_descs;
+	bool budget_limited;
+};
+
+static inline u32 xsk_tx_batch_cq_descs(const struct xsk_tx_batch *batch)
+{
+	return batch->tx_descs + batch->reclaim_descs;
+}
+
 /* The structure of the shared state of the rings are a simple
  * circular buffer, as outlined in
  * Documentation/core-api/circular-buffers.rst. For the Rx and
@@ -263,17 +274,18 @@ static inline void parse_desc(struct xsk_queue *q, struct xsk_buff_pool *pool,
 	parsed->mb = xp_mb_desc(desc);
 }
 
-static inline
-u32 xskq_cons_read_desc_batch(struct xsk_queue *q, struct xsk_buff_pool *pool,
-			      u32 max)
+static inline struct xsk_tx_batch
+xskq_cons_read_desc_batch(struct xdp_sock *xs, struct xsk_buff_pool *pool,
+			  struct xdp_desc *descs, u32 max)
 {
-	u32 cached_cons = q->cached_cons, nb_entries = 0;
-	struct xdp_desc *descs = pool->tx_descs;
-	u32 total_descs = 0, nr_frags = 0;
+	bool drain = READ_ONCE(xs->drain_cont);
+	u32 cached_cons, nb_entries = 0;
+	struct xsk_tx_batch batch = {};
+	struct xsk_queue *q = xs->tx;
+	u32 nr_frags = 0;
+
+	cached_cons = q->cached_cons;
 
-	/* track first entry, if stumble upon *any* invalid descriptor, rewind
-	 * current packet that consists of frags and stop the processing
-	 */
 	while (cached_cons != q->cached_prod && nb_entries < max) {
 		struct xdp_rxtx_ring *ring = (struct xdp_rxtx_ring *)q->ring;
 		u32 idx = cached_cons & q->ring_mask;
@@ -283,25 +295,42 @@ u32 xskq_cons_read_desc_batch(struct xsk_queue *q, struct xsk_buff_pool *pool,
 		cached_cons++;
 		parse_desc(q, pool, &descs[nb_entries], &parsed);
 		if (unlikely(!parsed.valid))
-			break;
+			drain = true;
+
+		nr_frags++;
+		nb_entries++;
 
 		if (likely(!parsed.mb)) {
-			total_descs += (nr_frags + 1);
-			nr_frags = 0;
-		} else {
-			nr_frags++;
-			if (nr_frags == pool->xdp_zc_max_segs) {
+			if (unlikely(drain)) {
+				batch.reclaim_descs = nr_frags;
+				WRITE_ONCE(xs->drain_cont, false);
 				nr_frags = 0;
 				break;
 			}
+
+			batch.tx_descs += nr_frags;
+			nr_frags = 0;
+			continue;
+		}
+
+		if (nr_frags == pool->xdp_zc_max_segs)
+			drain = true;
+	}
+
+	if (nr_frags) {
+		if (drain) {
+			batch.reclaim_descs = nr_frags;
+			WRITE_ONCE(xs->drain_cont, true);
+		} else {
+			if (nb_entries == max)
+				batch.budget_limited = true;
+			cached_cons -= nr_frags;
 		}
-		nb_entries++;
 	}
 
-	cached_cons -= nr_frags;
 	/* Release valid plus any invalid entries */
 	xskq_cons_release_n(q, cached_cons - q->cached_cons);
-	return total_descs;
+	return batch;
 }
 
 /* Functions for consumers */
-- 
2.43.0


^ permalink raw reply related

* [PATCH v4 net 5/6] selftests/xsk: fix too-many-frags multi-buffer Tx test
From: Maciej Fijalkowski @ 2026-07-19 13:56 UTC (permalink / raw)
  To: netdev
  Cc: bpf, magnus.karlsson, stfomichev, kuba, pabeni, horms, bjorn,
	kerneljasonxing, Maciej Fijalkowski, Jason Xing
In-Reply-To: <20260719135609.147823-1-maciej.fijalkowski@intel.com>

The too-many-frags test describes a packet that is valid from the Tx
ring ownership point of view, but invalid for transmission because it
exceeds the supported number of fragments.

Keep the generated Tx descriptors valid so that __send_pkts() accounts
them as outstanding descriptors that must be reclaimed through the CQ.
Then mark the corresponding Rx packet invalid so the test still does
not expect the oversized packet to appear on the receive side.

Add a valid synchronization packet after the oversized packet so the
test can verify that the Tx path drains the bad packet and resumes at
the next packet boundary.

Reviewed-by: Jason Xing <kernelxing@tencent.com>
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
---
 .../selftests/bpf/prog_tests/test_xsk.c       | 24 ++++++++++++-------
 1 file changed, 15 insertions(+), 9 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/test_xsk.c b/tools/testing/selftests/bpf/prog_tests/test_xsk.c
index 477aedbb01ba..f0e0f3c4f7a3 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_xsk.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_xsk.c
@@ -2270,7 +2270,7 @@ int testapp_too_many_frags(struct test_spec *test)
 		max_frags += 1;
 	}
 
-	pkts = calloc(2 * max_frags + 2, sizeof(struct pkt));
+	pkts = calloc(2 * max_frags + 3, sizeof(struct pkt));
 	if (!pkts)
 		return TEST_FAILURE;
 
@@ -2288,24 +2288,30 @@ int testapp_too_many_frags(struct test_spec *test)
 	}
 	pkts[max_frags].options = 0;
 
-	/* An invalid packet with the max amount of frags but signals packet
-	 * continues on the last frag
-	 */
-	for (i = max_frags + 1; i < 2 * max_frags + 1; i++) {
+	/* An invalid packet with the max + 1 amount of frags */
+	for (i = max_frags + 1; i < 2 * max_frags + 2; i++) {
 		pkts[i].len = MIN_PKT_SIZE;
 		pkts[i].options = XDP_PKT_CONTD;
-		pkts[i].valid = false;
+		pkts[i].valid = true;
 	}
+	pkts[2 * max_frags + 1].options = 0;
 
 	/* Valid packet for synch */
-	pkts[2 * max_frags + 1].len = MIN_PKT_SIZE;
-	pkts[2 * max_frags + 1].valid = true;
+	pkts[2 * max_frags + 2].len = MIN_PKT_SIZE;
+	pkts[2 * max_frags + 2].valid = true;
 
-	if (pkt_stream_generate_custom(test, pkts, 2 * max_frags + 2)) {
+	if (pkt_stream_generate_custom(test, pkts, 2 * max_frags + 3)) {
 		free(pkts);
 		return TEST_FAILURE;
 	}
 
+	/* The generated Tx stream must keep the too-big packet valid so that
+	 * __send_pkts() accounts its descriptors in outstanding_tx. The Rx
+	 * stream, however, must not expect this packet on the wire.
+	 */
+	test->ifobj_rx->xsk->pkt_stream->pkts[2].valid = false;
+	test->ifobj_rx->xsk->pkt_stream->nb_valid_entries--;
+
 	ret = testapp_validate_traffic(test);
 	free(pkts);
 	return ret;
-- 
2.43.0


^ permalink raw reply related

* [PATCH v4 net 6/6] selftests/xsk: account reclaimed invalid Tx descriptors
From: Maciej Fijalkowski @ 2026-07-19 13:56 UTC (permalink / raw)
  To: netdev
  Cc: bpf, magnus.karlsson, stfomichev, kuba, pabeni, horms, bjorn,
	kerneljasonxing, Maciej Fijalkowski, Jason Xing
In-Reply-To: <20260719135609.147823-1-maciej.fijalkowski@intel.com>

Invalid Tx descriptors are now returned through the completion ring,
regardless of whether they form a standalone packet or belong to an
invalid multi-buffer packet.

The selftests previously counted only descriptors belonging to valid
packets, with a special exception for some invalid multi-buffer packets
in verbatim streams. This undercounts completion entries when a
standalone invalid descriptor or another invalid packet is reclaimed by
the kernel.

Keep valid_pkts as the number of packets expected on the Rx side, but
count every descriptor submitted to the Tx ring in valid_frags, as every
such descriptor is now expected to be returned through the completion
ring.

Make fragment counting in verbatim mode follow the packet boundary
instead of stopping at the first invalid fragment. Update custom stream
generation so an invalid middle fragment terminates the generated Rx
packet while Tx completion accounting still covers the complete invalid
packet.

Also add explicit end fragments after invalid middle descriptors. This
exercises the kernel drain logic and verifies that subsequent valid
packets are not interpreted as continuations of the invalid packet.

Reviewed-by: Jason Xing <kernelxing@tencent.com>
Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
---
 .../selftests/bpf/prog_tests/test_xsk.c       | 26 ++++++++++---------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/test_xsk.c b/tools/testing/selftests/bpf/prog_tests/test_xsk.c
index f0e0f3c4f7a3..4549358cc8c2 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_xsk.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_xsk.c
@@ -427,14 +427,14 @@ static u32 pkt_nb_frags(u32 frame_size, struct pkt_stream *pkt_stream, struct pk
 	}
 
 	/* Search for the end of the packet in verbatim mode */
-	if (!pkt_continues(pkt->options) || !pkt->valid)
+	if (!pkt_continues(pkt->options))
 		return nb_frags;
 
 	next_frag = pkt_stream->current_pkt_nb;
 	pkt++;
 	while (next_frag++ < pkt_stream->nb_pkts) {
 		nb_frags++;
-		if (!pkt_continues(pkt->options) || !pkt->valid)
+		if (!pkt_continues(pkt->options))
 			break;
 		pkt++;
 	}
@@ -665,11 +665,11 @@ static struct pkt_stream *__pkt_stream_generate_custom(struct ifobject *ifobj, s
 			if (!frame->valid || !pkt_continues(frame->options))
 				payload++;
 		} else {
-			if (frame->valid)
+			if (frame->valid) {
 				len += frame->len;
-			if (frame->valid && pkt_continues(frame->options))
-				continue;
-
+				if (pkt_continues(frame->options))
+					continue;
+			}
 			pkt->pkt_nb = pkt_nb;
 			pkt->len = len;
 			pkt->valid = frame->valid;
@@ -1250,10 +1250,9 @@ static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk,
 			}
 		}
 
-		if (pkt && pkt->valid) {
+		if (pkt && pkt->valid)
 			valid_pkts++;
-			valid_frags += nb_frags;
-		}
+		valid_frags += nb_frags;
 	}
 
 	pthread_mutex_lock(&pacing_mutex);
@@ -2099,13 +2098,16 @@ int testapp_invalid_desc_mb(struct test_spec *test)
 		{0, 0, 0, false, 0},
 		/* Invalid address in the second frame */
 		{0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD},
-		{umem_sz, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD},
+		{umem_sz * 2, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD},
+		{0, MIN_PKT_SIZE, 0, false, 0},
 		/* Invalid len in the middle */
 		{0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD},
 		{0, XSK_UMEM__INVALID_FRAME_SIZE, 0, false, XDP_PKT_CONTD},
+		{0, MIN_PKT_SIZE, 0, false, 0},
 		/* Invalid options in the middle */
 		{0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XDP_PKT_CONTD},
 		{0, XSK_UMEM__LARGE_FRAME_SIZE, 0, false, XSK_DESC__INVALID_OPTION},
+		{0, MIN_PKT_SIZE, 0, false, 0},
 		/* Transmit 2 frags, receive 3 */
 		{0, XSK_UMEM__MAX_FRAME_SIZE, 0, true, XDP_PKT_CONTD},
 		{0, XSK_UMEM__MAX_FRAME_SIZE, 0, true, 0},
@@ -2117,8 +2119,8 @@ int testapp_invalid_desc_mb(struct test_spec *test)
 
 	if (umem->unaligned_mode) {
 		/* Crossing a chunk boundary allowed */
-		pkts[12].valid = true;
-		pkts[13].valid = true;
+		pkts[15].valid = true;
+		pkts[16].valid = true;
 	}
 
 	test->mtu = MAX_ETH_JUMBO_SIZE;
-- 
2.43.0


^ permalink raw reply related

* RE: [PATCH ethtool-next v3 1/3] sfpid: print all implemented options
From: Danielle Ratson @ 2026-07-19 14:07 UTC (permalink / raw)
  To: Aleksander Jan Bajkowski, mkubecek@suse.cz, andrew@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, jbe@pengutronix.de, netdev@vger.kernel.org
In-Reply-To: <20260719090458.659332-1-olek2@wp.pl>

> -----Original Message-----
> From: Aleksander Jan Bajkowski <olek2@wp.pl>
> Sent: Sunday, 19 July 2026 12:01
> To: Danielle Ratson <danieller@nvidia.com>; olek2@wp.pl;
> mkubecek@suse.cz; andrew@lunn.ch; davem@davemloft.net;
> edumazet@google.com; kuba@kernel.org; pabeni@redhat.com;
> jbe@pengutronix.de; netdev@vger.kernel.org
> Subject: [PATCH ethtool-next v3 1/3] sfpid: print all implemented options
> 
> SFP modules implement multiple options. Before the “json” option was
> introduced, all options were listed. Currently, only the last option is listed. This
> commit fixes this bug. Options are represented as array.
> 
> Before:
> $ ethtool -m sfp-wan
> ...
> 	Option values                             : 0x00 0x32
> 	Option                                    : RATE_SELECT implemented
> ...
> $ ethtool --json -m sfp-wan
> [ {
> ...
>         "option_values": [ 0,50 ],
>         "option": "RATE_SELECT implemented", ...
>     } ]
> 
> After:
> $ ethtool -m sfp-wan
> ...
> 	Option values                             : 0x00 0x32
> 	Option                                    : RX_LOS implemented
> 	Option                                    : TX_DISABLE implemented
> 	Option                                    : RATE_SELECT implemented
> ...
> $ ethtool --json -m sfp-wan
> [ {
> ...
>         "option_values": [ 0,50 ],
>         "option": [ "RX_LOS implemented","TX_DISABLE
> implemented","RATE_SELECT implemented" ], ...
>     } ]
> 
> Fixes: 4071862f58d8 ("sfpid: Add JSON output handling to --module-info in
> SFF8079 modules")
> Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
> ---
> Changes in v3:
>  - fix indentation and checkpatch warnings Changes in v2:
>  - fix typo introduced -> introduced
>  - rename module_print_array_string() ->
> module_print_any_array_string_entry()
> ---
 
Reviewed-by: Danielle Ratson <danieller@nvidia.com>

^ permalink raw reply

* RE: [PATCH ethtool-next v3 2/3] sfpid: print all compliance codes
From: Danielle Ratson @ 2026-07-19 14:07 UTC (permalink / raw)
  To: Aleksander Jan Bajkowski, mkubecek@suse.cz, andrew@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, jbe@pengutronix.de, netdev@vger.kernel.org
In-Reply-To: <20260719090458.659332-2-olek2@wp.pl>

> -----Original Message-----
> From: Aleksander Jan Bajkowski <olek2@wp.pl>
> Sent: Sunday, 19 July 2026 12:01
> To: Danielle Ratson <danieller@nvidia.com>; olek2@wp.pl;
> mkubecek@suse.cz; andrew@lunn.ch; davem@davemloft.net;
> edumazet@google.com; kuba@kernel.org; pabeni@redhat.com;
> jbe@pengutronix.de; netdev@vger.kernel.org
> Subject: [PATCH ethtool-next v3 2/3] sfpid: print all compliance codes
> 
> SFP modules implement multiple compliance codes. This is common for dual-
> rate modules. Before the `json` option was introduced, all compliance codes
> were displayed. Currently, only the last code is displayed. This commit fixes
> that bug. Compliance codes are represented as array.
> 
> Before:
> $ ethtool -m sfp-wan
> ...
> 	Transceiver codes                         : 0x00 0x00 0x00 0x01 0x20 0x40 0x0c
> 0x15 0x00
> 	Transceiver type                          : FC: 100 MBytes/sec
> ...
> $ ethtool --json -m sfp-wan
> [ {
> ...
>         "transceiver_codes": [ 0,0,0,1,32,64,12,21,0 ],
>         "transceiver_type": "FC: 100 MBytes/sec", ...
>     } ]
> 
> After:
> $ ethtool -m sfp-wan
> ...
> 	Transceiver codes                         : 0x00 0x00 0x00 0x01 0x20 0x40 0x0c
> 0x15 0x00
> 	Transceiver type                          : Ethernet: 1000BASE-SX
> 	Transceiver type                          : FC: intermediate distance (I)
> 	Transceiver type                          : FC: Shortwave laser w/o OFC (SN)
> 	Transceiver type                          : FC: Multimode, 62.5um (M6)
> 	Transceiver type                          : FC: Multimode, 50um (M5)
> 	Transceiver type                          : FC: 400 MBytes/sec
> 	Transceiver type                          : FC: 200 MBytes/sec
> 	Transceiver type                          : FC: 100 MBytes/sec
> ...
> $ ethtool --json -m sfp-wan
> [ {
> ...
>         "transceiver_codes": [ 0,0,0,1,32,64,12,21,0 ],
>         "transceiver_type": [ "Ethernet: 1000BASE-SX","FC: intermediate distance
> (I)","FC: Shortwave laser w/o OFC (SN)","FC: Multimode, 62.5um (M6)","FC:
> Multimode, 50um (M5)","FC: 400 MBytes/sec","FC: 200 MBytes/sec","FC:
> 100 MBytes/sec" ], ...
>     } ]
> 
> Fixes: 4071862f58d8 ("sfpid: Add JSON output handling to --module-info in
> SFF8079 modules")
> Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
> ---
> Changes in v3:
>  - fix indentation and checkpatch warnings Changes in v2:
>  - drop </pre> leftover
>  - use single sfp module in Before/After
>  - rename module_print_array_string() ->
> module_print_any_array_string_entry()
> ---

Reviewed-by: Danielle Ratson <danieller@nvidia.com>

^ permalink raw reply

* RE: [PATCH ethtool-next v3 3/3] qsfp: print all compliance codes
From: Danielle Ratson @ 2026-07-19 14:08 UTC (permalink / raw)
  To: Aleksander Jan Bajkowski, mkubecek@suse.cz, andrew@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, jbe@pengutronix.de, netdev@vger.kernel.org
In-Reply-To: <20260719090458.659332-3-olek2@wp.pl>

> -----Original Message-----
> From: Aleksander Jan Bajkowski <olek2@wp.pl>
> Sent: Sunday, 19 July 2026 12:01
> To: Danielle Ratson <danieller@nvidia.com>; olek2@wp.pl;
> mkubecek@suse.cz; andrew@lunn.ch; davem@davemloft.net;
> edumazet@google.com; kuba@kernel.org; pabeni@redhat.com;
> jbe@pengutronix.de; netdev@vger.kernel.org
> Subject: [PATCH ethtool-next v3 3/3] qsfp: print all compliance codes
> 
> QSFP modules implement multiple compliance codes. This is common for dual-
> rate modules. Before the `json` option was introduced, all compliance codes
> were displayed. Currently, only the last code is displayed. This commit fixes
> that bug. Compliance codes are represented as array.
> 
> Fixes: 4071862f58d8 ("sfpid: Add JSON output handling to --module-info in
> SFF8079 modules")
> Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
> ---
> Changes in v3:
>  - add patch to series
> ---

Reviewed-by: Danielle Ratson <danieller@nvidia.com>

^ permalink raw reply

* Re: [PATCH net] nfc: microread: validate CARD_FOUND event length before parsing targets
From: David Heidelberg @ 2026-07-19 14:15 UTC (permalink / raw)
  To: Doruk Tan Ozturk; +Cc: oe-linux-nfc, netdev, linux-kernel, stable, Pengpeng Hou
In-Reply-To: <20260713215936.23137-1-doruk@0sec.ai>

On 13/07/2026 23:59, Doruk Tan Ozturk wrote:
> microread_target_discovered() parses a device-supplied MREAD_CARD_FOUND
> event into a struct nfc_target, reading fixed offsets and -- for the
> ISO-A and ISO-A-3 gates -- a variable-length NFCID1 straight out of the
> event skb. The only length check is nfcid1_len vs sizeof(targets->nfcid1);
> skb->len itself is never validated, so a short event makes every gate
> case read out of bounds past the skb:
> 
>    - ISO-A / ISO-A-3: fixed ATQA/SAK/LEN reads plus a memcpy of an
>      attacker-controlled nfcid1_len bytes from the NFCID1 offset;
>    - ISO-B / NFC-T1 / NFC-T3: a fixed 4- or 8-byte NFCID1 memcpy from a
>      fixed offset.
> 
> The copied nfcid1 is exported to user space via nfc_targets_found(), so
> the over-read is an information leak (and a possible oops on an unmapped
> page).
> 
> Reject events too short for the fields each gate case reads.
> 
> Found by 0sec (https://0sec.ai).
> 
> Fixes: cfad1ba87150 ("NFC: Initial support for Inside Secure microread")
> Cc: stable@vger.kernel.org
> Assisted-by: 0sec
> Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
> ---
>   drivers/nfc/microread/microread.c | 31 +++++++++++++++++++++++++++++--
>   1 file changed, 29 insertions(+), 2 deletions(-)
> 
Hello Doruk,

thanks for the patch, 1. 7. I got the same one from Pengpeng, which needs to 
address Fixes and Cc tag [1].

Feel free to sync together for the future effort to not get duplicated (and 
tokens not wasted ;-) )

Adding Pengpeng to Cc.

David

[1] https://lore.kernel.org/all/20260701053709.45176-1-pengpeng@iscas.ac.cn/

^ permalink raw reply

* Re: [PATCH net-next v2 2/2] nfc: s3fwrn5: support the S3NRN4V variant
From: Jorijn van der Graaf @ 2026-07-19 14:22 UTC (permalink / raw)
  To: David Heidelberg, Krzysztof Kozlowski
  Cc: Jorijn van der Graaf, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Rob Herring, Conor Dooley,
	oe-linux-nfc, netdev, devicetree, linux-kernel, Luca Weiss
In-Reply-To: <18c3e13f-88e4-458e-9f57-7aceeb1ce1d1@ixit.cz>

Hello David,

Thank you for the review!

On 19/07/2026 15:15, David Heidelberg wrote:
> Please, send the "drop the of_match_ptr()/__maybe_unused annotations
> from it." type of change as part of the series, but as a separate
> commit before the new HW support introduction.

Will do in v3.

> Since you touch S3FWRN5_I2C_DRIVER_NAME, replace define
> S3FWRN5_I2C_DRIVER_NAME occurenced with the "s3fwrn5_i2c" directly
> before introducing the support (also separate commit)

Will do, also in v3.

> is S3NRN4V really a variant of S3FWRN5 or is it just S3NRN4V?

It is a separate, later part, but from the same Samsung S.LSI NFC
controller line this driver covers. Samsung's downstream stack drives
that whole line with one kernel driver and one HAL: the HAL's product
table lists the N5 (S3FWRN5) and N82 (S3FWRN82) generations next to
RN4V (S3NRN4V) and others, dispatching on a product code reported by
the chip's bootloader, and the parts share the I2C framing, the
power-control GPIO scheme and the proprietary-NCI style of
configuration. The generational differences (bootloader protocol,
RF-register transport command, FW_CFG payload form) are exactly what
this patch dispatches on -- the same way the driver already supports
the S3FWRN82 next to the S3FWRN5.

That said, "S3FWRN5-family" can indeed be read as "a variant of the
S3FWRN5 chip", which it is not, so I'll reword it in v3 to something
like "a later part of the same Samsung NFC controller line". The
phrase also sits in the commit message of the already-acked binding
patch; I'll tweak it there too (commit message only) and note it in
the changelog.

> While it's "register update" and function is named "configure_dual",
> it's loading firmware.
>
> If it's not a firmware, but only configuration, it can reside inside
> the driver, maybe LLM even be able to decode to understandable
> sequence of registers and values.

There are two separate things here: the chip's executable firmware
(~180 KiB) ships in its flash and is not touched by this patch at all
-- its download protocol is not implemented, which is why the
download step is skipped. What is loaded here are only the two RF
register tables (~3.5 KiB combined).

Those tables are configuration by nature, but I don't think they can
reside in the driver:

- They are board-specific analog/RF tuning, not chip constants: the
  values match a particular antenna/matching-network design, and the
  vendor revises them across software releases (my two Fairphone 6
  units shipped different builds of these files, with different
  version stamps embedded). A different S3NRN4V board design would be
  expected to ship its own tables. Per-device data loaded at runtime
  is what request_firmware() is there for, much like Wi-Fi
  board/calibration files. The tables ship in the device's vendor
  image, which is where I extracted them from.

- There is nothing to decode them against. The register map of these
  controllers is not publicly documented, and even Samsung's own
  (Apache-licensed) HAL treats the register content as opaque: the
  only part of the image it interprets is a 16-byte metadata trailer
  at its end (version stamps, used to decide whether an update is
  needed at all, plus a region code), while the register content
  itself is pushed to the chip untouched, in 252-byte sections.
  Nothing in the stream or in the vendor stack identifies
  address/value pairs one could transcribe, so "decoded" into the
  driver this could only become a 3.5 KiB hex array in C, and we
  would lose the ability to ship a newer table without rebuilding
  the kernel.

- It also mirrors what this driver already does for the parts it
  supports: s3fwrn5_nci_rf_configure() loads the same class of table
  (sec_s3fwrn5_rfreg.bin) with request_firmware() and pushes it via
  the older START/SET/STOP_RFREG commands. The new function is the
  same operation over the newer parts' transport command.

If the naming reads confusingly I'm happy to rename the function or
extend its comment to spell out the firmware-vs-register-table
distinction.

> For next revision of the patch, I'll likely still have some
> additional feedback.

Understood -- I'll send the v3 with all of the above shortly.

> With next revision send also as last patch the device-tree entry for
> the Fairphone 6, so we can also get additional testing from
> developers/users.

Will do -- v3 will carry the Fairphone 6 DT patch at the end of the
series, marked as included for testing and presumably to be picked up
via the Qualcomm DT tree once the driver side is settled; I'll Cc
linux-arm-msm and the qcom maintainers on that patch.

Thanks again,
Jorijn

^ permalink raw reply

* Re: [BUG] nfc: llcp: race between nfc_llcp_send_ui_frame() and llcp_sock_bind() dereferences NULL sock->dev
From: David Heidelberg @ 2026-07-19 14:24 UTC (permalink / raw)
  To: Junwoong Doh
  Cc: krzk, davem, edumazet, kuba, pabeni, horms, oe-linux-nfc, netdev,
	linux-kernel
In-Reply-To: <a89d0419-8bcf-40a2-b52d-3e5d911f11da@gmail.com>

On 14/07/2026 02:00, Junwoong Doh wrote:
> Hello,
> 
> Commit dded08927ca3 ("nfc: llcp: fix NULL error pointer dereference on
> sendmsg() after failed bind()") added a NULL check for llcp_sock->local
> in llcp_sock_sendmsg(), but it does not handle all the races.
> The thread interleaving is the same as Krzysztof mentioned:
> https://lore.kernel.org/oe-linux-nfc/20220119074816.6505-2-krzysztof.kozlowski@canonical.com/
> 
> In detail:
> nfc_llcp_send_ui_frame() checks sock->local == NULL, but it is called
> without socket's lock held, which opens a window for a race condition.
> Between the sock->local == NULL check and the sock->dev use in
> nfc_alloc_send_skb(), llcp_sock_bind() can run concurrently and set
> both sock->local and sock->dev to NULL.
> This leads to NULL pointer dereference in the nfc_alloc_send_skb() call.
> Moreover, the window can be enlarged by the
> memcpy_from_msg(msg_data, msg, len) call that sits between
> the sock->local check and the sock->dev use.

Hello Junwoong,

thank you for the report. Would you be willing to try preparing a patch against 
the NFC for-next or for-linus tree to fix the issue?

Thank you
David

[...]

^ permalink raw reply

* Re: [PATCH net-next v2 2/2] nfc: s3fwrn5: support the S3NRN4V variant
From: David Heidelberg @ 2026-07-19 14:56 UTC (permalink / raw)
  To: Jorijn van der Graaf, Luca Weiss, Krzysztof Kozlowski
  Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Rob Herring, Conor Dooley, oe-linux-nfc, netdev,
	devicetree, linux-kernel
In-Reply-To: <20260719142241.12640-1-jorijnvdgraaf@catcrafts.net>

On 19/07/2026 16:22, Jorijn van der Graaf wrote:
> Hello David,
> 
> Thank you for the review!
> 
> On 19/07/2026 15:15, David Heidelberg wrote:
>> Please, send the "drop the of_match_ptr()/__maybe_unused annotations
>> from it." type of change as part of the series, but as a separate
>> commit before the new HW support introduction.
> 
> Will do in v3.
> 
>> Since you touch S3FWRN5_I2C_DRIVER_NAME, replace define
>> S3FWRN5_I2C_DRIVER_NAME occurenced with the "s3fwrn5_i2c" directly
>> before introducing the support (also separate commit)
> 
> Will do, also in v3.
> 
>> is S3NRN4V really a variant of S3FWRN5 or is it just S3NRN4V?
> 
> It is a separate, later part, but from the same Samsung S.LSI NFC
> controller line this driver covers. Samsung's downstream stack drives
> that whole line with one kernel driver and one HAL: the HAL's product
> table lists the N5 (S3FWRN5) and N82 (S3FWRN82) generations next to
> RN4V (S3NRN4V) and others, dispatching on a product code reported by
> the chip's bootloader, and the parts share the I2C framing, the
> power-control GPIO scheme and the proprietary-NCI style of
> configuration. The generational differences (bootloader protocol,
> RF-register transport command, FW_CFG payload form) are exactly what
> this patch dispatches on -- the same way the driver already supports
> the S3FWRN82 next to the S3FWRN5.
> 
> That said, "S3FWRN5-family" can indeed be read as "a variant of the
> S3FWRN5 chip", which it is not, so I'll reword it in v3 to something
> like "a later part of the same Samsung NFC controller line". The
> phrase also sits in the commit message of the already-acked binding
> patch; I'll tweak it there too (commit message only) and note it in
> the changelog.
> 
>> While it's "register update" and function is named "configure_dual",
>> it's loading firmware.
>>
>> If it's not a firmware, but only configuration, it can reside inside
>> the driver, maybe LLM even be able to decode to understandable
>> sequence of registers and values.
> 
> There are two separate things here: the chip's executable firmware
> (~180 KiB) ships in its flash and is not touched by this patch at all
> -- its download protocol is not implemented, which is why the
> download step is skipped. What is loaded here are only the two RF
> register tables (~3.5 KiB combined).
> 
> Those tables are configuration by nature, but I don't think they can
> reside in the driver:
> 
> - They are board-specific analog/RF tuning, not chip constants: the
>    values match a particular antenna/matching-network design, and the
>    vendor revises them across software releases (my two Fairphone 6
>    units shipped different builds of these files, with different
>    version stamps embedded). A different S3NRN4V board design would be
>    expected to ship its own tables. Per-device data loaded at runtime
>    is what request_firmware() is there for, much like Wi-Fi
>    board/calibration files. The tables ship in the device's vendor
>    image, which is where I extracted them from.
> 
> - There is nothing to decode them against. The register map of these
>    controllers is not publicly documented, and even Samsung's own
>    (Apache-licensed) HAL treats the register content as opaque: the
>    only part of the image it interprets is a 16-byte metadata trailer
>    at its end (version stamps, used to decide whether an update is
>    needed at all, plus a region code), while the register content
>    itself is pushed to the chip untouched, in 252-byte sections.
>    Nothing in the stream or in the vendor stack identifies
>    address/value pairs one could transcribe, so "decoded" into the
>    driver this could only become a 3.5 KiB hex array in C, and we
>    would lose the ability to ship a newer table without rebuilding
>    the kernel.
> 
> - It also mirrors what this driver already does for the parts it
>    supports: s3fwrn5_nci_rf_configure() loads the same class of table
>    (sec_s3fwrn5_rfreg.bin) with request_firmware() and pushes it via
>    the older START/SET/STOP_RFREG commands. The new function is the
>    same operation over the newer parts' transport command.
> 
> If the naming reads confusingly I'm happy to rename the function or
> extend its comment to spell out the firmware-vs-register-table
> distinction.

Thanks,

now it makes more sense to me, feel free to name it as calibration data.

I would suggest to introduce something as a calibration-variant (see ath10k code).

If I understand right, firmware location path could look like

default path + driver vendor and model + device vendor and model + revision

/lib/firmware/ + Samsung/s3nrn4v/ + Fairphone/FP5/hwrevision.bin

/cc Luca here, as he may know more about the different configuration data shipped.

We should assume the configuration will be shipped with linux-firmware at some 
point.

David

> 
>> For next revision of the patch, I'll likely still have some
>> additional feedback.
> 
> Understood -- I'll send the v3 with all of the above shortly.
> 
>> With next revision send also as last patch the device-tree entry for
>> the Fairphone 6, so we can also get additional testing from
>> developers/users.
> 
> Will do -- v3 will carry the Fairphone 6 DT patch at the end of the
> series, marked as included for testing and presumably to be picked up
> via the Qualcomm DT tree once the driver side is settled; I'll Cc
> linux-arm-msm and the qcom maintainers on that patch.
> 
> Thanks again,
> Jorijn

-- 
David Heidelberg


^ permalink raw reply

* Re: [PATCH 6.12] vsock/virtio: fix zerocopy completion for multi-skb sends
From: Sasha Levin @ 2026-07-19 15:00 UTC (permalink / raw)
  To: stable, Greg Kroah-Hartman
  Cc: Sasha Levin, Alexander Martyniuk, lvc-project, Michael S. Tsirkin,
	Jason Wang, Xuan Zhuo, Eugenio Pérez, Stefan Hajnoczi,
	Stefano Garzarella, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Arseniy Krasnov, virtualization, kvm,
	netdev, linux-kernel, Maher Azzouzi
In-Reply-To: <20260716163600.115458-1-alexevgmart@gmail.com>

> When a large message is fragmented into multiple skbs, the zerocopy
> uarg is only allocated and attached to the last skb in the loop.
> Non-final skbs carry pinned user pages with no completion tracking,
> so the kernel has no way to notify userspace when those pages are safe
> to reuse.

Queued for 6.12, thanks.

-- 
Thanks,
Sasha

^ permalink raw reply

* [PATCH] net: pktgen: fix proc entry use-after-free
From: Chengfeng Ye @ 2026-07-19 14:57 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Thorsten Blum, Andrew Morton, Andy Shevchenko,
	Randy Dunlap, Chengfeng Ye, Robert Olsson, Stephen Hemminger
  Cc: netdev, linux-kernel, stable

pktgen_change_name() replaces pkt_dev->entry while holding t->if_lock.
pktgen_remove_device() removes the same entry before
_rem_dev_from_if_list() takes that lock.

This allows the following interleaving:

  CPU 0 (NETDEV_CHANGENAME)       CPU 1 (kpktgend)
  if_lock(t)
  proc_remove(pkt_dev->entry)
                                  proc_remove(pkt_dev->entry)
  pkt_dev->entry = proc_create_data(...)
  if_unlock(t)

The kthread can pass the stale proc_dir_entry to proc_remove() after the
rename path has freed it. A reproducer with a widened race window reports:

  BUG: KASAN: slab-use-after-free in proc_remove+0x78/0x80
  Read of size 8 at addr ffff8881478fea70 by task kpktgend_0/67
  Call Trace:
   proc_remove+0x78/0x80
   pktgen_remove_device.isra.0+0x11c/0x4c0
   pktgen_thread_worker+0x1214/0x6bc0
   kthread+0x2c6/0x3b0
  Allocated by task 95:
   __proc_create+0x204/0x790
   proc_create_data+0x72/0xe0
   pktgen_thread_write+0xd61/0x1510
  Freed by task 28:
   kmem_cache_free+0xcb/0x3d0
   proc_free_inode+0x5b/0x80
   rcu_core+0x50a/0x1850
  The buggy address belongs to the object at ffff8881478fea00
   which belongs to the cache proc_dir_entry of size 192

Move proc_remove() into the if_lock-protected list removal helper. Keep it
before list_del_rcu() to preserve the ordering required by add_device().
The rename path must then finish replacing the entry before removal, or
it observes that the device is no longer on the list.

Fixes: 39df232f1a9b ("[PKTGEN]: fix device name handling")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
---
 net/core/pktgen.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 8e185b318288..ee64f3012321 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -3972,6 +3972,7 @@ static void _rem_dev_from_if_list(struct pktgen_thread *t,
 	struct pktgen_dev *p;
 
 	if_lock(t);
+	proc_remove(pkt_dev->entry);
 	list_for_each_safe(q, n, &t->if_list) {
 		p = list_entry(q, struct pktgen_dev, list);
 		if (p == pkt_dev)
@@ -4001,9 +4002,6 @@ static int pktgen_remove_device(struct pktgen_thread *t,
 	 * list to determine if interface already exist, avoid race
 	 * with proc_create_data()
 	 */
-	proc_remove(pkt_dev->entry);
-
-	/* And update the thread if_list */
 	_rem_dev_from_if_list(t, pkt_dev);
 
 #ifdef CONFIG_XFRM
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH net v5 0/3] nfc: fix remaining OOB bugs in NCI/LLCP parsing
From: David Heidelberg @ 2026-07-19 15:04 UTC (permalink / raw)
  To: Lekë Hapçiu, David Heidelberg
  Cc: davem, edumazet, kuba, pabeni, krzk, horms, linux-kernel, netdev,
	oe-linux-nfc
In-Reply-To: <20260716203507.7328-1-snowwlake@icloud.com>

On 16/07/2026 22:35, Lekë Hapçiu wrote:
> Rebased against David's linux-nfc for-linus tree [1], as requested.
> 
> This was originally a 5-patch series. Two of the five (the
> parse_gb_tlv()/parse_connection_tlv() offset-wrap fix and the
> nfc_llcp_recv_snl() TLV bounds fix) have since been fixed independently
> by other contributors already merged into for-linus:
> 
>    d8bd2dedbde5 ("nfc: llcp: fix OOB read and u8 offset wrap in TLV parsers")
>    27256cdb290e ("nfc: llcp: bound SNL TLV parsing to the skb and add length checks")
> 
> Those two are dropped from this series to avoid duplicating work. The
> remaining three patches are unchanged in substance from v4, just
> rebased and renumbered:
> 
>    1/3 (was 1/5) - nci_store_general_bytes_nfc_dep() u8 underflow
>    2/3 (was 4/5) - nfc_llcp_recv_dm() OOB read of the reason byte
>    3/3 (was 5/5) - nfc_llcp_connect_sn() TLV parsing OOB
> 
> All three still reproduce against current for-linus (verified against
> 1671b8fb7300 before rebase). checkpatch --strict is clean on all three.
> 
> [1] https://codeberg.org/linux-nfc/linux.git for-linus
> 
> Lekë Hapçiu (3):
>    nfc: nci: fix u8 underflow in nci_store_general_bytes_nfc_dep
>    nfc: llcp: fix OOB read of DM reason byte in nfc_llcp_recv_dm
>    nfc: llcp: fix TLV parsing OOB in nfc_llcp_connect_sn
> 
>   net/nfc/llcp_core.c | 19 +++++++++++++++++--
>   net/nfc/nci/ntf.c   |  6 ++++++
>   2 files changed, 23 insertions(+), 2 deletions(-)
> 

Hello Lekë,

I'm afraid I won't make you happy here, but after merging the outstanding 
backlog today, I ran into conflicts again with your patch series. I'm very sorry 
about that, but I've been receiving a high number of fixes.

Now that I'm back from the conference, if you send the next revision based on 
the current for-linus / for-next, I believe I'll be able to apply it quickly 
enough to avoid conflicts.

Thank you for your understanding.

David

^ permalink raw reply

* [PATCH] bpf, sockmap: Fix sk_redir use-after-free in send verdict
From: Chengfeng Ye @ 2026-07-19 15:22 UTC (permalink / raw)
  To: Eric Dumazet, Neal Cardwell, Kuniyuki Iwashima, John Fastabend,
	Jakub Sitnicki, Jiayuan Chen, David S. Miller, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Daniel Borkmann, Alexei Starovoitov,
	open list:BPF [L7 FRAMEWORK] (sockmap)
  Cc: netdev, linux-kernel, Chengfeng Ye, stable

sk_psock_msg_verdict() takes a socket reference for psock->sk_redir.
tcp_bpf_send_verdict() copies that pointer while holding the source socket
lock, but does not take a reference for the local copy before dropping the
lock around tcp_bpf_sendmsg_redir().

When apply_bytes keeps the cached verdict active, another sendmsg() on the
same source socket can consume the remaining bytes and release the cached
reference while the first thread still holds only the raw local pointer:

  CPU 0                                  CPU 1
  sk_redir = psock->sk_redir
  apply_bytes remains nonzero
  release_sock(sk)
                                         lock_sock(sk)
                                         apply_bytes reaches zero
                                         psock->sk_redir = NULL
                                         release_sock(sk)
                                         tcp_bpf_sendmsg_redir(sk_redir)
                                         sock_put(sk_redir)
  tcp_bpf_sendmsg_redir(sk_redir)

The final sock_put() can free sk_redir before CPU 0 dereferences it.

KASAN reported:

  BUG: KASAN: slab-use-after-free in tcp_bpf_sendmsg_redir+0xf39/0x1020
  Read of size 8 at addr ffff888108537090 by task poc/87
  Call Trace:
   tcp_bpf_sendmsg_redir+0xf39/0x1020
   tcp_bpf_sendmsg+0x977/0x1a50
   __sys_sendto+0x32c/0x3a0
   __x64_sys_sendto+0xdb/0x1b0
  Allocated by task 85:
   sk_prot_alloc+0x56/0x210
   sk_clone+0x6f/0x14b0
   inet_csk_clone_lock+0x24/0x740
   tcp_create_openreq_child+0x25/0x2710
   tcp_v4_syn_recv_sock+0x10a/0xe00
  Freed by task 0:
   __kasan_slab_free+0x43/0x70
   slab_free_after_rcu_debug+0xa6/0x1e0
   rcu_core+0x50a/0x1850
  Last potentially related work creation:
   __sk_destruct+0x3da/0x540
   sk_psock_destroy+0x81e/0xab0
   process_one_work+0x63a/0x1070

Take a temporary socket reference while the source socket lock still
protects psock->sk_redir, and drop it after tcp_bpf_sendmsg_redir()
returns.  This keeps each unlocked use independent of cached-verdict
ownership.

Fixes: 604326b41a6f ("bpf, sockmap: convert to generic sk_msg interface")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
---
 net/ipv4/tcp_bpf.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
index 8e905b50dead..69cc8bc33bcd 100644
--- a/net/ipv4/tcp_bpf.c
+++ b/net/ipv4/tcp_bpf.c
@@ -469,6 +469,7 @@ static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
 	case __SK_REDIRECT:
 		redir_ingress = psock->redir_ingress;
 		sk_redir = psock->sk_redir;
+		sock_hold(sk_redir);
 		sk_msg_apply_bytes(psock, tosend);
 		if (!psock->apply_bytes) {
 			/* Clean up before releasing the sock lock. */
@@ -489,6 +490,7 @@ static int tcp_bpf_send_verdict(struct sock *sk, struct sk_psock *psock,
 
 		if (eval == __SK_REDIRECT)
 			sock_put(sk_redir);
+		sock_put(sk_redir);
 
 		lock_sock(sk);
 		sk_mem_uncharge(sk, sent);
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH net v2] nfc: nci: fix use of uninitialized memory in NFC-DEP general bytes
From: David Heidelberg @ 2026-07-19 15:27 UTC (permalink / raw)
  To: Muhammad Bilal
  Cc: netdev, davem, edumazet, kuba, pabeni, horms, oe-linux-nfc,
	linux-kernel, stable
In-Reply-To: <20260628214929.135152-1-meatuni001@gmail.com>

On 28/06/2026 23:49, Muhammad Bilal wrote:
> nci_store_general_bytes_nfc_dep() derives the length of the NFC-DEP
> general bytes by subtracting the fixed general-bytes offset from the ATR
> length:
> 
>    atr_res_len - NFC_ATR_RES_GT_OFFSET   (poll, offset 15)
>    atr_req_len - NFC_ATR_REQ_GT_OFFSET   (listen, offset 14)
> 
> It never checks that the ATR is at least that long.  When a
> RF_INTF_ACTIVATED_NTF reports an ATR shorter than the offset the
> subtraction is negative; because min_t() casts its arguments to __u8 the
> negative value becomes large and is then capped at
> NFC_ATR_RES_GB_MAXSIZE / NFC_ATR_REQ_GB_MAXSIZE.  remote_gb_len is thus
> set to up to 47/48 even though only atr_res_len/atr_req_len bytes of the
> on-stack atr_res/atr_req buffer were copied from the packet, and the
> following memcpy() reads the uninitialized remainder into
> ndev->remote_gb.
> 
> Zero remote_gb_len and skip storing the general bytes when the ATR is
> shorter than the general-bytes offset, so that a stale remote_gb_len
> from a previous activation does not survive into the new session.
> 
> Fixes: a99903ec4566 ("NFC: NCI: Handle Target mode activation")
> Cc: stable@vger.kernel.org
> Signed-off-by: Muhammad Bilal <meatuni001@gmail.com>
> ---
>   net/nfc/nci/ntf.c | 8 ++++++--
>   1 file changed, 6 insertions(+), 2 deletions(-)
> 
Hello Muhammad,

could you please rebase the patch on the currect version for-linus or for-next?

Thank you
David

^ permalink raw reply

* Re: [PATCH v3 net 4/6] xsk: reclaim invalid multi-buffer Tx descs in ZC path
From: Jason Xing @ 2026-07-19 15:30 UTC (permalink / raw)
  To: Maciej Fijalkowski
  Cc: netdev, bpf, magnus.karlsson, stfomichev, kuba, pabeni, horms,
	bjorn
In-Reply-To: <alzPbtHWgy97oeBv@boxer>

On Sun, Jul 19, 2026 at 9:22 PM Maciej Fijalkowski
<maciej.fijalkowski@intel.com> wrote:
>
> On Thu, Jul 16, 2026 at 11:58:24PM +0200, Jason Xing wrote:
> > On Tue, Jul 14, 2026 at 4:08 PM Maciej Fijalkowski
> > <maciej.fijalkowski@intel.com> wrote:
> > >
> > > The zero-copy Tx batch parser stops when it encounters an invalid
> > > descriptor. If this happens after one or more continuation descriptors,
> > > the Tx consumer can be advanced past fragments that are neither submitted
> > > to the driver nor returned to userspace through the completion ring.
> > >
> > > A similar problem occurs when a packet exceeds xdp_zc_max_segs. The
> > > descriptors consumed up to the limit are released without completion, and
> > > the remaining continuation descriptors can subsequently be interpreted
> > > as the beginning of another packet.
> > >
> > > Parse Tx batches in packet units and distinguish descriptors belonging to
> > > complete valid packets from descriptors consumed while draining an
> > > invalid or oversized packet. Return the former to the driver and append
> > > the latter to the CQ address area so userspace can reclaim their UMEM
> > > frames.
> > >
> > > Once draining starts, continue until the packet's end-of-packet
> > > descriptor is consumed. Preserve the drain state on the socket when EOP
> > > has not yet been supplied, so draining can continue during a later call.
> > > Leave incomplete but otherwise valid packets on the Tx ring. Keep the
> > > existing handling of standalone invalid descriptors unchanged.
> > >
> > > Shared-UMEM pools using multi-buffer Tx also need packet-framed parsing.
> > > Walk their Tx sockets one packet at a time, preserving the existing
> > > per-socket fairness scheme, instead of using the legacy one-descriptor
> > > fallback. Keep that fallback for shared pools that do not use
> > > multi-buffer Tx. Since the drain state is maintained per socket and both
> > > the singular and shared paths can resume an interrupted drain, changing
> > > the socket list from singular to shared requires no special bind-time
> > > transition.
> > >
> > > CQ entries are positional, and drivers may complete only part of the Tx
> > > work returned by xsk_tx_peek_release_desc_batch(). Therefore, reclaim-only
> > > entries cannot be published immediately when earlier driver-visible
> > > descriptors are still outstanding.
> > >
> > > Track the number of driver-visible CQ entries preceding the reclaim
> > > entries. Let xsk_tx_completed() publish partial real Tx completions, and
> > > publish the reclaim entries only after every earlier Tx descriptor has
> > > completed. Complete a reclaim-only batch immediately when there is no
> > > driver-visible work in front of it, and prevent another Tx batch from
> > > being appended while reclaim entries remain pending.
> > >
> > > Also cap batch processing by the size of the pool's temporary descriptor
> > > array, as Tx rings belonging to sockets sharing a UMEM may have different
> > > sizes.
> > >
> > > This ensures that every descriptor consumed as part of an invalid
> > > multi-buffer packet is eventually returned to userspace without exposing
> > > the dropped packet to the driver or violating CQ completion ordering.
> > >
> > > Fixes: cf24f5a5feea ("xsk: add support for AF_XDP multi-buffer on Tx path")
> > > Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> >
> > Thanks for working on this big patch! It's not easy to fix it in a
> > simpler way, I think. And I didn't observe any obvious performance
> > impact by xdpsock.
> >
> > Overall, it looks good to me except for a few minor points:
> > Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
> >
> > > ---
> > >  include/net/xsk_buff_pool.h |   3 +
> > >  net/xdp/xsk.c               | 192 ++++++++++++++++++++++++++++++++----
> > >  net/xdp/xsk_buff_pool.c     |   1 +
> > >  net/xdp/xsk_queue.h         |  76 ++++++++++----
> > >  4 files changed, 232 insertions(+), 40 deletions(-)
> > >
> > > diff --git a/include/net/xsk_buff_pool.h b/include/net/xsk_buff_pool.h
> > > index f5e737a83055..2bb1d122b1bc 100644
> > > --- a/include/net/xsk_buff_pool.h
> > > +++ b/include/net/xsk_buff_pool.h
> > > @@ -78,6 +78,9 @@ struct xsk_buff_pool {
> > >         u32 chunk_size;
> > >         u32 chunk_shift;
> > >         u32 frame_len;
> > > +       u32 tx_descs_nentries;
> > > +       u32 reclaim_descs;
> > > +       u32 tx_zc_pending_descs;
> > >         u32 xdp_zc_max_segs;
> > >         u8 tx_metadata_len; /* inherited from umem */
> > >         u8 cached_need_wakeup;
> > > diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
> > > index 385a3f4a1b32..2909a0ec6837 100644
> > > --- a/net/xdp/xsk.c
> > > +++ b/net/xdp/xsk.c
> > > @@ -499,6 +499,23 @@ void __xsk_map_flush(struct list_head *flush_list)
> > >
> > >  void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries)
> > >  {
> > > +       u32 reclaim_descs = READ_ONCE(pool->reclaim_descs);
> > > +
> > > +       if (unlikely(reclaim_descs)) {
> >
> > Just a side note: it might impact the performance because new descs
> > need to wait for the existing descs to be completed if there are
> > reclaim descs.
>
> That is a tradeoff for dealing with this corner case i'd say.
>
> >
> > > +               u32 pending_descs = READ_ONCE(pool->tx_zc_pending_descs);
> > > +
> > > +               if (nb_entries < pending_descs) {
> > > +                       WRITE_ONCE(pool->tx_zc_pending_descs,
> > > +                                  pending_descs - nb_entries);
> > > +                       xskq_prod_submit_n(pool->cq, nb_entries);
> > > +                       return;
> > > +               }
> > > +
> > > +               WRITE_ONCE(pool->tx_zc_pending_descs, 0);
> > > +               nb_entries += reclaim_descs;
> > > +               WRITE_ONCE(pool->reclaim_descs, 0);
> > > +       }
> > > +
> > >         xskq_prod_submit_n(pool->cq, nb_entries);
> > >  }
> > >  EXPORT_SYMBOL(xsk_tx_completed);
> > > @@ -574,24 +591,162 @@ static u32 xsk_tx_peek_release_fallback(struct xsk_buff_pool *pool, u32 max_entr
> > >         return nb_pkts;
> > >  }
> > >
> > > +static void xsk_tx_commit_batch(struct xsk_buff_pool *pool,
> > > +                               struct xsk_tx_batch *batch)
> > > +{
> > > +       u32 nb_descs = xsk_tx_batch_cq_descs(batch);
> > > +       u32 cq_cached_prod;
> > > +
> > > +       if (!nb_descs)
> > > +               return;
> > > +
> > > +       cq_cached_prod = pool->cq->cached_prod;
> > > +       xskq_prod_write_addr_batch(pool->cq, pool->tx_descs, nb_descs);
> > > +
> > > +       if (unlikely(batch->reclaim_descs)) {
> > > +               u32 cq_pending_descs;
> > > +
> > > +               /* CQ is positional. Descriptors already written but not
> > > +                * submitted must complete before any reclaim-only descriptors
> > > +                * appended below.
> > > +                */
> > > +               cq_pending_descs = cq_cached_prod - xskq_get_prod(pool->cq);
> > > +
> > > +               WRITE_ONCE(pool->tx_zc_pending_descs,
> > > +                          batch->tx_descs + cq_pending_descs);
> > > +               WRITE_ONCE(pool->reclaim_descs, batch->reclaim_descs);
> > > +               if (unlikely(!pool->tx_zc_pending_descs))
> > > +                       xsk_tx_completed(pool, 0);
> > > +       }
> > > +}
> > > +
> > > +static struct xsk_tx_batch
> > > +__xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, struct xdp_sock *xs,
> > > +                                struct xdp_desc *descs, u32 max_descs)
> > > +{
> > > +       struct xsk_tx_batch batch = {};
> > > +       u32 entries;
> > > +
> > > +       entries = xskq_cons_nb_entries(xs->tx, max_descs);
> > > +       if (!entries)
> > > +               return batch;
> > > +
> > > +       batch = xskq_cons_read_desc_batch(xs, pool, descs, max_descs);
> > > +       if (!xsk_tx_batch_cq_descs(&batch)) {
> > > +               xs->tx->queue_empty_descs++;
> > > +               if (batch.consumed_descs) {
> > > +                       __xskq_cons_release(xs->tx);
> > > +                       xs->sk.sk_write_space(&xs->sk);
> > > +               }
> > > +               return batch;
> > > +       }
> > > +
> > > +       __xskq_cons_release(xs->tx);
> > > +       xs->sk.sk_write_space(&xs->sk);
> > > +       return batch;
> > > +}
> > > +
> > > +static struct xsk_tx_batch
> > > +xsk_tx_peek_release_shared_desc_batch(struct xsk_buff_pool *pool, u32 max_descs)
> > > +{
> > > +       u32 cq_descs_before, cq_descs_after;
> > > +       struct xsk_tx_batch sum_batch = {};
> > > +       bool budget_exhausted;
> > > +       u32 per_socket_budget;
> > > +       struct xdp_sock *xs;
> > > +
> > > +       /* The fairness quota must allow one maximum-sized valid packet. */
> > > +       per_socket_budget = max_t(u32, MAX_PER_SOCKET_BUDGET,
> > > +                                 pool->xdp_zc_max_segs);
> > > +
> > > +again:
> > > +       budget_exhausted = false;
> > > +       cq_descs_before = xsk_tx_batch_cq_descs(&sum_batch);
> > > +       list_for_each_entry_rcu(xs, &pool->xsk_tx_list, tx_list) {
> > > +               u32 budget, budget_left, offset, remaining;
> > > +               struct xsk_tx_batch curr_batch;
> > > +
> > > +               /* Once reclaim-only descriptors have been appended to the CQ
> > > +                * address area, do not append driver-visible Tx descriptors
> > > +                * from another socket after them. xsk_tx_completed() relies on
> > > +                * all driver-visible descriptors preceding all reclaim-only
> > > +                * descriptors in CQ order.
> > > +                */
> > > +               if (sum_batch.reclaim_descs)
> > > +                       break;
> > > +
> > > +               /* be gentle when playing with pool->tx_descs */
> >
> > Minor nit: seems unneeded comment?
>
> this has been my helper/reminder that we need to respect already consumed
> space at tx_descs array; i can remove it
>
> >
> > > +               offset = xsk_tx_batch_cq_descs(&sum_batch);
> > > +               if (offset >= max_descs)
> > > +                       break;
> > > +
> > > +               if (xs->tx_budget_spent >= per_socket_budget) {
> > > +                       if (xskq_cons_nb_entries(xs->tx, 1))
> > > +                               budget_exhausted = true;
> > > +                       continue;
> > > +               }
> > > +
> > > +               budget_left = per_socket_budget - xs->tx_budget_spent;
> > > +               remaining = max_descs - offset;
> > > +               budget = min(remaining, budget_left);
> > > +
> > > +               curr_batch = __xsk_tx_peek_release_desc_batch(pool, xs,
> > > +                                                             pool->tx_descs + offset,
> > > +                                                             budget);
> > > +               if (!xsk_tx_batch_cq_descs(&curr_batch)) {
> > > +                       if (curr_batch.budget_limited && budget_left < remaining)
> > > +                               budget_exhausted = true;
> > > +                       xs->tx_budget_spent += curr_batch.consumed_descs;
> > > +                       continue;
> > > +               }
> > > +
> > > +               xs->tx_budget_spent += curr_batch.consumed_descs;
> > > +               sum_batch.tx_descs += curr_batch.tx_descs;
> >
> > No need to use '+' here because of the previous reclaim_descs check.
>
> hmm correct!
>
> >
> > > +               sum_batch.reclaim_descs += curr_batch.reclaim_descs;
> > > +       }
> > > +
> > > +       cq_descs_after = xsk_tx_batch_cq_descs(&sum_batch);
> > > +
> > > +       if (sum_batch.reclaim_descs || cq_descs_after >= max_descs)
> > > +               return sum_batch;
> > > +
> > > +       /* Continue filling the batch while this pass made progress */
> > > +       if (cq_descs_before != cq_descs_after)
> > > +               goto again;
> > > +
> > > +       if (!budget_exhausted)
> > > +               return sum_batch;
> > > +
> > > +       list_for_each_entry_rcu(xs, &pool->xsk_tx_list, tx_list)
> > > +               xs->tx_budget_spent = 0;
> > > +       goto again;
> > > +}
> > > +
> > >  u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 nb_pkts)
> > >  {
> > > +       struct xsk_tx_batch batch = {};
> > >         struct xdp_sock *xs;
> > > +       bool umem_shared;
> > >
> > >         rcu_read_lock();
> > > -       if (!list_is_singular(&pool->xsk_tx_list)) {
> > > -               /* Fallback to the non-batched version */
> > > -               rcu_read_unlock();
> > > -               return xsk_tx_peek_release_fallback(pool, nb_pkts);
> > > -       }
> > > +       if (unlikely(READ_ONCE(pool->reclaim_descs)))
> > > +               goto out;
> > >
> > > -       xs = list_first_or_null_rcu(&pool->xsk_tx_list, struct xdp_sock, tx_list);
> > > -       if (!xs) {
> > > -               nb_pkts = 0;
> > > +       xs = list_first_or_null_rcu(&pool->xsk_tx_list, struct xdp_sock,
> > > +                                   tx_list);
> > > +       if (!xs)
> > >                 goto out;
> > > -       }
> > >
> > > -       nb_pkts = xskq_cons_nb_entries(xs->tx, nb_pkts);
> > > +       nb_pkts = min(nb_pkts, pool->tx_descs_nentries);
> > > +       if (!nb_pkts)
> > > +               goto out;
> > > +
> > > +       umem_shared = !list_is_singular(&pool->xsk_tx_list);
> > > +
> > > +       if (umem_shared && !(pool->umem->flags & XDP_UMEM_SG_FLAG)) {
> > > +               rcu_read_unlock();
> > > +               return xsk_tx_peek_release_fallback(pool, nb_pkts);
> > > +       }
> > >
> > >         /* This is the backpressure mechanism for the Tx path. Try to
> > >          * reserve space in the completion queue for all packets, but
> > > @@ -603,19 +758,16 @@ u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 nb_pkts)
> > >         if (!nb_pkts)
> > >                 goto out;
> > >
> > > -       nb_pkts = xskq_cons_read_desc_batch(xs->tx, pool, nb_pkts);
> > > -       if (!nb_pkts) {
> > > -               xs->tx->queue_empty_descs++;
> > > -               goto out;
> > > -       }
> > > -
> > > -       __xskq_cons_release(xs->tx);
> > > -       xskq_prod_write_addr_batch(pool->cq, pool->tx_descs, nb_pkts);
> > > -       xs->sk.sk_write_space(&xs->sk);
> > > +       batch = umem_shared ?
> > > +               xsk_tx_peek_release_shared_desc_batch(pool, nb_pkts) :
> > > +               __xsk_tx_peek_release_desc_batch(pool, xs,
> > > +                                                pool->tx_descs,
> > > +                                                nb_pkts);
> > > +       xsk_tx_commit_batch(pool, &batch);
> > >
> > >  out:
> > >         rcu_read_unlock();
> > > -       return nb_pkts;
> > > +       return batch.tx_descs;
> > >  }
> > >  EXPORT_SYMBOL(xsk_tx_peek_release_desc_batch);
> > >
> > > diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c
> > > index 12c9fb29af05..a4089480b22b 100644
> > > --- a/net/xdp/xsk_buff_pool.c
> > > +++ b/net/xdp/xsk_buff_pool.c
> > > @@ -51,6 +51,7 @@ int xp_alloc_tx_descs(struct xsk_buff_pool *pool, struct xdp_sock *xs,
> > >         if (!pool->tx_descs)
> > >                 return -ENOMEM;
> > >
> > > +       pool->tx_descs_nentries = nentries;
> > >         return 0;
> > >  }
> > >
> > > diff --git a/net/xdp/xsk_queue.h b/net/xdp/xsk_queue.h
> > > index 3e3fbb73d23e..a15ff1929db6 100644
> > > --- a/net/xdp/xsk_queue.h
> > > +++ b/net/xdp/xsk_queue.h
> > > @@ -58,6 +58,18 @@ struct parsed_desc {
> > >         u32 valid;
> > >  };
> > >
> > > +struct xsk_tx_batch {
> > > +       u32 tx_descs;
> > > +       u32 reclaim_descs;
> > > +       u32 consumed_descs;
> > > +       bool budget_limited;
> > > +};
> > > +
> > > +static inline u32 xsk_tx_batch_cq_descs(const struct xsk_tx_batch *batch)
> > > +{
> > > +       return batch->tx_descs + batch->reclaim_descs;
> > > +}
> > > +
> > >  /* The structure of the shared state of the rings are a simple
> > >   * circular buffer, as outlined in
> > >   * Documentation/core-api/circular-buffers.rst. For the Rx and
> > > @@ -263,17 +275,18 @@ static inline void parse_desc(struct xsk_queue *q, struct xsk_buff_pool *pool,
> > >         parsed->mb = xp_mb_desc(desc);
> > >  }
> > >
> > > -static inline
> > > -u32 xskq_cons_read_desc_batch(struct xsk_queue *q, struct xsk_buff_pool *pool,
> > > -                             u32 max)
> > > +static inline struct xsk_tx_batch
> > > +xskq_cons_read_desc_batch(struct xdp_sock *xs, struct xsk_buff_pool *pool,
> > > +                         struct xdp_desc *descs, u32 max)
> > >  {
> > > -       u32 cached_cons = q->cached_cons, nb_entries = 0;
> > > -       struct xdp_desc *descs = pool->tx_descs;
> > > -       u32 total_descs = 0, nr_frags = 0;
> > > +       bool drain = READ_ONCE(xs->drain_cont);
> > > +       u32 cached_cons, nb_entries = 0, released;
> > > +       struct xsk_tx_batch batch = {};
> > > +       struct xsk_queue *q = xs->tx;
> > > +       u32 nr_frags = 0;
> > > +
> > > +       cached_cons = q->cached_cons;
> > >
> > > -       /* track first entry, if stumble upon *any* invalid descriptor, rewind
> > > -        * current packet that consists of frags and stop the processing
> > > -        */
> > >         while (cached_cons != q->cached_prod && nb_entries < max) {
> > >                 struct xdp_rxtx_ring *ring = (struct xdp_rxtx_ring *)q->ring;
> > >                 u32 idx = cached_cons & q->ring_mask;
> > > @@ -282,26 +295,49 @@ u32 xskq_cons_read_desc_batch(struct xsk_queue *q, struct xsk_buff_pool *pool,
> > >                 descs[nb_entries] = ring->desc[idx];
> > >                 cached_cons++;
> > >                 parse_desc(q, pool, &descs[nb_entries], &parsed);
> > > -               if (unlikely(!parsed.valid))
> > > -                       break;
> > > +               if (unlikely(!parsed.valid)) {
> > > +                       if (!drain && !nr_frags && !parsed.mb)
> >
> > I understand you're fixing the mb problem here. But I'm wondering if
> > it still has a problem in the non mb case because the single invalid
> > packet (mb ==0, nr_frags == 0, drain == 0) that isn't published in CQ
> > cannot be tracked by application?
> >
> > My thinking is to just remove the above line in this patch. Or I can
> > cook a follow-up patch to fix this specific problem?
>
> Good catch - seems I got too focused at mb case and now we have a bit of
> misbehave as invalid mb descs are cq produced and standalone not.
>
> I'm gonna address this and align standalone descs (in generic xmit as
> well) that are invalid so they are also cq published, not silently wiped
> out from tx ring only.
>
> Thanks! sending v4.

Great! Thanks!

^ permalink raw reply

* Re: [PATCH net-next] net: phy: motorcomm: enable the reference clock for YT8531
From: Andrew Lunn @ 2026-07-19 15:34 UTC (permalink / raw)
  To: Jiaxing Hu
  Cc: Frank.Sae, hkallweit1, linux, davem, edumazet, kuba, pabeni,
	netdev, linux-kernel, maxime.chevallier, heiko, linux-rockchip
In-Reply-To: <20260719034555.3623003-1-gahing@gahingwoo.com>

On Sun, Jul 19, 2026 at 03:45:55PM +1200, Jiaxing Hu wrote:
> The YT8531 needs a 25 MHz reference. On boards without a local crystal
> it is fed from the SoC, described as a clock on the PHY node. Get and
> enable it in probe so the PHY is clocked before its registers are
> accessed. The clock is optional, so crystal-clocked boards are
> unaffected.
> 
> Signed-off-by: Jiaxing Hu <gahing@gahingwoo.com>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* Re: unix_stream_connect and socket address resolution
From: John Ericson @ 2026-07-19 15:37 UTC (permalink / raw)
  To: David Laight
  Cc: Kuniyuki Iwashima, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Cong Wang, Simon Horman, Christian Brauner,
	David Rheinsberg, Andy Lutomirski, Sergei Zimmerman, network dev,
	Mickaël Salaün, Günther Noack, Paul Moore,
	linux-security-module, LKML
In-Reply-To: <20260718215855.07284fb1@pumpkin>

Hi David,

On Sat, Jul 18, 2026, at 4:58 PM, David Laight wrote:
> My $0.02

Thanks for weighing in here.

> If you assume that the client isn't responsible for restarting the server,
> then there is no strong timing relation between creating a new server
> (by any means) and the connect request from the client.
> In other words both the above are very similar to the client being
> preempted at the start of the connect() system call.
> 
> What you need to do is hard link foo to foo1, create the new
> socket at foo2/bar then mv foo2 to foo so that it is atomic.
> But I suspect hard links to directories aren't allowed any more :-(
> (Creating 'random' hard links to directories used to be 'fun',
> you could get 'find' in a right mess.)
> 
> David

I think I am a little confused by your answer. I am not trying to do
anything in particular in userland relating to dying and restarting
servers. Rather, I am wondering why it was decided (long ago, pre the
current repo's git history) for connect to re-resolve the path every
loop iteration.

I am working on a series of related af_unix refactors, and it would
simplify things a lot if I could make `unix_stream_connect` just resolve
the path once before the loop, but I do not know if that is an
acceptable change in behavior.

I was justifying the change in terms of the resolve-once behavior being
less surprising in my original email, since that reason stands on its
own, with or without my other planned work, but the truth is both that
and the ease of refactoring with that change are my motivations.

Hope that clarifies things,

John

^ permalink raw reply

* Re: [PATCH net] rds: tcp: unregister sysctl before tearing down listen socket
From: Cen Zhang (Microsoft) @ 2026-07-19 15:48 UTC (permalink / raw)
  To: achender
  Cc: AutonomousCodeSecurity, blbllhy, davem, edumazet, horms, kuba,
	kys, linux-kernel, linux-rdma, netdev, pabeni, rds-devel,
	tgopinath
In-Reply-To: <259284aa1280d387c413cc34fa5e4b11ad28379d.camel@kernel.org>

Thanks. The KASAN stack was observed on x86_64 QEMU/KASAN.

The full KASAN report and C reproducer are a few hundred lines. Would you
prefer that I include them after the --- line in v2, or reply to this
thread with them separately and keep v2 concise?

I'll prepare v2 after confirming the preferred format.

^ permalink raw reply

* Re: [PATCH net-next] net: sfp: add quirk for HORACO copper SFP+ module
From: Andrew Lunn @ 2026-07-19 15:49 UTC (permalink / raw)
  To: Aleksander Jan Bajkowski
  Cc: linux, hkallweit1, davem, edumazet, kuba, pabeni, netdev,
	linux-kernel
In-Reply-To: <20260719100158.874882-1-olek2@wp.pl>

On Sun, Jul 19, 2026 at 12:01:55PM +0200, Aleksander Jan Bajkowski wrote:
> Add quirk for a copper SFP+ module that identifies itself as "OEM"
> "HC-10GE-113C". It uses RollBall protocol to talk to the PHY.
> 
> Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew

^ permalink raw reply

* Re: [PATCH ethtool-next v3 1/3] sfpid: print all implemented options
From: Andrew Lunn @ 2026-07-19 15:54 UTC (permalink / raw)
  To: Aleksander Jan Bajkowski
  Cc: danieller, mkubecek, davem, edumazet, kuba, pabeni, jbe, netdev
In-Reply-To: <20260719090458.659332-1-olek2@wp.pl>

On Sun, Jul 19, 2026 at 11:00:35AM +0200, Aleksander Jan Bajkowski wrote:
> SFP modules implement multiple options. Before the “json” option was
> introduced, all options were listed.

Hi Aleksander

This is a common theme here, the json option. Are the three patches
for things you noticed for devices you have, or have you analysed
those json patches and think you have found all the places it broke?

Thanks
	Andrew

^ permalink raw reply

* Re: [PATCH net-next] net: stmmac: Simplify ioctl handling
From: Andrew Lunn @ 2026-07-19 16:13 UTC (permalink / raw)
  To: Maxime Chevallier
  Cc: Andrew Lunn, Jakub Kicinski, davem, Eric Dumazet, Paolo Abeni,
	Simon Horman, Maxime Coquelin, Alexandre Torgue, Russell King,
	thomas.petazzoni, Alexis Lothoré, netdev, linux-kernel,
	linux-arm-kernel, linux-stm32
In-Reply-To: <20260718143848.677531-1-maxime.chevallier@bootlin.com>

> Looking at this, I'm wondering if we can't just get rid of SIOCSHWTSTAMP
> handling in phy_mii_ioctl(). Looks like we can ?

I'm not sure about that. We need Richards input.

The code in phy_mii_ioctl() allows the MAC to be bypassed, it goes
straight to a PHY based stamper. It could be the MAC has no idea the
PHY has this capability, so it has not implemented the .ndo?

It might be we need to hoist the code from phy_mii_ioctl() into
dev_{sg}et_hwtstamp()?

	Andrew

^ permalink raw reply

* [PATCH] bpf, sockmap: Fix cork use-after-free in tcp_bpf_sendmsg()
From: Chengfeng Ye @ 2026-07-19 16:16 UTC (permalink / raw)
  To: Eric Dumazet, Neal Cardwell, Kuniyuki Iwashima, John Fastabend,
	Jakub Sitnicki, Jiayuan Chen, David S. Miller, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Alexei Starovoitov, Daniel Borkmann,
	open list:BPF [L7 FRAMEWORK] (sockmap)
  Cc: netdev, linux-kernel, Chengfeng Ye, stable

tcp_bpf_sendmsg() keeps msg_tx across sk_stream_wait_memory(), which
drops and reacquires the socket lock.  Its error path tries to decide
whether msg_tx names the local temporary message by comparing it with
the current value of psock->cork.

This comparison is unsafe when two threads send on the same socket:

  Thread A                         Thread B
  msg_tx = psock->cork
  sk_msg_alloc() fails
  sk_stream_wait_memory()
    releases the socket lock      acquires the socket lock
                                  completes the cork
                                  psock->cork = NULL
                                  frees the cork
    reacquires the socket lock
  msg_tx != psock->cork
  sk_msg_free(msg_tx)

The stale cork is therefore mistaken for the local temporary message
and freed again.  KASAN reported:

  BUG: KASAN: slab-use-after-free in sk_msg_free+0x49/0x50
  Read of size 4 at addr ffff88810c908800 by task poc/90
  Call Trace:
   sk_msg_free+0x49/0x50
   tcp_bpf_sendmsg+0x14f5/0x1cc0
   __sys_sendto+0x32c/0x3a0
   __x64_sys_sendto+0xdb/0x1b0
  Allocated by task 89:
   __kasan_kmalloc+0x8f/0xa0
   tcp_bpf_sendmsg+0x16b3/0x1cc0
  Freed by task 91:
   __kasan_slab_free+0x43/0x70
   kfree+0x131/0x3c0
   tcp_bpf_sendmsg+0xec3/0x1cc0

msg_tx can only name the stack-local tmp or the shared cork.  Test for
tmp directly so a changed psock->cork cannot turn a shared message into
an apparent local one.

Fixes: 604326b41a6f ("bpf, sockmap: convert to generic sk_msg interface")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
---
 net/ipv4/tcp_bpf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
index 8e905b50dead..a30475afb6f8 100644
--- a/net/ipv4/tcp_bpf.c
+++ b/net/ipv4/tcp_bpf.c
@@ -604,7 +604,7 @@ static int tcp_bpf_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
 wait_for_memory:
 		err = sk_stream_wait_memory(sk, &timeo);
 		if (err) {
-			if (msg_tx && msg_tx != psock->cork)
+			if (msg_tx == &tmp)
 				sk_msg_free(sk, msg_tx);
 			goto out_err;
 		}
-- 
2.43.0


^ permalink raw reply related

* Re: [RFC PATCH net-next v0.1 0/1] add GeoNetworking protocol
From: Andrew Lunn @ 2026-07-19 16:21 UTC (permalink / raw)
  To: Simon Dietz
  Cc: netdev, andrew+netdev, davem, edumazet, johannes, kuniyu,
	linux-wireless, dietz23838
In-Reply-To: <20260718210046.2357882-1-simon.dietz@plantwatch.de>

On Sat, Jul 18, 2026 at 11:00:32PM +0200, Simon Dietz wrote:
> Implement the GeoNetworking / ETSI ITS-G5 ('net/gn') protocol which
> is based on 802.11p wifi and used for vehicle2x applications. It is
> standardized by the ETSI and used by some car manufacturers
> (especially in europe). It enables ad-hoc, multi-hop geographical
> communication and routing among vehicles (and road- or railside
> infrastructure).
> 
> Most work of this implementation has been done by the bachelor
> project 2018/2019 of the operating systems and middleware group of
> the Hasso Plattner Institute, University of Potsdam, which the author
> was part of.

Hi Simon

Is there are architecture documentation somewhere?

One of my comments was about routing tables. Should there be a user
space component determining the routes, and the kernel just has a
static routing table? That would be typical for IP.

There also seems to be a need for location information. How does that
get into the kernel? Is there a daemon for that? Patches to gpsd?

    Andrew

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox