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 BDAD48015C for ; Mon, 14 Sep 2026 09:37:18 +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 68E9a35H028407; Mon, 14 Sep 2026 12:36:05 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 68E9a35H028407 Authentication-Results: mail.openvz.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=virtuozzo.com header.i=@virtuozzo.com header.b="hQur/UW/" Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by mail.openvz.org (8.14.4/8.14.4) with ESMTP id 68E9ZwSe028394 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=FAIL) for ; Mon, 14 Sep 2026 12:35:58 +0300 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.openvz.org 68E9ZwSe028394 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-486f3dbf7d2so1807318f8f.0 for ; Mon, 14 Sep 2026 02:35:58 -0700 (PDT) X-Gm-Message-State: AFuF++mFo0eHsNCzXfaEdl+KRaJX06zuOjTAhhrPC9VKLqTWfu4BRCvx u/GRixTeyYBKhoWm2WA1T9auSubBSJJ6e6YES+DEuME7HM7wgf0iIcMKV44LXy2bsP8CY9LRgje SbH/4+sn2eyPeg4FZbC+NCwpx5jsyssEUGbwcRMQjDTY87vIaG/NUqw== X-Gm-Gg: AYBFou1F1kHTh2QCBuGsFr+wkkkUO51USANOt45t1hcLp7xg9CslYGMK1uPBxPGzy/c XjWrT4WmBEruC/Z+u0PFsKzp7KAIxv6+/pUGypq6WdcNDauSnGRKGWIsPzwxWzv8PCisNED8wf9 /Pf+CynnVeTO2iMUKL24LvxYLciF5sjlXtmo4Mb4dvHWrlsza0tzcyag6Wu66MWwE1KxFA7mZWY NkvXS0t0BEnvJ6LU1XrlSffY32aogclJcVnBP9aaenmG7RwnRn1jrTQACVxDuh9prP8DsPMCkWy aXIj9NVPivemv+ww9B+8mrxUWlCrtNFp7bZFU0VoIWI92wVgV/JADoRd/7+N7KVj7RsGMBz322s U1PSMeuSv4X7aZv22tgDCbjjOy2qkXH8= X-Received: by 2002:a05:6000:2002:b0:486:f614:dd0f with SMTP id ffacd0b85a97d-48702b30aeemr1642074f8f.52.1789378557710; Mon, 14 Sep 2026 02:35:57 -0700 (PDT) X-Received: by 2002:a05:6000:2002:b0:486:f614:dd0f with SMTP id ffacd0b85a97d-48702b30aeemr1641981f8f.52.1789378556529; Mon, 14 Sep 2026 02:35:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1789378556; cv=none; d=google.com; s=arc-20260327; b=kZ9kDkNTfspMinOohxb/R2Bhj+i3Jbf51XH6lm1fQCWFgapeWjjQDySQHseEBZT8f5 YA4zP4CbhYlj0cVnch/Zrbw5Gin2L5PLvV07mRJfA2yhM8mlWi/wZnb/+NzbjyfCmf/w rX13lXNM45aiSRB4m75hM3SEcu3MQm617x/zAv1k3xnwZPS1xIbrxDSkj3hq2l6fDnP0 GqwwvLl/OYJkZ+tVB8AAX5PzJm4yw9/cd+FlFBbzKNancwD6JORzpi3pYkYv1QmRNyLq kz3yGrRfL70P60d20uyiiV/Nex5YJAToJo4L3kteC1omnxj4ot8HZaM4JH6LbYeqWkZh ycRg== 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=h2NjYhbOaOyNPydomgTGpyuBo+LV18KTj6a9bI5RGlo=; fh=skezItRrPUmDWFjzm5RAGnCYsXdZjhBsZcOEYn6bEzI=; b=hBI4ks7Wizss9I+MdXveZ7PH75whTuWm2q6sl3SCQGcLdg3u0IkpkUBl+ihIH6yf1B zqLEKYXLm8WfyrOoZTBTQ3RbXUHDlrrDSdXdacGvW8WtvmerkSHDkuuYq+FgQg+Dty90 BdZfpuFc6oULgn1FflZHGJ9XY+tSvsg+uugiMUSAsBJDlN+b48+5FCElkSJfNM94Laep ykcJTY2/ItmCxOACUHIQdWDS1pzvl/XqeLObjz/jgaAhbj4X6FIgEd2sDr1d3qtB9TSq DWT5nELDFnXyEaZM90sdYxWy8FQy/538FxUEcvwbgyKl8RdGVO5zk7ndFjJrAmNqhGu8 EpWQ==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@virtuozzo.com header.s=relay header.b="hQur/UW/"; 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 ffacd0b85a97d-486eba60a3csi18164142f8f.328.2026.09.14.02.35.56 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Sep 2026 02:35:56 -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="hQur/UW/"; 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=h2NjYhbOaOyNPydomgTGpyuBo+LV18KTj6a9bI5RGlo=; b=hQur/UW/Ia74 +jvHjKY7H2+E14a/E6fcnnKHXVJuEOS1Tki+gTVHBbdI1Ga0ZQW7dTQ85lqwputXHK3zkz05KyP3z SaXGD9MXmMTzgPaCMqWQIbnGrqklucK/dPUgxo6qwmdBoMZi/5Y7cjNHkmsErY4MnxbsPCCUIexl3 a/bnkn3wWMNGODh9Wr5YwQoJ8/heViLTk1bxWwoc25R5m9OGbLlBnVdhHHzJH1jJm0zvDGzoDvcXs kaiysn3+ZegTKqH5bdRynk9GrzTuXnliUCEpVqPzKreTTkgdbxyuGLK+zdMljQiwpc+RyeFUpCmwH ZbKEml7hFxCn/ANR8k0uKA==; Received: from [130.117.225.5] (helo=dev010.ch-qa.vzint.dev) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1x633k-00FEoj-2q; Mon, 14 Sep 2026 11:35:47 +0200 MIME-Version: 1.0 From: Vasileios Almpanis To: Vladimir Riabchun In-Reply-To: <8cdef39deacb456104771458f4f75d1fae3d38f9.1788989664.git.vladimir.riabchun@virtuozzo.com> References: <8cdef39deacb456104771458f4f75d1fae3d38f9.1788989664.git.vladimir.riabchun@virtuozzo.com> Date: Mon, 14 Sep 2026 09:35:54 +0000 Message-Id: <178937855430.982024.6102594745116066136.b4-review@b4> X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1789378555; l=18050; i=vasileios.almpanis@virtuozzo.com; s=20260812; h=from:subject:message-id; bh=MRDfXvEE74XaiazWnWbTtEpeZdnBVCXhT9G7uf9/BBQ=; b=+D0Xy5jF7lNOsE0BvtCHFYVWbfx46SRkpbeXYT/jn7Zuvh3tLkxHPOML8v8ypmWyqQih7eH1b 3PQCkAbTKonAKiGSJDuHotQ9lu2PP4FyxyhPqfuiNqn+f/uj4Mg7DKe 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 v8 7/7] selftests/ve: Add mount accounting selftest 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 > There are 6 test cases, covered in the new test: > 1. Simple mount accouting correctness, just mount/umount. > 2. Verification of correct limit hits and changes, including > negative values. > 3. Partial mounts test, when mount limit is hit in the middle > of creation. > 4. Test that enabled pseudosuper allows overuse. > 5. Test that pseudosuper doesn't affect mount accounting. > 6. Failcount feature verification. > > https://virtuozzo.atlassian.net/browse/VSTOR-135520 > > Feature: per-ve failcounters > Signed-off-by: Vladimir Riabchun > > diff --git a/tools/testing/selftests/ve/.gitignore b/tools/testing/selftests/ve/.gitignore > index afa4c568c2c9..3df4d05888dc 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_mount_accounting_test > diff --git a/tools/testing/selftests/ve/Makefile b/tools/testing/selftests/ve/Makefile > index ec40cbc7b3a1..c6efe7c4b4fb 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_mount_accounting_test > > include ../lib.mk > diff --git a/tools/testing/selftests/ve/ve_mount_accounting_test.c b/tools/testing/selftests/ve/ve_mount_accounting_test.c > new file mode 100644 > index 000000000000..e82d9bf23839 > --- /dev/null > +++ b/tools/testing/selftests/ve/ve_mount_accounting_test.c > @@ -0,0 +1,489 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * ve_mount_accounting selftests > + * > + * Tests to check the correctness of mount accounting. > + */ > +#define _GNU_SOURCE > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "../kselftest_harness.h" > +#include "ve_selftest.h" > + > +#define TMP_DIR "/ve-mnt-tmp/" > +#define VE_MOUNTS_MAX 128 > + > +/* > + * These values take a while to calculate, the first test will > + * do this and store the values for those who come after. > + */ > +int *need_avail; > +int *mnt_cost; > + > +FIXTURE(ve_mnt_acc) > +{ > + int cgv2_fd; > + int ctid; > + struct namespace_ctx ns_ctx; > + int orig_have_mnt; > +}; > + > +static int set_pseudosuper(FIXTURE_DATA(ve_mnt_acc) * self, int value) > +{ > + char path[64]; > + > + snprintf(path, sizeof(path), "%d/ve.pseudosuper", self->ctid); > + return write_u64_at(self->cgv2_fd, path, value); > +} > + > +static int _create_mount(void *id_ptr) > +{ > + char path[PATH_MAX]; > + int id = *(int *)id_ptr, ret; > + > + snprintf(path, sizeof(path), TMP_DIR "%d", id); > + > + if (mkdir(path, 0755) < 0) { > + fprintf(stderr, "Failed to create directory %s: %s\n", path, strerror(errno)); > + return -1; > + } > + ret = mount("tmpfs", path, "tmpfs", 0, "size=1M"); > + if (!ret) > + return 0; > + fprintf(stderr, "Failed to mount tmpfs to %s: %s\n", path, strerror(errno)); > + > + rmdir(path); > + return -1; > +} > + > +static int create_mount(FIXTURE_DATA(ve_mnt_acc) * self, int id) > +{ > + int ret = run_in_ve(self->cgv2_fd, self->ctid, &self->ns_ctx, > + CLONE_NEWVE | CLONE_NEWNS, _create_mount, &id); > + /* > + * If mount fails, cleanup by free_vfsmnt will be called > + * via call_rcu, need to wait for update. > + */ > + sleep(1); > + return ret; > +} > + > +static int _destroy_mount(void *id_ptr) > +{ > + char path[PATH_MAX]; > + struct stat st; > + int id = *(int *)id_ptr; > + > + snprintf(path, sizeof(path), TMP_DIR "%d", id); > + > + if (stat(path, &st)) > + return 1; > + if (umount(path)) { > + fprintf(stderr, "failed to umount directory %s: %s\n", path, strerror(errno)); > + return -1; > + } > + if (rmdir(path)) { > + fprintf(stderr, "failed to remove directory %s: %s\n", path, strerror(errno)); > + return -1; > + } > + return 0; > +} > + > +static int destroy_mount(FIXTURE_DATA(ve_mnt_acc) * self, int id) > +{ > + int ret = run_in_ve(self->cgv2_fd, self->ctid, &self->ns_ctx, > + CLONE_NEWVE | CLONE_NEWNS, _destroy_mount, &id); > + /* free_vfsmnt is called via call_rcu, need to wait for update */ > + sleep(1); > + return ret; > +} > + > +#define MAX_MNT_ID 32 > + > +static int get_free_mnt_id(void) > +{ > + int i; > + struct stat st; > + char path[PATH_MAX]; > + > + for (i = 0; i < MAX_MNT_ID; i++) { > + snprintf(path, sizeof(path), TMP_DIR "%d", i); > + if (stat(path, &st)) > + return i; > + } > + return -1; > +} > + > +static int get_mount_cost(FIXTURE_DATA(ve_mnt_acc) * self) > +{ > + int avail1, avail2, mnt_id; > + char path[64]; > + > + mnt_id = get_free_mnt_id(); > + > + snprintf(path, sizeof(path), "%d/ve.mnt_avail_nr", self->ctid); > + if (mnt_id < 0 || > + read_s32_at(self->cgv2_fd, path, &avail1) || > + create_mount(self, mnt_id) || > + read_s32_at(self->cgv2_fd, path, &avail2) || > + destroy_mount(self, mnt_id)) > + return -1; > + > + return avail1 - avail2; > +} > + > +/* > + * Current kernel code first creates many mounts with ve_owner != ve0, > + * so this VE needs more mounts than would be really consumed after commit_tree. > + */ > +static int get_required_avail_mnts(FIXTURE_DATA(ve_mnt_acc) * self) > +{ > + int l = 0, r = VE_MOUNTS_MAX + 1, mid; > + char path_max_nr[64]; > + > + snprintf(path_max_nr, sizeof(path_max_nr), "%d/ve.mnt_max_nr", self->ctid); > + > + while (r - l > 1) { > + mid = (l + r) / 2; > + if (write_u64_at(self->cgv2_fd, path_max_nr, mid + self->orig_have_mnt)) > + return -1; > + > + if (get_mount_cost(self) < 0) > + l = mid; > + else > + r = mid; > + } > + if (r == VE_MOUNTS_MAX + 1) { > + fprintf(stderr, "%s: %d avail mounts is not enough\n", __func__, r); > + return -1; > + } > + if (write_u64_at(self->cgv2_fd, path_max_nr, VE_MOUNTS_MAX)) > + return -1; > + return r; > +} > + > +/* Expect mount success and return new avail value */ > +static int mount_and_get_avail(struct __test_metadata *_metadata, > + FIXTURE_DATA(ve_mnt_acc) * self, int mnt_id) > +{ > + char path_avail[64]; > + int mnt_avail_nr; > + > + snprintf(path_avail, sizeof(path_avail), "%d/ve.mnt_avail_nr", self->ctid); > + > + ASSERT_EQ(create_mount(self, mnt_id), 0); > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path_avail, &mnt_avail_nr), 0); > + return mnt_avail_nr; > +} > + > +/* Expect mount failure and ensure intact avail number */ > +static int check_mount_fails(struct __test_metadata *_metadata, > + FIXTURE_DATA(ve_mnt_acc) * self, > + int mnt_id, int avail_count) > +{ > + char path_avail[64]; > + int mnt_avail_nr; > + > + snprintf(path_avail, sizeof(path_avail), "%d/ve.mnt_avail_nr", self->ctid); > + > + if (read_s32_at(self->cgv2_fd, path_avail, &mnt_avail_nr)) > + return 1; > + if (mnt_avail_nr != avail_count) { > + fprintf(stderr, "%s: mnt_avail(%d) != avail_count(%d) before mount\n", > + __func__, mnt_avail_nr, avail_count); > + return -1; > + } > + > + if (create_mount(self, mnt_id) == 0) { > + fprintf(stderr, "%s: successful mount\n", __func__); > + return -1; > + } > + > + if (read_s32_at(self->cgv2_fd, path_avail, &mnt_avail_nr)) > + return 1; > + if (mnt_avail_nr != avail_count) { > + fprintf(stderr, "%s: mnt_avail(%d) != avail_count(%d) after mount\n", > + __func__, mnt_avail_nr, avail_count); > + return -1; > + } > + return 0; > +} > + > +FIXTURE_SETUP(ve_mnt_acc) > +{ > + int initial_mnt_avail_nr; > + char path[64]; > + > + self->cgv2_fd = mount_cg2_fd(); > + ASSERT_GE(self->cgv2_fd, 0); > + mkdir(TMP_DIR, 0755); > + > + ASSERT_EQ(write_file_at(self->cgv2_fd, "cgroup.subtree_control", > + VE_CONTROLLERS), 0); > + > + self->ctid = make_ve(self->cgv2_fd, CTID_MIN); > + ASSERT_GE(self->ctid, 0); > + > + snprintf(path, sizeof(path), "%d/ve.mnt_max_nr", self->ctid); > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path, VE_MOUNTS_MAX), 0); > + > + /* > + * The new ve cgroup has not been entered by anything yet, so its > + * mnt_avail_nr counter should be VE_MOUNTS_MAX. > + */ > + snprintf(path, sizeof(path), "%d/ve.mnt_avail_nr", self->ctid); > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path, &initial_mnt_avail_nr), 0); > + ASSERT_EQ(initial_mnt_avail_nr, VE_MOUNTS_MAX); > + > + ASSERT_EQ(prepare_namespaces(&self->ns_ctx, CLONE_NEWNS | CLONE_NEWVE, > + self->cgv2_fd, self->ctid), 0); > + > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path, &initial_mnt_avail_nr), 0); > + self->orig_have_mnt = VE_MOUNTS_MAX - initial_mnt_avail_nr; > + > + /* Calculate once - it is time-consuming */ > + if (*need_avail == -1) > + *need_avail = get_required_avail_mnts(self); > + if (*mnt_cost == -1) > + *mnt_cost = get_mount_cost(self); > + ASSERT_GE(*need_avail, 1); > + ASSERT_GE(*mnt_cost, 1); > +}; > + > +FIXTURE_TEARDOWN(ve_mnt_acc) > +{ > + for (int i = 0; i < MAX_MNT_ID; i++) > + _destroy_mount((void *)&i); > + > + close_namespace_fds(&self->ns_ctx); > + destroy_ve(self->cgv2_fd, self->ctid); > + close(self->cgv2_fd); > + rmdir(TMP_DIR); > +} > + > +/* Simple test to check mount/umount accounting correctness */ > +TEST_F(ve_mnt_acc, mount_umount) > +{ > + int original_mnt_avail, mnt_avail_nr; > + char path[64]; > + > + snprintf(path, sizeof(path), "%d/ve.mnt_avail_nr", self->ctid); > + > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path, &original_mnt_avail), 0); > + > + ASSERT_LT(mount_and_get_avail(_metadata, self, 0), > + original_mnt_avail); > + > + ASSERT_EQ(destroy_mount(self, 0), 0); > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path, &mnt_avail_nr), 0); > + ASSERT_EQ(mnt_avail_nr, original_mnt_avail); > +} > + > +/* Test mount limit hits */ > +TEST_F(ve_mnt_acc, hit_limits) > +{ > + int mnt_avail_nr; > + char path_avail[64], path_max_nr[64]; > + > + snprintf(path_avail, sizeof(path_avail), "%d/ve.mnt_avail_nr", self->ctid); > + snprintf(path_max_nr, sizeof(path_max_nr), "%d/ve.mnt_max_nr", self->ctid); > + > + /* Step 1: reduce number of available mounts to *need_avail */ > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_max_nr, > + self->orig_have_mnt + 1 * (*need_avail)), 0); > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path_avail, &mnt_avail_nr), 0); > + ASSERT_EQ(mnt_avail_nr, 1 * *need_avail); > + > + /* Step 2: do one mount, no mounts should be available */ > + ASSERT_EQ(mount_and_get_avail(_metadata, self, 0), *need_avail - *mnt_cost); > + > + /* Step 3: check that one more mount fails */ > + ASSERT_EQ(check_mount_fails(_metadata, self, 1, (*need_avail) - 1), 0); > + > + /* Step 4: increase by 1 and win now */ > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_max_nr, > + self->orig_have_mnt + *mnt_cost + *need_avail), 0); > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path_avail, &mnt_avail_nr), 0); > + ASSERT_EQ(mnt_avail_nr, *need_avail); > + > + ASSERT_EQ(mount_and_get_avail(_metadata, self, 1), *need_avail - *mnt_cost); > + > + /* Step 5: reduce mnt_max_nr so we have more mounts than allowed */ > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_max_nr, > + self->orig_have_mnt + 1 * (*mnt_cost)), 0); > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path_avail, &mnt_avail_nr), 0); > + ASSERT_EQ(mnt_avail_nr, -1 * (*mnt_cost)); > + > + /* Step 6: try to do mount when avail < 0, ensure number is intact */ > + ASSERT_EQ(check_mount_fails(_metadata, self, 2, -1 * (*mnt_cost)), 0); > + > + /* Step 7: remove one mount, check avail value update, mount should fail */ > + ASSERT_EQ(destroy_mount(self, 0), 0); > + ASSERT_EQ(check_mount_fails(_metadata, self, 2, 0), 0); > + > + /* Step 8: remove one more mount and check that new mount succeeds */ > + ASSERT_EQ(destroy_mount(self, 1), 0); > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path_avail, &mnt_avail_nr), 0); > + ASSERT_EQ(mnt_avail_nr, 1 * *mnt_cost); > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_max_nr, self->orig_have_mnt + *need_avail), 0); > + ASSERT_EQ(mount_and_get_avail(_metadata, self, 2), *need_avail - *mnt_cost); > + > + ASSERT_EQ(destroy_mount(self, 2), 0); > +} > + > +/* > + * Mount propagation makes one mount cost more. > + * This test checks that if we run out of mounts in the middle of creating > + * a new one, everything is restored smoothly and nothing leaks. > + */ > +TEST_F(ve_mnt_acc, partial_mounts) > +{ > + char path_avail[64], path_max_nr[64]; > + int i; > + > + snprintf(path_max_nr, sizeof(path_max_nr), "%d/ve.mnt_max_nr", self->ctid); > + snprintf(path_avail, sizeof(path_avail), "%d/ve.mnt_avail_nr", self->ctid); > + > + if (*need_avail == 1) > + SKIP(return, "mount cost is 1, no partial mounts possible"); > + > + for (i = 0; i < *need_avail; i++) { > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_max_nr, self->orig_have_mnt + i), 0); > + ASSERT_EQ(check_mount_fails(_metadata, self, 0, i), 0); > + } > +} > + > +/* Test that pseudosuper allows negative avail with correct accounting. */ > +TEST_F(ve_mnt_acc, pseudosuper_allows_overuse) > +{ > + char path_max_nr[64]; > + > + snprintf(path_max_nr, sizeof(path_max_nr), "%d/ve.mnt_max_nr", self->ctid); > + > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_max_nr, self->orig_have_mnt + *need_avail), 0); > + ASSERT_EQ(set_pseudosuper(self, 1), 0); > + > + ASSERT_EQ(mount_and_get_avail(_metadata, self, 0), *need_avail - *mnt_cost); > + ASSERT_EQ(mount_and_get_avail(_metadata, self, 1), *need_avail - 2 * (*mnt_cost)); > + > + /* Go below zero */ > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_max_nr, self->orig_have_mnt), 0); > + ASSERT_EQ(mount_and_get_avail(_metadata, self, 2), -3 * (*mnt_cost)); > + > + ASSERT_EQ(set_pseudosuper(self, 0), 0); > + > + /* Below zero should fail */ > + ASSERT_EQ(check_mount_fails(_metadata, self, 3, -3 * (*mnt_cost)), 0); > + /* Now need 2 more to add a new mount */ > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_max_nr, > + self->orig_have_mnt + 3 * (*mnt_cost) + *need_avail - 2 * (*mnt_cost)), 0); > + ASSERT_EQ(check_mount_fails(_metadata, self, 3, *need_avail - 2 * (*mnt_cost)), 0); > + > + ASSERT_EQ(destroy_mount(self, 0), 0); > + ASSERT_EQ(check_mount_fails(_metadata, self, 3, *need_avail - *mnt_cost), 0); > + ASSERT_EQ(destroy_mount(self, 2), 0); > + ASSERT_EQ(get_mount_cost(self), *mnt_cost); > +} > + > +/* Test that pseudosuper doesn't disable accounting. */ > +TEST_F(ve_mnt_acc, pseudosuper_continues_accounting) > +{ > + int orig_mnt_avail, mnt_avail_nr; > + char path_avail[64]; > + > + snprintf(path_avail, sizeof(path_avail), "%d/ve.mnt_avail_nr", self->ctid); > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path_avail, &orig_mnt_avail), 0); > + > + ASSERT_EQ(set_pseudosuper(self, 0), 0); > + > + /* mnt 0 - mounted without pseudosuper, umounted with it. */ > + ASSERT_EQ(mount_and_get_avail(_metadata, self, 0), orig_mnt_avail - *mnt_cost); > + ASSERT_EQ(set_pseudosuper(self, 1), 0); > + > + /* Cost is the same when mount/umount happen under pseudosuper. */ > + ASSERT_EQ(get_mount_cost(self), *mnt_cost); > + > + /* mnt 1 - mounted with pseudosuper, umounted without it. */ > + ASSERT_EQ(mount_and_get_avail(_metadata, self, 1), > + orig_mnt_avail - 2 * (*mnt_cost)); > + > + ASSERT_EQ(destroy_mount(self, 0), 0); > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path_avail, &mnt_avail_nr), 0); > + ASSERT_EQ(mnt_avail_nr, orig_mnt_avail - *mnt_cost); > + > + ASSERT_EQ(set_pseudosuper(self, 0), 0); > + > + ASSERT_EQ(destroy_mount(self, 1), 0); > + ASSERT_EQ(read_s32_at(self->cgv2_fd, path_avail, &mnt_avail_nr), 0); > + ASSERT_EQ(mnt_avail_nr, orig_mnt_avail); > +} > + > +/* Test failcount feature */ > +TEST_F(ve_mnt_acc, failcount) > +{ > + char path_fc[64], failcount_str[512], path_max_nr[64]; > + > + snprintf(path_fc, sizeof(path_fc), "%d/ve.failcount", self->ctid); > + snprintf(path_max_nr, sizeof(path_max_nr), "%d/ve.mnt_max_nr", self->ctid); > + > + ASSERT_GE(read_file_at(self->cgv2_fd, path_fc, > + failcount_str, sizeof(failcount_str)), 0); > + ASSERT_TRUE(strstr(failcount_str, "mnt: 0\n") != NULL); > + > + /* Check successful mount doesn't affect failcount */ > + mount_and_get_avail(_metadata, self, 0); > + ASSERT_GE(read_file_at(self->cgv2_fd, path_fc, > + failcount_str, sizeof(failcount_str)), 0); > + ASSERT_TRUE(strstr(failcount_str, "mnt: 0\n") != NULL); > + ASSERT_EQ(destroy_mount(self, 0), 0); > + > + /* Check failcount update when mount fails */ > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_max_nr, 0), 0); > + ASSERT_LT(create_mount(self, 1), 0); > + ASSERT_GE(read_file_at(self->cgv2_fd, path_fc, > + failcount_str, sizeof(failcount_str)), 0); > + ASSERT_TRUE(strstr(failcount_str, "mnt: 1\n") != NULL); > + > + /* Check failcount flush */ > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_fc, 0), 0); > + ASSERT_GE(read_file_at(self->cgv2_fd, path_fc, > + failcount_str, sizeof(failcount_str)), 0); > + ASSERT_TRUE(strstr(failcount_str, "mnt: 0\n") != NULL); > + > + /* Check failcount update when mount fails again */ > + ASSERT_EQ(write_u64_at(self->cgv2_fd, path_max_nr, 0), 0); > + ASSERT_LT(create_mount(self, 1), 0); > + ASSERT_GE(read_file_at(self->cgv2_fd, path_fc, > + failcount_str, sizeof(failcount_str)), 0); > + ASSERT_TRUE(strstr(failcount_str, "mnt: 1\n") != NULL); > +} > + > +int main(int argc, char **argv) > +{ > + int *shared_data = mmap(NULL, sizeof(int) * 2, > + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); > + Better check against MAP_FAILED not NULL -- Vasileios Almpanis _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel