]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
relayfs: support a counter tracking if per-cpu buffers is full
authorJason Xing <kernelxing@tencent.com>
Thu, 12 Jun 2025 06:11:58 +0000 (14:11 +0800)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 10 Jul 2025 05:57:51 +0000 (22:57 -0700)
When using relay mechanism, we often encounter the case where new data are
lost or old unconsumed data are overwritten because of slow reader.

Add 'full' field in per-cpu buffer structure to detect if the above case
is happening.  Relay has two modes: 1) non-overwrite mode, 2) overwrite
mode.  So buffer being full here respectively means: 1) relayfs doesn't
intend to accept new data and then simply drop them, or 2) relayfs is
going to start over again and overwrite old unread data with new data.

Note: this counter doesn't need any explicit lock to protect from being
modified by different threads for the better performance consideration.
Writers calling __relay_write/relay_write should consider how to use the
lock and ensure it performs under the lock protection, thus it's not
necessary to add a new small lock here.

Link: https://lkml.kernel.org/r/20250612061201.34272-3-kerneljasonxing@gmail.com
Signed-off-by: Jason Xing <kernelxing@tencent.com>
Reviewed-by: Yushan Zhou <katrinzhou@tencent.com>
Reviewed-by: Jens Axboe <axboe@kernel.dk>
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/relay.h
kernel/relay.c

index e10a0fdf4325157d88d0a04df185d374527b14f6..cd77eb285a4807a3abec1787cff0e8f476037bd8 100644 (file)
  */
 #define RELAYFS_CHANNEL_VERSION                7
 
+/*
+ * Relay buffer statistics
+ */
+struct rchan_buf_stats
+{
+       unsigned int full_count;        /* counter for buffer full */
+};
+
 /*
  * Per-cpu relay channel buffer
  */
@@ -43,6 +51,7 @@ struct rchan_buf
        struct irq_work wakeup_work;    /* reader wakeup */
        struct dentry *dentry;          /* channel file dentry */
        struct kref kref;               /* channel buffer refcount */
+       struct rchan_buf_stats stats;   /* buffer stats */
        struct page **page_array;       /* array of current buffer pages */
        unsigned int page_count;        /* number of current buffer pages */
        unsigned int finalized;         /* buffer has been finalized */
index fc6ad76b789da4cdfa77a2ae69a2e9976558b281..4b07efddc2cfe073b28957de0d44eedcb29d930f 100644 (file)
@@ -251,8 +251,13 @@ EXPORT_SYMBOL_GPL(relay_buf_full);
 static int relay_subbuf_start(struct rchan_buf *buf, void *subbuf,
                              void *prev_subbuf)
 {
+       int full = relay_buf_full(buf);
+
+       if (full)
+               buf->stats.full_count++;
+
        if (!buf->chan->cb->subbuf_start)
-               return !relay_buf_full(buf);
+               return !full;
 
        return buf->chan->cb->subbuf_start(buf, subbuf,
                                           prev_subbuf);
@@ -297,6 +302,7 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init)
        buf->finalized = 0;
        buf->data = buf->start;
        buf->offset = 0;
+       buf->stats.full_count = 0;
 
        for (i = 0; i < buf->chan->n_subbufs; i++)
                buf->padding[i] = 0;