All Virtuozzo development lists (kernel + QEMU)
 help / color / mirror / Atom feed
* [Devel] [PATCH VZ10 v4 0/3] Improvements for ve selftests
@ 2026-09-25 12:47 Konstantin Khorenko
  2026-09-25 12:47 ` [Devel] [PATCH VZ10 v4 1/3] ve_namespace: Allow entering non-running VE namespace Konstantin Khorenko
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Konstantin Khorenko @ 2026-09-25 12:47 UTC (permalink / raw)
  To: Vladimir Riabchun, Vasileios Almpanis; +Cc: devel

This change adds helpers for creating and preserving various
namespaces and running functions inside them.
This appeared useful while implementing ve mount accounting
selftests - it required keeping mount namespace alive and
doing different things at different moments of time.

To make setns work with CLONE_NEWVE without starting VE,
the first patch changes the -EINVAL return to a warning message.

https://virtuozzo.atlassian.net/browse/VSTOR-144504

Feature: ve selftests

Changes in v4:
- Moved the ve_namespace patch to the front, before the selftest
  helpers that rely on it.
- ve_namespace: the warning follows the "CT: %s:" format of other
  ve.c messages and prints the VE state and the offender's comm/pid;
  the commit message now explains why the warning is kept.
- namespace management helpers: prepare_namespaces() leaves ctx
  empty on any failure (mask zeroed on entry, saved fds closed on
  error), so unconditional cleanup in callers is safe; fixed a
  comment typo.
- more helpers: dropped a stray blank line in run_in_ve().
- Collected Reviewed-by tags.
- Link to v3: http://lore.virtuozzo.com/20260909-ve-selftest-improv-v3-0-4b41980d9a45@virtuozzo.com

Changes in v3:
- Patch 1: wrap flag -> (flag) in macros, undef them after use.
- Patch 2: Fix comments in run_in_ve function.
- Link to v2: http://lore.virtuozzo.com/20260909-ve-selftest-improv-v2-0-aad0a25d6569@virtuozzo.com

Changes in v2:
- Patch 1: fixed JOIN_NS order in enter_namespaces, added proper
  cleanup in prepare_namespaces.
- Patch 2: increased buf size in write_u64_at, added range check in
  read_s32_at, separated setup failures in run_in_ve from fn setup
  failures.
- Patch 3: Removed kselftests mention.
- Link to v1: http://lore.virtuozzo.com/20260907-ve-selftest-improv-v1-0-a17847abbd48@virtuozzo.com

Signed-off-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
Vladimir Riabchun (3):
      ve_namespace: Allow entering non-running VE namespace
      selftests/ve: Add namespace management helpers
      selftests/ve: Add more helpers

 kernel/ve/ve_namespace.c                 |   4 +-
 tools/testing/selftests/ve/ve_selftest.h | 214 ++++++++++++++++++++++++++++++-
 2 files changed, 210 insertions(+), 8 deletions(-)
---
base-commit: f7ba712715849bef1a54e1f13fab79b094ccc0df
change-id: 20260907-ve-selftest-improv-2d043d021cae

Best regards,
--  
Konstantin Khorenko <khorenko@virtuozzo.com>

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Devel] [PATCH VZ10 v4 1/3] ve_namespace: Allow entering non-running VE namespace
  2026-09-25 12:47 [Devel] [PATCH VZ10 v4 0/3] Improvements for ve selftests Konstantin Khorenko
@ 2026-09-25 12:47 ` Konstantin Khorenko
  2026-09-25 12:47 ` [Devel] [PATCH VZ10 v4 2/3] selftests/ve: Add namespace management helpers Konstantin Khorenko
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Konstantin Khorenko @ 2026-09-25 12:47 UTC (permalink / raw)
  To: Vladimir Riabchun, Vasileios Almpanis; +Cc: devel

From: Vladimir Riabchun <vladimir.riabchun@virtuozzo.com>

The restriction doesn't bring a lot of value and makes tests more
complex: to enter a VE namespace, the VE has to be actually started.

In vzctl we have locking to prevent parallel creations.
If someone decides to skip locks and start one CT
in parallel - big mistake, but not ours.

Still, entering a non-running CT is a strange thing to do. Our
selftests do it on purpose, but if some of our userspace does the
same on a production node, that is a bug we want to know about and
fix, so leave a warning in place of the check.

https://virtuozzo.atlassian.net/browse/VSTOR-144504

Feature: ve selftests
Signed-off-by: Vladimir Riabchun <vladimir.riabchun@virtuozzo.com>
Reviewed-by: Vasileios Almpanis <vasileios.almpanis@virtuozzo.com>
Reviewed-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
 kernel/ve/ve_namespace.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/ve/ve_namespace.c b/kernel/ve/ve_namespace.c
index 3dbe0dde2645d..6b12bcd605ea4 100644
--- a/kernel/ve/ve_namespace.c
+++ b/kernel/ve/ve_namespace.c
@@ -227,7 +227,9 @@ static int ve_ns_install(struct nsset *nsset, struct ns_common *new)
 		return -EPERM;
 
 	if (!VE_IS_RUNNING(ve_ns->ve))
-		return -EINVAL;
+		pr_warn_once("CT: %s: setns to the VE namespace of a non-running CT (state %d) by %s (%d)\n",
+			     ve_name(ve_ns->ve), ve_ns->ve->state,
+			     current->comm, task_pid_nr(current));
 
 	/*
 	 * Don't need to put_ve_ns(nsset->ve_ns) here,

-- 
2.43.0

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Devel] [PATCH VZ10 v4 2/3] selftests/ve: Add namespace management helpers
  2026-09-25 12:47 [Devel] [PATCH VZ10 v4 0/3] Improvements for ve selftests Konstantin Khorenko
  2026-09-25 12:47 ` [Devel] [PATCH VZ10 v4 1/3] ve_namespace: Allow entering non-running VE namespace Konstantin Khorenko
