[PATCH RFC 1/2] rlimits: add infra to report violations

From: Yauheni Kaliuta
Date: Wed Sep 07 2016 - 06:27:28 EST


The patch defines tracepoints for resource limits (rlimits) violations
reporting and adds a thin layer to be called from rlimits aware code
without direct dependency of the tracepoints.

Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@xxxxxxxxxx>
---
include/linux/resource.h | 5 +++
kernel/Makefile | 4 +-
kernel/rlimit.c | 26 +++++++++++
kernel/trace-rlimit.h | 112 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 146 insertions(+), 1 deletion(-)
create mode 100644 kernel/rlimit.c
create mode 100644 kernel/trace-rlimit.h

diff --git a/include/linux/resource.h b/include/linux/resource.h
index 5bc3116e649c..f4de2827e647 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -9,5 +9,10 @@ struct task_struct;
int getrusage(struct task_struct *p, int who, struct rusage __user *ru);
int do_prlimit(struct task_struct *tsk, unsigned int resource,
struct rlimit *new_rlim, struct rlimit *old_rlim);
+void rlimit_exceeded_task(int rlimit_id, u64 req, struct task_struct *task);
+void rlimit_exceeded(int rlimit_id, u64 req);
+void rlimit_hard_exceeded_task(int rlimit_id, u64 req,
+ struct task_struct *task);
+void rlimit_hard_exceeded(int rlimit_id, u64 req);

#endif
diff --git a/kernel/Makefile b/kernel/Makefile
index e2ec54e2b952..30999d83a261 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@ obj-y = fork.o exec_domain.o panic.o \
extable.o params.o \
kthread.o sys_ni.o nsproxy.o \
notifier.o ksysfs.o cred.o reboot.o \
- async.o range.o smpboot.o
+ async.o range.o smpboot.o rlimit.o

obj-$(CONFIG_MULTIUSER) += groups.o

@@ -18,6 +18,8 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_irq_work.o = $(CC_FLAGS_FTRACE)
endif

