diff mbox series

[RFC,v2,2/3] tst_cgroup: Add safe_cg_open and safe_cg_fchown functions

Message ID 1660813232-2378-2-git-send-email-xuyang2018.jy@fujitsu.com
State Superseded
Headers show
Series [RFC,v2,1/3] tst_safe_file_at: Add SAFE_FCHOWNAT macro | expand

Commit Message

Yang Xu Aug. 18, 2022, 9 a.m. UTC
safe_cg_open is used to open the sub control's file ie cgroup.procs
and returns the fd.

safe_cg_fchown is used to use fchownat to change file's uid and gid.

To avoid the problem that if the file only exists on a single V1 controller,
but if it exists on multiple controllers (e.g. any cgroup.* file) then we w
ill open multiple filesand only return the fd for the last of them, introduce
the common_cgroup_file function and add ctrl_name agrument.

The common_cgroup_file is used to detect whether this file can exists on
each controller. If the created cg is v2, we don't have this problem. If
the created cg is v1, then we need to use common_cgroup_file. Also need to
compare root cgroup ctrl whether equal to the ctrl_name agrument. So we
know that we are opening a correct controller cgroup* file instead of
last.

Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com>
---
 include/tst_cgroup.h |  38 +++++++++++++++
 lib/tst_cgroup.c     | 111 ++++++++++++++++++++++++++++++++++++-------
 2 files changed, 131 insertions(+), 18 deletions(-)
diff mbox series

Patch

diff --git a/include/tst_cgroup.h b/include/tst_cgroup.h
index d06847cc6..e75d88254 100644
--- a/include/tst_cgroup.h
+++ b/include/tst_cgroup.h
@@ -82,6 +82,7 @@ 
 #define TST_CGROUP_H
 
 #include <sys/types.h>
