[LTP] [PATCH 1/2] lib: Add library functions to check specified cgroup subsystem

Cyril Hrubis chrubis@suse.cz
Mon Jan 28 17:12:12 CET 2019


Hi!
> 1) Check if specified cgroup subsystem is supported.
> 2) Check if specified cgroup subsystem is mounted by default, and use
>    custom mountpoint as the cgroup subsystem's mountpoint properly.
> 3) Add doc for these library functions.
> 
> Signed-off-by: Xiao Yang <yangx.jy@cn.fujitsu.com>
> ---
>  doc/test-writing-guidelines.txt |  45 +++++++++++++++++
>  include/tst_cgroups.h           |  13 +++++
>  lib/tst_cgroups.c               | 107 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 165 insertions(+)
>  create mode 100644 include/tst_cgroups.h
>  create mode 100644 lib/tst_cgroups.c
> 
> diff --git a/doc/test-writing-guidelines.txt b/doc/test-writing-guidelines.txt
> index 731be76..57ae6aa 100644
> --- a/doc/test-writing-guidelines.txt
> +++ b/doc/test-writing-guidelines.txt
> @@ -1539,6 +1539,51 @@ static struct tst_test test = {
>  };
>  -------------------------------------------------------------------------------
>  
> +2.2.29 Parsing specified cgroup subsystem
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +void tst_set_cgroup_mntpoint(char *subsys_name, char *spec_mntpoint);

This function name is a bit misleading as it actually mounts the cgroup.

> +void tst_umount_cgroup(char *spec_mntpoint);
> +
> +The 'tst_set_cgroup_mntpoint()' function checks if 'subsys_name' (i.e. specified
> +cgroup subsystem) is supported and mounted by default, and uses 'spec_mntpoint'
> +(custom mountpoint) as 'subsys_name' mountpoint to test.  For details:
> +1) It exits with TCONF if 'subsys_name' is not supported.
> +2) If 'subsys_name' is already mounted to a mountpoint, it creates a symlink
> +   named by 'spec_mntpoint' to the pre-existent mountpoint.
> +3) If 'subsys_name' is not mounted, it mounts 'subsys_name' to 'spec_mntpoint'.
> +
> +The 'tst_umount_cgroup()' function unmounts and removes 'spec_mntpoint'.
> +
> +Note:
> +We should set .needs_tmpdir flag because we create 'spec_mntpoint' in tmpdir.

Generally this is a great step forward but what this is missing:

* Automatic cleanup, if tests creates any subdirectories in the cgroup
  filesystem these will stay there until the machine is rebooted

  I guess that it will be much easier to create the interface so that it
  returns a path to a newly created subdirectory in the cgroup
  filesystem tree so that we can remove it recursively later on

* Interface in tst_test structure. I suppose that we may add something
  as const char *needs_cgroup; to the tst_test structure which would
  be set to subsystem name such as:

  static struct tst_test test = {
	...
	.needs_cgroup = "memory",
	...
  };

  And the test will then set const char *tst_cgroup_path pointer to the
  actuall path to the cgroup.

* I do wonder if we will nedd support for more than one cgroup type
  later on, but so far I do not see that need so keeping it as an
  interface for a single subsytem type will suffice.

> +[source,c]
> +-------------------------------------------------------------------------------
> +#include "tst_test.h"
> +#include "tst_cgroups.h"
> +
> +static void setup(void)
> +{
> +	...
> +	tst_set_cgroups_mntpoint("memory", "mntpoint");
> +	...
> +}
> +
> +static void cleanup(void)
> +{
> +	...
> +	tst_umount_cgroup("mntpoint");
> +	...
> +}
> +
> +sturct tst_test test = {
> +        ...
> +        .setup = setup,
> +        .cleanup = cleanup,
> +        ...
> +};
> +-------------------------------------------------------------------------------
>  
>  2.3 Writing a testcase in shell
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> diff --git a/include/tst_cgroups.h b/include/tst_cgroups.h
> new file mode 100644
> index 0000000..70f5d18
> --- /dev/null
> +++ b/include/tst_cgroups.h
> @@ -0,0 +1,13 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
> + * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
> + */
> +
> +#ifndef TST_CGROUPS_H__
> +#define TST_CGROUPS_H__
> +
> +void tst_set_cgroup_mntpoint(char *subsys_name, char *spec_mntpoint);
> +void tst_umount_cgroup(char *spec_mntpoint);
> +
> +#endif	/* TST_CGROUPS_H__ */
> diff --git a/lib/tst_cgroups.c b/lib/tst_cgroups.c
> new file mode 100644
> index 0000000..dd027c5
> --- /dev/null
> +++ b/lib/tst_cgroups.c
> @@ -0,0 +1,107 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved.
> + * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
> + */
> +
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <mntent.h>
> +
> +#define TST_NO_DEFAULT_MAIN
> +#include "tst_test.h"
> +#include "tst_safe_stdio.h"
> +
> +#define CGROUPS_PATH	"/proc/cgroups"
> +#define MOUNTS_PATH	"/proc/mounts"
> +
> +static char *cgroup_mntpoint;
> +static int cgroup_mounted;
> +
> +void tst_umount_cgroup(char *spec_mntpoint)
> +{
> +	char buf[1024];
> +
> +	if (cgroup_mntpoint) {
> +		if (!access(spec_mntpoint, F_OK))
> +			SAFE_UNLINK(spec_mntpoint);
> +		return;
> +	}
> +
> +	if (cgroup_mounted) {
> +		/* 'spec_mntpoint' may be treated as source instead
> +		 * of target, so append '/' to 'spec_mntpoint'.  See
> +		 * ltp commit 4617249 for details.
> +		 */
> +		sprintf(buf, "%s/", spec_mntpoint);
> +		SAFE_UMOUNT(buf);
> +		cgroup_mounted = 0;
> +	}
> +
> +	if (!access(spec_mntpoint, F_OK))
> +		SAFE_RMDIR(spec_mntpoint);
> +}
> +
> +void tst_set_cgroup_mntpoint(char *subsys_name, char *spec_mntpoint)
> +{
> +	FILE *fp = NULL, *mp = NULL;
> +	struct mntent *mnt;
> +	char buf[1024], name[64];
> +	int enabled = 0, supported = 0;
> +
> +	if (access(CGROUPS_PATH, F_OK))
> +		tst_brk(TCONF, "Kernel didn't support for control groups");
> +
> +	fp = SAFE_FOPEN(CGROUPS_PATH, "r");
> +
> +	while (fgets(buf, 1024, fp)) {
> +		if (sscanf(buf, "%s %*d %*d %d", name, &enabled) == -1) {
> +			SAFE_FCLOSE(fp);
> +			tst_brk(TBROK | TERRNO,
> +				"sscanf() failed to read %s info",
> +				subsys_name);
> +		}
> +
> +		if (!strcmp(name, subsys_name)) {
> +			supported++;
> +			break;
> +		}
> +	}
> +
> +	SAFE_FCLOSE(fp);
> +
> +	if (!supported || !enabled) {
> +		tst_brk(TCONF,
> +			"%s wasn't supported by kernel or it wasn't enabled",
> +			subsys_name);
> +	}
> +
> +	mp = setmntent(MOUNTS_PATH, "r");
> +	if (mp == NULL) {
> +		tst_brk(TBROK | TERRNO,
> +			"setmntent() failed to open /proc/mounts");
> +	}
> +
> +	while ((mnt = getmntent(mp))) {
> +		if (hasmntopt(mnt, subsys_name)) {
> +			cgroup_mntpoint = mnt->mnt_dir;
> +			break;
> +		}
> +	}
> +
> +	endmntent(mp);
> +
> +	if (cgroup_mntpoint) {
> +		/* Use pre-existent subsys mountpoint and creat a symlink
> +		 * named by spec_mntpoint to it.
> +		 */
> +		SAFE_SYMLINK(cgroup_mntpoint, spec_mntpoint);
> +	} else {
> +		/* Mount subsys to spec_mntpoint. */
> +		SAFE_MKDIR(spec_mntpoint, 0777);
> +		SAFE_MOUNT("none", spec_mntpoint, "cgroup", 0, subsys_name);
> +		cgroup_mounted = 1;
> +	}
> +}
> -- 
> 1.8.3.1
> 
> 
> 

-- 
Cyril Hrubis
chrubis@suse.cz


More information about the ltp mailing list