On Mon, 2025-08-04 at 10:20 +0800, Xu Kuohai wrote:
[...]
@@ -278,6 +293,92 @@ static int64_t ringbuf_process_ring(struct ring *r, size_t n) return cnt; } +static int64_t ringbuf_process_overwrite_ring(struct ring *r, size_t n) +{
- int err;
- uint32_t *len_ptr, len;
- /* 64-bit to avoid overflow in case of extreme application behavior */
- int64_t cnt = 0;
- size_t size, offset;
- unsigned long cons_pos, prod_pos, over_pos, tmp_pos;
- bool got_new_data;
- void *sample;
- bool copied;
- size = r->mask + 1;
- cons_pos = smp_load_acquire(r->consumer_pos);
- do {
got_new_data = false;/* grab a copy of data */prod_pos = smp_load_acquire(r->producer_pos);do {over_pos = READ_ONCE(*r->overwrite_pos);/* prod_pos may be outdated now */if (over_pos < prod_pos) {tmp_pos = max(cons_pos, over_pos);/* smp_load_acquire(r->producer_pos) before* READ_ONCE(*r->overwrite_pos) ensures that* over_pos + r->mask < prod_pos never occurs,* so size is never larger than r->mask*/size = prod_pos - tmp_pos;if (!size)goto done;memcpy(r->read_buffer,r->data + (tmp_pos & r->mask), size);copied = true;} else {copied = false;}prod_pos = smp_load_acquire(r->producer_pos);/* retry if data is overwritten by producer */} while (!copied || prod_pos - tmp_pos > r->mask);
Could you please elaborate a bit, why this condition is sufficient to guarantee that r->overwrite_pos had not changed while memcpy() was executing?
cons_pos = tmp_pos;for (offset = 0; offset < size; offset += roundup_len(len)) {len_ptr = r->read_buffer + (offset & r->mask);len = *len_ptr;if (len & BPF_RINGBUF_BUSY_BIT)goto done;got_new_data = true;cons_pos += roundup_len(len);if ((len & BPF_RINGBUF_DISCARD_BIT) == 0) {sample = (void *)len_ptr + BPF_RINGBUF_HDR_SZ;err = r->sample_cb(r->ctx, sample, len);if (err < 0) {/* update consumer pos and bail out */smp_store_release(r->consumer_pos,cons_pos);return err;}cnt++;}if (cnt >= n)goto done;}- } while (got_new_data);
+done:
- smp_store_release(r->consumer_pos, cons_pos);
- return cnt;
+}
[...]