From: Loic Gelle <loic.gelle@polymtl.ca>
Date: Thu, 12 Dec 2017 12:37:36 -0700
Subject: [PATCH] cgroups: add write tracepoints

diff --git a/include/trace/events/cgroup.h b/include/trace/events/cgroup.h
index d74722c2ac8b..d679fe1c28ea 100644
--- a/include/trace/events/cgroup.h
+++ b/include/trace/events/cgroup.h
@@ -150,6 +150,123 @@ DEFINE_EVENT(cgroup_migrate, cgroup_transfer_tasks,
 	TP_ARGS(dst_cgrp, task, threadgroup)
 );
 
+TRACE_EVENT(cgroup_file_write_fail,
+
+	TP_PROTO(struct cgroup *cgrp, struct cftype *cft, int ret),
+
+	TP_ARGS(cgrp, cft, ret),
+
+	TP_STRUCT__entry(
+		__field(	int,		root			)
+		__field(	int,		id				)
+		__string(	ss_name,	cft->ss->name	)
+		__string(	name,		cft->name		)
+		__field(	int,		ret				)
+	),
+
+	TP_fast_assign(
+		__entry->root = cgrp->root->hierarchy_id;
+		__entry->id = cgrp->id;
+		__assign_str(ss_name, cft->ss->name);
+		__assign_str(name, cft->name);
+		__entry->ret = ret;
+	),
+
+	TP_printk("root=%d id=%d ss_name=%s name=%s ret=%d",
+		  __entry->root, __entry->id, __get_str(ss_name),
+		  __get_str(name), __entry->ret)
+);
+
+TRACE_EVENT(cgroup_file_write_u64,
+
+	TP_PROTO(struct cgroup *cgrp, struct cftype *cft,
+		u64 val, int ret),
+
+	TP_ARGS(cgrp, cft, val, ret),
+
+	TP_STRUCT__entry(
+		__field(	int,		root			)
+		__field(	int,		id				)
+		__string(	ss_name,	cft->ss->name	)
+		__string(	name,		cft->name		)
+		__field(	u64,		val				)
+		__field(	int,		ret				)
+	),
+
+	TP_fast_assign(
+		__entry->root = cgrp->root->hierarchy_id;
+		__entry->id = cgrp->id;
+		__assign_str(ss_name, cft->ss->name);
+		__assign_str(name, cft->name);
+		__entry->val = val;
+		__entry->ret = ret;
+	),
+
+	TP_printk("root=%d id=%d ss_name=%s name=%s val=%lld ret=%d",
+		  __entry->root, __entry->id, __get_str(ss_name),
+		  __get_str(name), __entry->val, __entry->ret)
+);
+
+TRACE_EVENT(cgroup_file_write_s64,
+
+	TP_PROTO(struct cgroup *cgrp, struct cftype *cft,
+		s64 val, int ret),
+
+	TP_ARGS(cgrp, cft, val, ret),
+
+	TP_STRUCT__entry(
+		__field(	int,		root			)
+		__field(	int,		id				)
+		__string(	ss_name,	cft->ss->name	)
+		__string(	name,		cft->name		)
+		__field(	s64,		val				)
+		__field(	int,		ret				)
+	),
+
+	TP_fast_assign(
+		__entry->root = cgrp->root->hierarchy_id;
+		__entry->id = cgrp->id;
+		__assign_str(ss_name, cft->ss->name);
+		__assign_str(name, cft->name);
+		__entry->val = val;
+		__entry->ret = ret;
+	),
+
+	TP_printk("root=%d id=%d ss_name=%s name=%s val=%lld ret=%d",
+		  __entry->root, __entry->id, __get_str(ss_name),
+		  __get_str(name), __entry->val, __entry->ret)
+);
+
+TRACE_EVENT(cgroup_file_write_str,
+
+	TP_PROTO(struct cgroup *cgrp, struct cftype *cft,
+		char *buf, int ret),
+
+	TP_ARGS(cgrp, cft, buf, ret),
+
+	TP_STRUCT__entry(
+		__field(	int,		root			)
+		__field(	int,		id				)
+		__string(	ss_name,	cft->ss->name	)
+		__string(	name,		cft->name		)
+		__string(	str,		buf		)
+		__field(	int,		ret				)
+	),
+
+	TP_fast_assign(
+		__entry->root = cgrp->root->hierarchy_id;
+		__entry->id = cgrp->id;
+		__assign_str(ss_name, cft->ss->name);
+		__assign_str(name, cft->name);
+		__assign_str(str, buf);
+		__entry->ret = ret;
+	),
+
+	TP_printk("root=%d id=%d ss_name=%s name=%s str=%s ret=%d",
+		  __entry->root, __entry->id, __get_str(ss_name),
+		  __get_str(name), __get_str(str), __entry->ret)
+);
+
 #endif /* _TRACE_CGROUP_H */
 
 /* This part must be outside protection */
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 0b1ffe147f24..f2f4b3af74bb 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -3412,11 +3412,20 @@ static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf,
 	 */
 	if ((cgrp->root->flags & CGRP_ROOT_NS_DELEGATE) &&
 	    !(cft->flags & CFTYPE_NS_DELEGATABLE) &&
-	    ns != &init_cgroup_ns && ns->root_cset->dfl_cgrp == cgrp)
-		return -EPERM;
+	    ns != &init_cgroup_ns && ns->root_cset->dfl_cgrp == cgrp) {
+		ret = -EPERM;
+		trace_cgroup_file_write_fail(cgrp, cft, ret);
+		return ret;
+	}
 
-	if (cft->write)
-		return cft->write(of, buf, nbytes, off);
+	if (cft->write) {
+		ret = cft->write(of, buf, nbytes, off);
+		if (ret)
+			trace_cgroup_file_write_fail(cgrp, cft, ret);
+		else
+			trace_cgroup_file_write_str(cgrp, cft, buf, ret);
+		return ret;
+	}
 
 	/*
 	 * kernfs guarantees that a file isn't deleted with operations in
@@ -3431,15 +3440,24 @@ static ssize_t cgroup_file_write(struct kernfs_open_file *of, char *buf,
 	if (cft->write_u64) {
 		unsigned long long v;
 		ret = kstrtoull(buf, 0, &v);
-		if (!ret)
+		if (!ret) {
 			ret = cft->write_u64(css, cft, v);
+			trace_cgroup_file_write_u64(cgrp, cft, v, ret);
+		}
+		else
+			trace_cgroup_file_write_fail(cgrp, cft, ret);
 	} else if (cft->write_s64) {
 		long long v;
 		ret = kstrtoll(buf, 0, &v);
-		if (!ret)
+		if (!ret) {
 			ret = cft->write_s64(css, cft, v);
+			trace_cgroup_file_write_s64(cgrp, cft, v, ret);
+		}
+		else
+			trace_cgroup_file_write_fail(cgrp, cft, ret);
 	} else {
 		ret = -EINVAL;
+		trace_cgroup_file_write_fail(cgrp, cft, ret);
 	}
 
 	return ret ?: nbytes;