+#include <stdbool.h>
 
 /* CGroups Kernel API version */
 enum tst_cg_ver {
@@ -89,6 +90,25 @@  enum tst_cg_ver {
 	TST_CG_V2 = 2,
 };
 
+/* Controller sub-systems */
+enum cgroup_ctrl_indx {
+	CTRL_MEMORY = 1,
+	CTRL_CPU,
+	CTRL_CPUSET,
+	CTRL_IO,
+	CTRL_PIDS,
+	CTRL_HUGETLB,
+	CTRL_CPUACCT,
+	CTRL_DEVICES,
+	CTRL_FREEZER,
+	CTRL_NETCLS,
+	CTRL_NETPRIO,
+	CTRL_BLKIO,
+	CTRL_MISC,
+	CTRL_PERFEVENT,
+	CTRL_DEBUG
+};
+
 /* Used to specify CGroup hierarchy configuration options, allowing a
  * test to request a particular CGroup structure.
  */
@@ -188,6 +208,24 @@  ssize_t safe_cg_read(const char *const file, const int lineno,
 			 char *const out, const size_t len)
 			 __attribute__ ((nonnull));
 
+#define SAFE_CG_OPEN(cg, file_name, ctrl_indx, flags)		\
+	safe_cg_open(__FILE__, __LINE__,				\
+			(cg), (file_name), (ctrl_indx), (flags))
+
+int safe_cg_open(const char *const file, const int lineno,
+		    const struct tst_cg_group *const cg,
+		    const char *const file_name,
+		    enum cgroup_ctrl_indx ctrl_indx, int flags);
+
+#define SAFE_CG_FCHOWN(cg, file_name, ctrl_indx, owner, group)	\
+	safe_cg_fchown(__FILE__, __LINE__,				\
+			   (cg), (file_name), (ctrl_indx), (owner), (group))
+
+void safe_cg_fchown(const char *const file, const int lineno,
+		    const struct tst_cg_group *const cg,
+		    const char *const file_name,
+		    enum cgroup_ctrl_indx ctrl_indx, uid_t owner, gid_t group);
+
 #define SAFE_CG_PRINTF(cg, file_name, fmt, ...)			\
 	safe_cg_printf(__FILE__, __LINE__,				\
 			   (cg), (file_name), (fmt), __VA_ARGS__)
diff --git a/lib/tst_cgroup.c b/lib/tst_cgroup.c
index 1cfd79243..946b945f0 100644
--- a/lib/tst_cgroup.c
+++ b/lib/tst_cgroup.c
@@ -77,24 +77,6 @@  struct cgroup_root {
 	int no_cpuset_prefix:1;
 };
 
-/* Controller sub-systems */
-enum cgroup_ctrl_indx {
-	CTRL_MEMORY = 1,
-	CTRL_CPU,
-	CTRL_CPUSET,
-	CTRL_IO,
-	CTRL_PIDS,
-	CTRL_HUGETLB,
-	CTRL_CPUACCT,
-	CTRL_DEVICES,
-	CTRL_FREEZER,
-	CTRL_NETCLS,
-	CTRL_NETPRIO,
-	CTRL_BLKIO,
-	CTRL_MISC,
-	CTRL_PERFEVENT,
-	CTRL_DEBUG
-};
 #define CTRLS_MAX CTRL_DEBUG
 
 /* At most we can have one cgroup V1 tree for each controller and one
@@ -1192,6 +1174,25 @@  static const char *cgroup_file_alias(const struct cgroup_file *const cfile,
 	return cfile->file_name_v1;
 }
 
+__attribute__ ((nonnull, warn_unused_result))
+static bool common_cgroup_file(const char *alias,
+			       const struct cgroup_dir *const dir)
+{
+	int i;
+
+	if (dir->dir_root->ver != TST_CG_V1) {
+		for (i = 0; cgroup_ctrl_files[i].file_name; i++)
+			if (!strcmp(cgroup_ctrl_files[i].file_name, alias))
+				return true;
+	} else {
+		for (i = 0; cgroup_ctrl_files[i].file_name_v1; i++)
+			if (!strcmp(cgroup_ctrl_files[i].file_name_v1, alias))
+				return true;
+	}
+
+	return false;
+}
+
 int safe_cg_has(const char *const file, const int lineno,
 		    const struct tst_cg_group *cg,
 		    const char *const file_name)
@@ -1297,6 +1298,80 @@  ssize_t safe_cg_read(const char *const file, const int lineno,
 	return read_ret;
 }
 
+int safe_cg_open(const char *const file, const int lineno,
+			const struct tst_cg_group *cg,
+			const char *const file_name,
+			enum cgroup_ctrl_indx ctrl_indx, int flags)
+{
+	const struct cgroup_file *const cfile =
+		cgroup_file_find(file, lineno, file_name);
+	struct cgroup_dir *const *dir;
+	const char *alias;
+	int fd, dismatch_ctrl = 0;
+
+	for_each_dir(cg, cfile->ctrl_indx, dir) {
+		alias = cgroup_file_alias(cfile, *dir);
+		if (!alias)
+			continue;
+
+		/*
+		 * For the file that exists on multiple v1 controllers (e.g. any cgroup.* file)
+		 * we need to ensure the v1 controller is belong to the specified controller.
+		 */
+		if ((*dir)->dir_root->ver == TST_CG_V1 && common_cgroup_file(alias, *dir)) {
+			if ((*dir)->ctrl_field == (uint32_t)1 << ctrl_indx) {
+				fd = safe_openat(file, lineno, (*dir)->dir_fd, alias, flags);
+				return fd;
+			}
+			dismatch_ctrl = (*dir)->ctrl_field;
+		} else {
+			fd = safe_openat(file, lineno, (*dir)->dir_fd, alias, flags);
+			return fd;
+		}
+	}
+
+	tst_brk_(file, lineno, TBROK, "%s is not in correct v1 controller expected %d but got %d",
+					file_name, 1 << ctrl_indx, dismatch_ctrl);
+	return -1;
+}
+
+void safe_cg_fchown(const char *const file, const int lineno,
+			const struct tst_cg_group *cg,
+			const char *const file_name,
+			enum cgroup_ctrl_indx ctrl_indx,
+			uid_t owner, gid_t group)
+{
+	const struct cgroup_file *const cfile =
+		cgroup_file_find(file, lineno, file_name);
+	struct cgroup_dir *const *dir;
+	const char *alias;
+	int dismatch_ctrl = 0;
+
+	for_each_dir(cg, cfile->ctrl_indx, dir) {
+		alias = cgroup_file_alias(cfile, *dir);
+		if (!alias)
+			continue;
+
+		/*
+		 * For the file that exists on multiple v1 controllers (e.g. any cgroup.* file)
+		 * we need to ensure the v1 controller is belong to the specified controller.
+		 */
+		if ((*dir)->dir_root->ver == TST_CG_V1 && common_cgroup_file(alias, *dir)) {
+			if ((*dir)->ctrl_field == (uint32_t)1 << ctrl_indx) {
+				safe_fchownat(file, lineno, (*dir)->dir_fd, alias, owner, group, 0);
+				return;
+			}
+			dismatch_ctrl = (*dir)->ctrl_field;
+		} else {
+			safe_fchownat(file, lineno, (*dir)->dir_fd, alias, owner, group, 0);
+			return;
+		}
+	}
+
+	tst_brk_(file, lineno, TBROK, "%s is not in correct v1 controller expected %d but got %d",
+					file_name, 1 << ctrl_indx, dismatch_ctrl);
+}
+
 void safe_cg_printf(const char *const file, const int lineno,
 			const struct tst_cg_group *cg,
 			const char *const file_name,