Thread (69 messages) 69 messages, 3 authors, 2026-02-16
STALE146d

[PATCH net-next v7 2/9] ptr_ring: add helper to detect newly freed space on consume

From: Simon Schippers <hidden>
Date: 2026-01-12 16:30:01
Also in: kvm, lkml, virtualization

On 1/9/26 10:06, Simon Schippers wrote:
On 1/9/26 09:31, Michael S. Tsirkin wrote:
quoted
On Fri, Jan 09, 2026 at 08:35:31AM +0100, Simon Schippers wrote:
quoted
On 1/9/26 08:22, Michael S. Tsirkin wrote:
quoted
On Wed, Jan 07, 2026 at 10:04:41PM +0100, Simon Schippers wrote:
quoted
This proposed function checks whether __ptr_ring_zero_tail() was invoked
within the last n calls to __ptr_ring_consume(), which indicates that new
free space was created. Since __ptr_ring_zero_tail() moves the tail to
the head - and no other function modifies either the head or the tail,
aside from the wrap-around case described below - detecting such a
movement is sufficient to detect the invocation of
__ptr_ring_zero_tail().

The implementation detects this movement by checking whether the tail is
at most n positions behind the head. If this condition holds, the shift
of the tail to its current position must have occurred within the last n
calls to __ptr_ring_consume(), indicating that __ptr_ring_zero_tail() was
invoked and that new free space was created.

This logic also correctly handles the wrap-around case in which
__ptr_ring_zero_tail() is invoked and the head and the tail are reset
to 0. Since this reset likewise moves the tail to the head, the same
detection logic applies.

Co-developed-by: Tim Gebauer <redacted>
Signed-off-by: Tim Gebauer <redacted>
Signed-off-by: Simon Schippers <redacted>
---
 include/linux/ptr_ring.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)
diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h
index a5a3fa4916d3..7cdae6d1d400 100644
--- a/include/linux/ptr_ring.h
+++ b/include/linux/ptr_ring.h
@@ -438,6 +438,19 @@ static inline int ptr_ring_consume_batched_bh(struct ptr_ring *r,
 	return ret;
 }
 
+/* Returns true if the consume of the last n elements has created space
+ * in the ring buffer (i.e., a new element can be produced).
+ *
+ * Note: Because of batching, a successful call to __ptr_ring_consume() /
+ * __ptr_ring_consume_batched() does not guarantee that the next call to
+ * __ptr_ring_produce() will succeed.

I think the issue is it does not say what is the actual guarantee.

Another issue is that the "Note" really should be more prominent,
it really is part of explaining what the functions does.

Hmm. Maybe we should tell it how many entries have been consumed and
get back an indication of how much space this created?

fundamentally
	 n - (r->consumer_head - r->consumer_tail)?
No, that is wrong from my POV.

It always creates the same amount of space which is the batch size or
multiple batch sizes (or something less in the wrap-around case). That is
of course only if __ptr_ring_zero_tail() was executed at least once,
else it creates zero space.
exactly, and caller does not know, and now he wants to know so
we add an API for him to find out?

I feel the fact it's a binary (batch or 0) is an implementation
detail better hidden from user.
I agree, and I now understood your logic :)

So it should be:

static inline int __ptr_ring_consume_created_space(struct ptr_ring *r,
						   int n)
{
	return max(n - (r->consumer_head - r->consumer_tail), 0);
}

Right?
BTW:

No, that's still not correct. It misses the elements between the tail and
head that existed before the consume operation (called pre_consume_gap in
the code below).

After thinking about it a bit more, the best solution I came up with is:

static inline int __ptr_ring_consume_created_space(struct ptr_ring *r,
						   int n)
{
	int pre_consume_gap = (r->head - n) % r->size % r->batch;
	return n - (r->head - r->tail) + pre_consume_gap;
}

Here, (r->head - n) represents the head position before the consume, but
it may be negative. The first modulo normalizes it to a positive value in
the range [0, size). Applying the modulo batch to the pre-consume head
position then yields the number of elements that were between the tail
and head before the consume.

With this approach, we no longer need max(..., 0), because if
n < (r->head - r->tail), the + pre_consume_gap term cancels it out.


Is this solution viable in terms of performance regarding the modulo
operations?
quoted

quoted
quoted

does the below sound good maybe?

/* Returns the amound of space (number of new elements that can be
 * produced) that calls to ptr_ring_consume created.
 *
 * Getting n entries from calls to ptr_ring_consume() /
 * ptr_ring_consume_batched() does *not* guarantee that the next n calls to
 * ptr_ring_produce() will succeed.
 *
 * Use this function after consuming n entries to get a hint about
 * how much space was actually created.




quoted
+ */
+static inline bool __ptr_ring_consume_created_space(struct ptr_ring *r,
+						    int n)
+{
+	return r->consumer_head - r->consumer_tail < n;
+}
+
 /* Cast to structure type and call a function without discarding from FIFO.
  * Function must return a value.
  * Callers must take consumer_lock.
-- 
2.43.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help