From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.openvz.org (unknown [69.168.225.77]) by lore.virtuozzo.com (Postfix) with ESMTPS id 78BA48015C for ; Fri, 18 Sep 2026 07:13:00 +0000 (UTC) Received: from mail.openvz.org (localhost [127.0.0.1]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 68I7BbGO030104; Fri, 18 Sep 2026 10:11:38 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 68I7BbGO030104 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="erzX04AS" Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 68I7BYpj030094 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Fri, 18 Sep 2026 10:11:35 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 68I7BYpj030094 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-49e823c4868so3150455e9.0 for ; Fri, 18 Sep 2026 00:11:34 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvBxzNBNncHeG1CcMSClxu6rjD1/bVNdb79UOfBFTYJLS4dzUYF7g1+MJnaZiHb1UYLStjVeF9g==@openvz.org X-Gm-Message-State: AFuF++kq6wQE3o0ZuyLYlUEi3+dHCjBcqWEiQQj2oYFdkSeWbOqFzebp 9+R2o44FxE/R2Z73rkbaklbI123+zrruX4vDVTfMAogGWm80lFo0OYP70IMhFRjpfxa9ZdfY0Wu xFHxoAfjoX4mB5yMoppier3FStFAlvJoQ+V1HmhGS9z3zsfgSw98+oA== X-Gm-Gg: AYBFou1G+PZ2ZdiMoLsGX8kfgOOKoIkl3v5GnEawFTc+Ro9FUhJKd3FkJHjp+Qi3//i Jqaw/j4YcM3LaqDbaOUO72iroB7RBT5TrDFbyptG0c8x6RJyjog7Zhig3kgXDWXkO3t0927UbEc NoPV2CxWRkEw2BkJd5uJfhAX0ZE6GhYfN2wHj9WkJ2za8yqPRpwR2RFHMbf2L8YkptQK5/lJBJn oumwJsxTUjd052lE/H3WxLkr1JpGjyjFfHD4dBf0N+X/iZ68rwp+8fuNL5lbzxNSHsX8RIGE2mR T8JoQ9LIy+Rt8KSk+lRwrVmFGDil8DqX4l+cY76JQJjAIofZeJqDYALrAFgzKyIIi2kCKZHyJ5M 86P/qzXAySK52snNwhshOeech0uhtLzs= X-Received: by 2002:a05:600c:64c5:b0:49e:6c11:c4fc with SMTP id 5b1f17b1804b1-49fc56aa4e7mr41006085e9.7.1789715494454; Fri, 18 Sep 2026 00:11:34 -0700 (PDT) X-Received: by 2002:a05:600c:64c5:b0:49e:6c11:c4fc with SMTP id 5b1f17b1804b1-49fc56aa4e7mr41005305e9.7.1789715494051; Fri, 18 Sep 2026 00:11:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1789715494; cv=none; d=google.com; s=arc-20260327; b=KSuPWHt2FOnIbZsxOcV+qD5Zxxzwa2jHVWuGj3yVdhKNod0jDZB9VQkFM2KmYBRHAX mgPvP7VCfSGKURkpAKvtOA/bQAFh1qZBVXBdOoLOlkhCxxSdmheCS1vM3qb5H5cCDMqA SDqRwNQW3gpr/8ISUnvJRMWqeRf53gY9bVrFPuY1RSZ0juxK/4C7nh4ZgW545lDjSz6I xduc3knrAi/jwKMvdyWrd21ubFijj7srUkONtN+Vu/5LJX97kqnB1K/VXpBcjft0+XQr lXSAx4UIvEb9nXdJANmgC4k2lRdNEQ12VL5gZjCTobxtPF2ZNYioh7ew3tUiXB26IWZw K5Aw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=message-id:date:references:in-reply-to:cc:to:from:subject :content-transfer-encoding:mime-version:dkim-signature; bh=bhPhsVtMO8YCpCFa4XskCXW5Od/8WTRRB6Xtg5XQ5PI=; fh=CTF2GHyV+XdzB5TROrdG4fdLri6JSHNOBC+LNuNq5bA=; b=Q5uQkkC99Hz60G9UkZIzTouXnsLO9ROrl5SShmaLDvYQXYVQOi07DXEXlUkTxyNedP Ajb3ZPb5YB/h2dNChJabZa7s5H1ZVm0i//v9KaYpS+PVk0mvn+w5sOIe7MELKXxRLzX1 d4O51X5rPmUQuUBW4HWkSWf2ahJadiHRw1T87Gd9U0hFrZBGzPS5cITdC9Ub9xvmxUNL 8nsnpmF+mV9LVNSTHmYhYi7EbsPaSYBGcBzqRKSRGHd8FiT8sQmXPBbUUBOPHJL8rpy2 Nw6YYcDP9W5gnHM9Nipm3RQXsek7cBALmfcBnQ4hmFOxsjf/O65L0GlR7bm8Agi4/k2j WXJw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=erzX04AS; spf=pass (google.com: domain of vasileios.almpanis@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=vasileios.almpanis@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com Received: from relay.virtuozzo.com (relay.virtuozzo.com. [130.117.225.111]) by mx.google.com with ESMTPS id 5b1f17b1804b1-49fbd32d3d1si107966525e9.4.2026.09.18.00.11.33 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 18 Sep 2026 00:11:33 -0700 (PDT) Received-SPF: pass (google.com: domain of vasileios.almpanis@virtuozzo.com designates 130.117.225.111 as permitted sender) client-ip=130.117.225.111; Authentication-Results: mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b=erzX04AS; spf=pass (google.com: domain of vasileios.almpanis@virtuozzo.com designates 130.117.225.111 as permitted sender) smtp.mailfrom=vasileios.almpanis@virtuozzo.com; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=virtuozzo.com DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=Message-Id:Date:From:Subject:Content-Type: MIME-Version; bh=bhPhsVtMO8YCpCFa4XskCXW5Od/8WTRRB6Xtg5XQ5PI=; b=erzX04ASkDwJ VCHegrj++YOKHo9EAnLGaw56gxGqxqTlU4W9Uj/CZuv/2pXt1/+3MyNlglAvp/oCrUEXoTmH187ML 6JgE73B8Q2UmytQU00X7ZUOPZzeT/ffhk0ry6FvtBsOeRQOO8ywyYyAhwQ9F/tpt5k1C7wzCik+az zGMnOC1zEJDg/xMKbtO2gxC4ygVG4hvWBUEsYN7K2pDhDSAadgjGwl8s4H8LHXDaTURbTfASTfXNH yQ/mhz4G9UzE3BuGL81hGWITErwPKLR+iTbJphEXoY4uGSnZmTTKbMSrpjLmUW0F4dGrWkfKCWfcM sHYkUAPhw4B2r7GixNuDKw==; Received: from [130.117.225.5] (helo=dev010.ch-qa.vzint.dev) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1x7Si8-00H4JP-1j; Fri, 18 Sep 2026 09:11:30 +0200 MIME-Version: 1.0 From: Vasileios Almpanis To: Eva Kurchatova In-Reply-To: <20260916123128.799429-2-eva.kurchatova@virtuozzo.com> References: <20260916123128.799429-1-eva.kurchatova@virtuozzo.com> <20260916123128.799429-2-eva.kurchatova@virtuozzo.com> Date: Fri, 18 Sep 2026 07:11:31 +0000 Message-Id: <178971549188.627261.1659284489115750750.b4-review@b4> X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1789715493; l=10148; i=vasileios.almpanis@virtuozzo.com; s=20260812; h=from:subject:message-id; bh=crKHgP2cBQX9fK37QgMSdAOxWalFFxYsdek5s1LSMf8=; b=yPpbR9YW8rK2geJALXapKl7M+2T27/4QOHeNaK+IRW5WsiqBc+eAU+PYNE0mDBCK78rugdEPR vK5+eAigc5JAQ0PRZgE0QlPRcmgJaE5AOb1z/HjYo10iuUfrWWhOU4a X-Developer-Key: i=vasileios.almpanis@virtuozzo.com; a=ed25519; pk=HhuHDXAcPva9A8zccWEMRsb36reu+y4IVbBjXKxNUjw= X-OZ-Fwd: true Cc: devel@openvz.org Subject: Re: [Devel] [PATCH vz10 v2 2/2] selftests: ve: introduce vtty pair teardown stress test X-BeenThere: devel@openvz.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: OpenVZ development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: devel-bounces@openvz.org Errors-To: devel-bounces@openvz.org > A vtty pair is created by the first master open and torn down by the > last close. The close racing the peer's close used to let both sides > decide they were the final one and call release_tty() twice, and a > master opening again while a teardown was in flight used to hand out a > reference to a tty_struct about to be freed. > > Hammer both ends. The master comes from the vzctl ioctl, which does > not look the VE up. The slave is only reachable from inside the VE, as > TTY_MAJOR minor 1..MAX_NR_VTTY_CONSOLES, which vtty_driver() maps to > vttys index minor - 1, so the test builds a VE with cgroup2, sets > ve.veid to the cgroup it made, and runs the slave side there. > > One of the symtoms of a buggy kernel is dmesg warning, not just an > eventual crash, so the test checks that. A crashed node should also > report test failure in CI, but that's less verbose, hence the check. > > https://virtuozzo.atlassian.net/browse/VSTOR-144771 > > Feature: ve selftest > Signed-off-by: Eva Kurchatova > > diff --git a/tools/testing/selftests/ve/.gitignore b/tools/testing/selftests/ve/.gitignore > index afa4c568c2c9..9d8d86093827 100644 > --- a/tools/testing/selftests/ve/.gitignore > +++ b/tools/testing/selftests/ve/.gitignore > @@ -1,2 +1,3 @@ > ve_ns_owner_test > ve_perms_test > +ve_vtty_stress > diff --git a/tools/testing/selftests/ve/Makefile b/tools/testing/selftests/ve/Makefile > index ec40cbc7b3a1..6cd5823c4d93 100644 > --- a/tools/testing/selftests/ve/Makefile > +++ b/tools/testing/selftests/ve/Makefile > @@ -4,5 +4,6 @@ CFLAGS += -g -Wall -O2 > > TEST_GEN_PROGS += ve_ns_owner_test > TEST_GEN_PROGS += ve_perms_test > +TEST_GEN_PROGS += ve_vtty_stress > > include ../lib.mk > diff --git a/tools/testing/selftests/ve/settings b/tools/testing/selftests/ve/settings > new file mode 100644 > index 000000000000..e2206265f67c > --- /dev/null > +++ b/tools/testing/selftests/ve/settings > @@ -0,0 +1 @@ > +timeout=900 > diff --git a/tools/testing/selftests/ve/ve_vtty_stress.c b/tools/testing/selftests/ve/ve_vtty_stress.c > new file mode 100644 > index 000000000000..57edbdeef0c8 > --- /dev/null > +++ b/tools/testing/selftests/ve/ve_vtty_stress.c > @@ -0,0 +1,250 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * ve_vtty_stress - close a vtty pair from both ends at once. > + * > + * A vtty pair is created by the first master open and torn down by the > + * last close. A close racing the peer's close used to let both sides > + * decide they were the final one and call release_tty() twice, and a > + * master opened again while a teardown was still in flight used to hand > + * out a reference to a tty_struct that was about to be freed. Either > + * way the next close walked freed memory. > + * > + * The master comes from the vzctl ioctl, which does not look the VE up. > + * The slave is only reachable from inside the VE, as TTY_MAJOR minor > + * 1..MAX_NR_VTTY_CONSOLES, which vtty_driver() maps to vttys index > + * minor - 1. So the test makes a VE with cgroup2, hammers the master > + * from the host and the slave from a task inside it, and fails if the > + * kernel logs a complaint about the teardown. > + * > + * Surviving is not a pass on its own: the first symptom is a warning, > + * which stops nothing by itself. > + * > + * Usage: ve_vtty_stress [seconds] (default 600, or $VE_VTTY_SECS) > + */ > +#define _GNU_SOURCE > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "ve_selftest.h" > +#include "../kselftest.h" > + > +/* The ioctl argument; the trailing data[] the uapi struct has is unused. */ > +struct vzctl_ve_configure { > + unsigned int veid, key, val, size; > +}; > + > +#define VZCTL_VE_CONFIGURE _IOW('.', 15, struct vzctl_ve_configure) > +#define VE_CONFIGURE_OPEN_TTY 5 > + > +#define VTTY_IDX 0 /* the pair both ends work on */ > +#define SLAVE_MINOR (VTTY_IDX + 1) /* vtty_driver(): index = minor - 1 */ > +#define DEFAULT_SECS 600 > + > +static int open_master(int ctl_fd, unsigned int veid) > +{ > + struct vzctl_ve_configure c = { > + .veid = veid, > + .key = VE_CONFIGURE_OPEN_TTY, > + .val = VTTY_IDX, > + }; > + > + return ioctl(ctl_fd, VZCTL_VE_CONFIGURE, &c); > +} > + > +/* > + * The slave end, inside the VE. Every error here is one the race is > + * expected to produce: the pair is gone once the master has closed it. > + */ > +static int hammer_slave(time_t deadline, unsigned long *opened) > +{ > + char node[] = "/tmp/ve_vtty_slave"; > + > + unlink(node); > + if (mknod(node, S_IFCHR | 0600, makedev(TTY_MAJOR, SLAVE_MINOR)) < 0) > + return -1; > + > + while (time(NULL) < deadline) { > + int fd = open(node, O_RDWR | O_NOCTTY | O_NONBLOCK); > + > + if (fd >= 0) { > + (*opened)++; > + close(fd); > + } > + } > + unlink(node); > + return 0; > +} > + > +/* The kernel log, since a warning fails nothing by itself. */ > +static int kmsg_open(void) > +{ > + int fd = open("/dev/kmsg", O_RDONLY | O_NONBLOCK); > + > + if (fd >= 0) > + lseek(fd, 0, SEEK_END); > + return fd; > +} > + > +static int kmsg_check(int fd) > +{ > + static const char *const ours[] = { > + "tty_release", "release_tty", "check_tty_count", > + "vtty_open_master", "vtty_shutdown", > + }; > + char buf[8192]; > + int found = 0; > + ssize_t r; > + size_t i; > + > + while (fd >= 0 && (r = read(fd, buf, sizeof(buf) - 1)) > 0) { > + buf[r] = '\0'; > + if (!strstr(buf, "WARNING") && !strstr(buf, "BUG") && > + !strstr(buf, "Oops") && !strstr(buf, "general protection")) > + continue; > + for (i = 0; i < ARRAY_SIZE(ours); i++) > + if (strstr(buf, ours[i])) { > + ksft_print_msg("kernel log: %s", buf); > + found++; > + break; > + } > + } > + return found; > +} > + > +int main(int argc, char **argv) > +{ > + unsigned long master_opened = 0, slave_opened = 0; > + int cg, ctid, ctl, kmsg, ready[2], count[2], status; > + const char *env = getenv("VE_VTTY_SECS"); > + char path[PATH_MAX], val[16], c; > + time_t deadline; > + long secs; > + pid_t pid; > + > + ksft_print_header(); > + secs = argc > 1 ? atol(argv[1]) : (env ? atol(env) : DEFAULT_SECS); > + if (secs <= 0) > + secs = DEFAULT_SECS; > + > + ctl = open("/dev/vzctl", O_RDWR); > + if (ctl < 0) > + ksft_exit_skip("cannot open /dev/vzctl: %s, the vz modules " > + "(vzdev, vzmon) are needed\n", > + strerror(errno)); > + > + cg = mount_cg2_fd(); > + if (cg < 0) > + ksft_exit_skip("cannot mount cgroup2: %s\n", strerror(errno)); > + write_file_at(cg, "cgroup.subtree_control", VE_CONTROLLERS); > + > + ctid = make_ve(cg, CTID_MIN); > + if (ctid < 0) > + ksft_exit_skip("cannot make a VE cgroup\n"); > + > + /* > + * The pair is filed under the veid of the VE, so the two ends only > + * meet if the cgroup carries the one the master is opened for. > + */ > + snprintf(path, sizeof(path), "%d/ve.veid", ctid); > + snprintf(val, sizeof(val), "%d", ctid); > + if (write_file_at(cg, path, val) < 0) { > + destroy_ve(cg, ctid); > + ksft_exit_skip("cannot set ve.veid: %s\n", strerror(errno)); > + } > + > + /* Do not report a failure where the vtty pair cannot be had at all. */ > + status = open_master(ctl, ctid); > + if (status < 0 && errno != EBUSY) { > + destroy_ve(cg, ctid); > + ksft_exit_skip("no vtty master: %s\n", strerror(errno)); > + } > + if (status >= 0) > + close(status); > + > + ksft_set_plan(1); > + kmsg = kmsg_open(); > + if (kmsg < 0) > + ksft_print_msg("cannot read /dev/kmsg: %s, only a crash will " > + "be noticed\n", > + strerror(errno)); > + > + if (pipe(ready) || pipe(count)) > + ksft_exit_fail_msg("pipe: %s\n", strerror(errno)); > + > + deadline = time(NULL) + secs; > + ksft_print_msg("VE %d, pair %d, %ld seconds\n", ctid, VTTY_IDX, secs); > + > + pid = fork(); > + if (pid == 0) { > + close(ready[0]); > + close(count[0]); > + if (enter_cgroup(cg, ctid) < 0) > + _exit(1); > + /* > + * CLONE_NEWVE puts the task in the VE the cgroup names, so > + * the slave lookup finds the pair. The pid namespace is > + * what a VE wants of its first task. > + */ > + if (unshare(CLONE_NEWVE | CLONE_NEWPID | CLONE_NEWNS) < 0) > + _exit(1); > + if (fork() == 0) { > + unsigned long n = 0; > + > + c = 'r'; > + if (write(ready[1], &c, 1) != 1) > + _exit(1); > + if (hammer_slave(deadline, &n) < 0) > + _exit(1); > + if (write(count[1], &n, sizeof(n)) != sizeof(n)) > + _exit(1); > + _exit(0); > + } > + wait(&status); > + _exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1); > + } else if (pid < 0) { > + ksft_exit_fail_msg("fork: %s\n", strerror(errno)); > + } > + close(ready[1]); > + close(count[1]); > + > + if (read(ready[0], &c, 1) != 1) { > + waitpid(pid, &status, 0); > + destroy_ve(cg, ctid); > + ksft_exit_fail_msg("the VE side never came up\n"); > + } > + > + while (time(NULL) < deadline) { > + int fd = open_master(ctl, ctid); > + > + if (fd >= 0) { > + master_opened++; > + close(fd); > + } > + } > + > + if (read(count[0], &slave_opened, sizeof(slave_opened)) != > + sizeof(slave_opened)) > + slave_opened = 0; > + waitpid(pid, &status, 0); > + > + ksft_print_msg("%lu master opens, %lu slave opens\n", master_opened, > + slave_opened); > + > + status = kmsg_check(kmsg); > + destroy_ve(cg, ctid); > + > + if (!master_opened) > + ksft_exit_fail_msg("no master was ever opened\n"); > + if (!slave_opened) > + ksft_exit_fail_msg("no slave was ever opened\n"); > + if (status) > + ksft_exit_fail_msg("kernel complained %d time(s)\n", status); > + > + ksft_test_result_pass("vtty pair closed from both ends\n"); > + ksft_finished(); > +} Reviewed-by: Vasileios Almpanis -- Vasileios Almpanis _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel