| From: Jason Xing <kernelxing@tencent.com> |
| Subject: relayfs: support a counter tracking if data is too big to write |
| Date: Thu, 12 Jun 2025 14:12:01 +0800 |
| |
| It really doesn't matter if the user/admin knows what the last too big |
| value is. Record how many times this case is triggered would be helpful. |
| |
| Solve the existing issue where relay_reset() doesn't restore the value. |
| |
| Store the counter in the per-cpu buffer structure instead of the global |
| buffer structure. It also solves the racy condition which is likely to |
| happen when a few of per-cpu buffers encounter the too big data case and |
| then access the global field last_toobig without lock protection. |
| |
| Remove the printk in relay_close() since kernel module can directly call |
| relay_stats() as they want. |
| |
| Link: https://lkml.kernel.org/r/20250612061201.34272-6-kerneljasonxing@gmail.com |
| Signed-off-by: Jason Xing <kernelxing@tencent.com> |
| Reviewed-by: Yushan Zhou <katrinzhou@tencent.com> |
| Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> |
| Cc: Jens Axboe <axboe@kernel.dk> |
| 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 | 5 +++-- |
| kernel/relay.c | 18 ++++++++++-------- |
| 2 files changed, 13 insertions(+), 10 deletions(-) |
| |
| --- a/include/linux/relay.h~relayfs-support-a-counter-tracking-if-data-is-too-big-to-write |
| +++ a/include/linux/relay.h |
| @@ -33,13 +33,15 @@ |
| */ |
| enum { |
| RELAY_STATS_BUF_FULL = (1 << 0), |
| + RELAY_STATS_WRT_BIG = (1 << 1), |
| |
| - RELAY_STATS_LAST = RELAY_STATS_BUF_FULL, |
| + RELAY_STATS_LAST = RELAY_STATS_WRT_BIG, |
| }; |
| |
| struct rchan_buf_stats |
| { |
| unsigned int full_count; /* counter for buffer full */ |
| + unsigned int big_count; /* counter for too big to write */ |
| }; |
| |
| /* |
| @@ -79,7 +81,6 @@ struct rchan |
| const struct rchan_callbacks *cb; /* client callbacks */ |
| struct kref kref; /* channel refcount */ |
| void *private_data; /* for user-defined data */ |
| - size_t last_toobig; /* tried to log event > subbuf size */ |
| struct rchan_buf * __percpu *buf; /* per-cpu channel buffers */ |
| int is_global; /* One global buffer ? */ |
| struct list_head list; /* for channel list */ |
| --- a/kernel/relay.c~relayfs-support-a-counter-tracking-if-data-is-too-big-to-write |
| +++ a/kernel/relay.c |
| @@ -303,6 +303,7 @@ static void __relay_reset(struct rchan_b |
| buf->data = buf->start; |
| buf->offset = 0; |
| buf->stats.full_count = 0; |
| + buf->stats.big_count = 0; |
| |
| for (i = 0; i < buf->chan->n_subbufs; i++) |
| buf->padding[i] = 0; |
| @@ -602,7 +603,7 @@ size_t relay_switch_subbuf(struct rchan_ |
| return length; |
| |
| toobig: |
| - buf->chan->last_toobig = length; |
| + buf->stats.big_count++; |
| return 0; |
| } |
| EXPORT_SYMBOL_GPL(relay_switch_subbuf); |
| @@ -662,11 +663,6 @@ void relay_close(struct rchan *chan) |
| if ((buf = *per_cpu_ptr(chan->buf, i))) |
| relay_close_buf(buf); |
| |
| - if (chan->last_toobig) |
| - printk(KERN_WARNING "relay: one or more items not logged " |
| - "[item size (%zd) > sub-buffer size (%zd)]\n", |
| - chan->last_toobig, chan->subbuf_size); |
| - |
| list_del(&chan->list); |
| kref_put(&chan->kref, relay_destroy_channel); |
| mutex_unlock(&relay_channels_mutex); |
| @@ -719,11 +715,17 @@ size_t relay_stats(struct rchan *chan, i |
| rbuf = *per_cpu_ptr(chan->buf, 0); |
| if (flags & RELAY_STATS_BUF_FULL) |
| count = rbuf->stats.full_count; |
| + else if (flags & RELAY_STATS_WRT_BIG) |
| + count = rbuf->stats.big_count; |
| } else { |
| for_each_online_cpu(i) { |
| rbuf = *per_cpu_ptr(chan->buf, i); |
| - if (rbuf && flags & RELAY_STATS_BUF_FULL) |
| - count += rbuf->stats.full_count; |
| + if (rbuf) { |
| + if (flags & RELAY_STATS_BUF_FULL) |
| + count += rbuf->stats.full_count; |
| + else if (flags & RELAY_STATS_WRT_BIG) |
| + count += rbuf->stats.big_count; |
| + } |
| } |
| } |
| |
| _ |