@ 2026-09-25 12:47 ` Konstantin Khorenko
  2026-09-25 12:47 ` [Devel] [PATCH VZ10 v4 3/3] selftests/ve: Add more helpers Konstantin Khorenko
  2026-09-25 13:37 ` [Devel] [PATCH VZ10 v4 0/3] Improvements for ve selftests Konstantin Khorenko
  3 siblings, 0 replies; 5+ messages in thread
From: Konstantin Khorenko @ 2026-09-25 12:47 UTC (permalink / raw)
  To: Vladimir Riabchun, Vasileios Almpanis; +Cc: devel

From: Vladimir Riabchun <vladimir.riabchun@virtuozzo.com>

When mount namespace is created in a child, it is destroyed
when the child dies. We may need to keep it for a while to check
how VE handles resources.

Instead of keeping a thread which lives in a new ve+mnt namespaces,
let's store open namespace file descriptors to enter them later
without keeping children alive.

https://virtuozzo.atlassian.net/browse/VSTOR-144504

Feature: ve selftests
Signed-off-by: Vladimir Riabchun <vladimir.riabchun@virtuozzo.com>
Reviewed-by: Vasileios Almpanis <vasileios.almpanis@virtuozzo.com>
Reviewed-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
 tools/testing/selftests/ve/ve_selftest.h | 130 +++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/tools/testing/selftests/ve/ve_selftest.h b/tools/testing/selftests/ve/ve_selftest.h
index c53bf7900d208..bc9dc28a8d074 100644
--- a/tools/testing/selftests/ve/ve_selftest.h
+++ b/tools/testing/selftests/ve/ve_selftest.h
@@ -31,6 +31,136 @@
 #define VE_CONTROLLERS \
 	"+cpuset +cpu +cpuacct +io +memory +hugetlb +pids +rdma +misc +ve"
 
+struct namespace_ctx {
+	int ns_save_mask;	/* Mask of stored CLONE_NEW* namespaces. */
+	/* Namespace file descriptors. Name should match /proc/PID/ns/NAME */
+	int ve_fd;
+	int mnt_fd;
+};
+
+static inline void close_namespace_fds(struct namespace_ctx *ctx)
+{
+	if (ctx->ns_save_mask & CLONE_NEWVE)
+		close(ctx->ve_fd);
+	if (ctx->ns_save_mask & CLONE_NEWNS)
+		close(ctx->mnt_fd);
+
+	ctx->ns_save_mask = 0;
+}
+
+static inline int save_namespace_fds(struct namespace_ctx *ctx, int flags)
+{
+#define OPEN_NS(name, flag)                                                \
+do {                                                                       \
+	if (flags & (flag)) {                                              \
+		ctx->name##_fd = open("/proc/self/ns/" #name, O_RDONLY);   \
+		if (ctx->name##_fd < 0) {                                  \
+			fprintf(stderr, "%s: could not open fd %s: %s\n",  \
+				__func__, #name, strerror(errno));         \
+			goto err;                                          \
+		}                                                          \
+		ctx->ns_save_mask |= (flag);                               \
+	}                                                                  \
+} while (0)
+
+	ctx->ns_save_mask = 0;
+
+	OPEN_NS(ve, CLONE_NEWVE);
+	OPEN_NS(mnt, CLONE_NEWNS);
+
+#undef OPEN_NS
+	return 0;
+
+err:
+	close_namespace_fds(ctx);
+	return -1;
+}
+
+static inline int enter_namespaces(struct namespace_ctx *ctx, int flags)
+{
+#define JOIN_NS(name, flag)                                                 \
+do {                                                                        \
+	if (flags & (flag)) {                                               \
+		if (!(ctx->ns_save_mask & (flag))) {                        \
+			fprintf(stderr, "%s: could not switch ns %s:"       \
+				" no fd in context.\n", __func__, #name);   \
+			return -1;                                          \
+		}                                                           \
+		if (setns(ctx->name##_fd, (flag))) {                        \
+			fprintf(stderr, "%s: could not switch ns %s: %s\n", \
+				__func__, #name, strerror(errno));          \
+			return -1;                                          \
+		}                                                           \
+	}                                                                   \
+} while (0)
+
+	JOIN_NS(ve, CLONE_NEWVE);
+	JOIN_NS(mnt, CLONE_NEWNS);
+
+#undef JOIN_NS
+	return 0;
+}
+
+static inline int enter_cgroup(int cgv2_fd, int ctid);
+
+/*
+ * Create new namespaces and store them in ctx.
+ * CLONE_NEWVE is treated specially - before unshare corresponding
+ * CT cgroup is entered, after it root cgroup is entered (not the original one).
+ */
+static inline int prepare_namespaces(struct namespace_ctx *ctx, int flags,
+	int cgv2_fd, int ctid)
+{
+	struct namespace_ctx tmp_ctx;
+	int ret = 0;
+
+	ctx->ns_save_mask = 0;
+
+	if (save_namespace_fds(&tmp_ctx, flags) < 0)
+		return -1;
+
+	if (flags & CLONE_NEWVE) {
+		if (enter_cgroup(cgv2_fd, ctid) < 0) {
+			fprintf(stderr, "%s: failed to enter CT cgroup\n", __func__);
+			ret = -1;
+			goto restore_ns;
+		}
+	}
+
+	if (unshare(flags) < 0) {
+		fprintf(stderr, "%s: failed to unshare, flags %x: %s\n",
+			__func__, flags, strerror(errno));
+		ret = -1;
+		goto restore_cg;
+	}
+
+	if (save_namespace_fds(ctx, flags)) {
+		fprintf(stderr, "%s: failed to save new namespaces, flags %x\n",
+			__func__, flags);
+		ret = -1;
+	}
+
+restore_cg:
+	if (flags & CLONE_NEWVE) {
+		if (enter_cgroup(cgv2_fd, 0) < 0) {
+			fprintf(stderr, "%s: failed to restore root cgroup\n", __func__);
+			ret = -1;
+		}
+	}
+
+restore_ns:
+	if (enter_namespaces(&tmp_ctx, flags) < 0) {
+		fprintf(stderr, "%s: failed to restore old namespaces, flags %x\n",
+			__func__, flags);
+		ret = -1;
+	}
+
+	close_namespace_fds(&tmp_ctx);
+	if (ret < 0)
+		close_namespace_fds(ctx);
+	return ret;
+}
+
 static inline int write_file_at(int dirfd, const char *path, const char *val)
 {
 	int fd, ret;

-- 
2.43.0

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Devel] [PATCH VZ10 v4 3/3] selftests/ve: Add more helpers
  2026-09-25 12:47 [Devel] [PATCH VZ10 v4 0/3] Improvements for ve selftests Konstantin Khorenko
  2026-09-25 12:47 ` [Devel] [PATCH VZ10 v4 1/3] ve_namespace: Allow entering non-running VE namespace Konstantin Khorenko
  2026-09-25 12:47 ` [Devel] [PATCH VZ10 v4 2/3] selftests/ve: Add namespace management helpers Konstantin Khorenko
@ 2026-09-25 12:47 ` Konstantin Khorenko
  2026-09-25 13:37 ` [Devel] [PATCH VZ10 v4 0/3] Improvements for ve selftests Konstantin Khorenko
  3 siblings, 0 replies; 5+ messages in thread
From: Konstantin Khorenko @ 2026-09-25 12:47 UTC (permalink / raw)
  To: Vladimir Riabchun, Vasileios Almpanis; +Cc: devel

From: Vladimir Riabchun <vladimir.riabchun@virtuozzo.com>

Some more read/write helpers may be useful.

Also, add a helper to execute functions in child process with
switched namespaces and cgroup.

https://virtuozzo.atlassian.net/browse/VSTOR-144504

Feature: ve selftests
Signed-off-by: Vladimir Riabchun <vladimir.riabchun@virtuozzo.com>
Reviewed-by: Vasileios Almpanis <vasileios.almpanis@virtuozzo.com>
Reviewed-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
 tools/testing/selftests/ve/ve_selftest.h | 84 +++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/ve/ve_selftest.h b/tools/testing/selftests/ve/ve_selftest.h
index bc9dc28a8d074..7b45f91c1d561 100644
--- a/tools/testing/selftests/ve/ve_selftest.h
+++ b/tools/testing/selftests/ve/ve_selftest.h
@@ -175,6 +175,14 @@ static inline int write_file_at(int dirfd, const char *path, const char *val)
 	return (ret == (int)len) ? 0 : -1;
 }
 
+static inline int write_u64_at(int dirfd, const char *path, unsigned long long val)
+{
+	char s[32];
+
+	snprintf(s, sizeof(s), "%llu", val);
+	return write_file_at(dirfd, path, s);
+}
+
 static inline int read_file_at(int dirfd, const char *path, char *buf,
 			       size_t buflen)
 {
@@ -205,14 +213,9 @@ static inline int read_u64_at(int dirfd, const char *path,
 			      unsigned long long *out)
 {
 	char buf[32] = {0}, *end;
-	int fd, ret;
-
-	fd = openat(dirfd, path, O_RDONLY);
-	if (fd < 0)
-		return -1;
+	int ret;
 
-	ret = read(fd, buf, sizeof(buf) - 1);
-	close(fd);
+	ret = read_file_at(dirfd, path, buf, sizeof(buf));
 	if (ret <= 0)
 		return -1;
 
@@ -223,6 +226,25 @@ static inline int read_u64_at(int dirfd, const char *path,
 	return 0;
 }
 
+static inline int read_s32_at(int dirfd, const char *path,
+			      int *out)
+{
+	char buf[32] = {0}, *end;
+	long tmp;
+	int ret;
+
+	ret = read_file_at(dirfd, path, buf, sizeof(buf));
+	if (ret <= 0)
+		return -1;
+
+	errno = 0;
+	tmp = strtol(buf, &end, 10);
+	if (errno || end == buf || tmp < INT_MIN || tmp > INT_MAX)
+		return -1;
+	*out = tmp;
+	return 0;
+}
+
 /* A fresh, private cgroup2 mount, returned as an fd to use with *at() calls. */
 static inline int mount_cg2_fd(void)
 {
@@ -266,6 +288,54 @@ static inline int enter_cgroup(int cgv2_fd, int ctid)
 	return ret;
 }
 
+/*
+ * Run function in VE cgroup and given namespaces.
+ *
+ * Namespaces are provided via namespace_ctx and entered based on flags mask.
+ *
+ * Return values:
+ *  -  0 if function returns zero
+ *  - -1 if function returns negative value
+ *  -  1 if function returns positive value
+ *  -  2 if setup fails
+ */
+static inline int run_in_ve(int cgv2_fd, int ctid, struct namespace_ctx *ctx,
+		int flags, int (*fn)(void *), void *arg)
+{
+	int status;
+	pid_t pid;
+
+	pid = fork();
+	if (pid < 0) {
+		fprintf(stderr, "%s: fork failed\n", __func__);
+		return 2;
+	}
+	if (pid == 0) {
+		int ret;
+
+		if (enter_cgroup(cgv2_fd, ctid) < 0) {
+			fprintf(stderr, "%s: enter_cgroup failed\n", __func__);
+			_exit(254);
+		}
+		if (enter_namespaces(ctx, flags) < 0)
+			_exit(254);
+
+		ret = fn(arg);
+		if (ret < 0)
+			ret = 1;
+		else if (ret > 0)
+			ret = 255;
+		_exit(ret);
+	}
+	if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status) == 254)
+		return 2;
+	if (WEXITSTATUS(status) == 255)
+		return 1;
+	if (WEXITSTATUS(status))
+		return -1;
+	return 0;
+}
+
 /*
  * Create a fresh VE cgroup at the first free id at or after @from and unhide
  * its ve.* control files. Return the new id, or -1.

-- 
2.43.0

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Devel] [PATCH VZ10 v4 0/3] Improvements for ve selftests
  2026-09-25 12:47 [Devel] [PATCH VZ10 v4 0/3] Improvements for ve selftests Konstantin Khorenko
                   ` (2 preceding siblings ...)
  2026-09-25 12:47 ` [Devel] [PATCH VZ10 v4 3/3] selftests/ve: Add more helpers Konstantin Khorenko
@ 2026-09-25 13:37 ` Konstantin Khorenko
  3 siblings, 0 replies; 5+ messages in thread
From: Konstantin Khorenko @ 2026-09-25 13:37 UTC (permalink / raw)
  To: Vladimir Riabchun, Vasileios Almpanis, Konstantin Khorenko; +Cc: devel

On Fri, 25 Sep 2026 14:47:01 +0200, Konstantin Khorenko wrote:
> Improvements for ve selftests
> 
> This change adds helpers for creating and preserving various
> namespaces and running functions inside them.
> This appeared useful while implementing ve mount accounting
> selftests - it required keeping mount namespace alive and
> doing different things at different moments of time.
> 
> [...]

Applied to branch-rh10-6.12.0-211.52.1.22.x.vz10-ovz, will be released in rh10-6.12.0-211.52.1.22.4.vz10, thanks!

[1/3] ve_namespace: Allow entering non-running VE namespace
      https://bitbucket.org/virtuozzocore/vzkernel.vzs/commits/9c6f7ef26780
[2/3] selftests/ve: Add namespace management helpers
      https://bitbucket.org/virtuozzocore/vzkernel.vzs/commits/c941a3e9e564
[3/3] selftests/ve: Add more helpers
      https://bitbucket.org/virtuozzocore/vzkernel.vzs/commits/e5808fb271c3

-- 
Konstantin Khorenko <khorenko@virtuozzo.com>

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-25 13:38 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-25 12:47 [Devel] [PATCH VZ10 v4 0/3] Improvements for ve selftests Konstantin Khorenko
2026-09-25 12:47 ` [Devel] [PATCH VZ10 v4 1/3] ve_namespace: Allow entering non-running VE namespace Konstantin Khorenko
2026-09-25 12:47 ` [Devel] [PATCH VZ10 v4 2/3] selftests/ve: Add namespace management helpers Konstantin Khorenko
2026-09-25 12:47 ` [Devel] [PATCH VZ10 v4 3/3] selftests/ve: Add more helpers Konstantin Khorenko
2026-09-25 13:37 ` [Devel] [PATCH VZ10 v4 0/3] Improvements for ve selftests Konstantin Khorenko

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.