+CFLAGS_rlimit.o := -I$(src)
+
# Prevents flicker of uninteresting __do_softirq()/__local_bh_disable_ip()
# in coverage traces.
KCOV_INSTRUMENT_softirq.o := n
diff --git a/kernel/rlimit.c b/kernel/rlimit.c
new file mode 100644
index 000000000000..0b42ebc3a9d5
--- /dev/null
+++ b/kernel/rlimit.c
@@ -0,0 +1,26 @@
+
+#include <linux/resource.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace-rlimit.h"
+
+void rlimit_exceeded_task(int rlimit_id, u64 req, struct task_struct *task)
+{
+ trace_rlimit_exceeded(rlimit_id, task_rlimit(task, rlimit_id), req,
+ task_pid_nr(task), task->comm);
+}
+
+void rlimit_exceeded(int rlimit_id, u64 req)
+{
+ rlimit_exceeded_task(rlimit_id, req, current);
+}
+
+void rlimit_hard_exceeded_task(int rlimit_id, u64 req, struct task_struct *task)
+{
+ trace_rlimit_hard_exceeded(rlimit_id, task_rlimit_max(task, rlimit_id),
+ req, task_pid_nr(task), task->comm);
+}
+void rlimit_hard_exceeded(int rlimit_id, u64 req)
+{
+ rlimit_hard_exceeded_task(rlimit_id, req, current);
+}
diff --git a/kernel/trace-rlimit.h b/kernel/trace-rlimit.h
new file mode 100644
index 000000000000..e7433ae8a09e
--- /dev/null
+++ b/kernel/trace-rlimit.h
@@ -0,0 +1,112 @@
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM rlimit
+
+#if !defined(_TRACE_RLIMIT_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_RLIMIT_H
+#include <linux/tracepoint.h>
+
+TRACE_DEFINE_ENUM(RLIMIT_CPU);
+TRACE_DEFINE_ENUM(RLIMIT_FSIZE);
+TRACE_DEFINE_ENUM(RLIMIT_DATA);
+TRACE_DEFINE_ENUM(RLIMIT_STACK);
+TRACE_DEFINE_ENUM(RLIMIT_CORE);
+TRACE_DEFINE_ENUM(RLIMIT_RSS);
+TRACE_DEFINE_ENUM(RLIMIT_NPROC);
+TRACE_DEFINE_ENUM(RLIMIT_NOFILE);
+TRACE_DEFINE_ENUM(RLIMIT_MEMLOCK);
+TRACE_DEFINE_ENUM(RLIMIT_AS);
+TRACE_DEFINE_ENUM(RLIMIT_LOCKS);
+TRACE_DEFINE_ENUM(RLIMIT_SIGPENDING);
+TRACE_DEFINE_ENUM(RLIMIT_MSGQUEUE);
+TRACE_DEFINE_ENUM(RLIMIT_NICE);
+TRACE_DEFINE_ENUM(RLIMIT_RTPRIO);
+TRACE_DEFINE_ENUM(RLIMIT_RTTIME);
+
+
+#define __print_rlimit_name(id_var) \
+ __print_symbolic(id_var, \
+ { RLIMIT_CPU, "CPU" }, \
+ { RLIMIT_FSIZE, "FSIZE" }, \
+ { RLIMIT_DATA, "DATA" }, \
+ { RLIMIT_STACK, "STACK" }, \
+ { RLIMIT_CORE, "CORE" }, \
+ { RLIMIT_RSS, "RSS" }, \
+ { RLIMIT_NPROC, "NPROC" }, \
+ { RLIMIT_NOFILE, "NOFILE" }, \
+ { RLIMIT_MEMLOCK, "MEMLOCK" }, \
+ { RLIMIT_AS, "AS" }, \
+ { RLIMIT_LOCKS, "LOCKS" }, \
+ { RLIMIT_SIGPENDING, "SIGPENDING" }, \
+ { RLIMIT_MSGQUEUE, "MSGQUEUE" }, \
+ { RLIMIT_NICE, "NICE" }, \
+ { RLIMIT_RTPRIO, "RTPRIO" }, \
+ { RLIMIT_RTTIME, "RTTIME" })
+
+DECLARE_EVENT_CLASS(rlimit_exceeded_template,
+
+ TP_PROTO(int rlimit_id,
+ unsigned long long cur,
+ unsigned long long req,
+ pid_t pid,
+ char *comm),
+
+ TP_ARGS(rlimit_id, cur, req, pid, comm),
+
+ TP_STRUCT__entry(
+ __field(int, rlimit_id)
+ __field(unsigned long long, cur)
+ __field(unsigned long long, req)
+ __field(pid_t, pid)
+ __string(comm, comm)
+ ),
+ TP_fast_assign(
+ __entry->rlimit_id = rlimit_id;
+ __entry->cur = cur;
+ __entry->req = req;
+ __entry->pid = pid;
+ __assign_str(comm, comm);
+ ),
+ TP_printk("RLIMIT %s violation [%s:%d]. Limit %llu, requested %s",
+ __print_rlimit_name(__entry->rlimit_id),
+ __get_str(comm),
+ __entry->pid,
+ __entry->cur,
+ __print_symbolic(__entry->req,
+ {(unsigned long long)-1, "Unknown"}))
+ );
+
+DEFINE_EVENT(rlimit_exceeded_template, rlimit_exceeded,
+ TP_PROTO(int rlimit_id,
+ unsigned long long cur,
+ unsigned long long req,
+ pid_t pid,
+ char *comm),
+
+ TP_ARGS(rlimit_id, cur, req, pid, comm)
+ );
+
+DEFINE_EVENT_PRINT(rlimit_exceeded_template, rlimit_hard_exceeded,
+ TP_PROTO(int rlimit_id,
+ unsigned long long cur,
+ unsigned long long req,
+ pid_t pid,
+ char *comm),
+
+ TP_ARGS(rlimit_id, cur, req, pid, comm),
+
+ TP_printk("Hard RLIMIT %s violation [%s:%d]. Limit %llu, requested %s",
+ __print_rlimit_name(__entry->rlimit_id),
+ __get_str(comm),
+ __entry->pid,
+ __entry->cur,
+ __print_symbolic(__entry->req,
+ {(unsigned long long)-1, "Unknown"}))
+ );
+
+#endif /* _TRACE_RLIMIT_H */
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace-rlimit
+#include <trace/define_trace.h>
--
2.7.4