[PATCH v2 1/2] selftests/resctrl: Add L3_CBM_VALIDATE to check CBM writes

Richard Cheng <[email protected]>
Newsgroups org.kernel.vger.linux-kselftest,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Add L3_CBM_VALIDATE to verify that resctrl enforces the L3 CBM rules
advertised by cbm_mask and min_cbm_bits.

Confirm that the full mask is accepted. Check the empty mask according
to min_cbm_bits, and confirm that out-of-range and undersized masks are
rejected.

This catches inconsistencies between the advertised capabilities and
schemata validation.

Signed-off-by: Richard Cheng <[email protected]>
---
Changelog:

v1 -> v2:
    - Rename L3_CAT_VALIDATE to L3_CBM_VALIDATE
    - Handle empty CBMs according to min_cbm_bits
    - Check count_contiguous_bits() before using its result
    - Use KSFT_FAIL and reverse-fir-tree ordering
    - Use a 64-bit out-of-range mask

Best regards,
Richard Cheng.
---
 tools/testing/selftests/resctrl/cat_test.c    | 91 +++++++++++++++++++
 tools/testing/selftests/resctrl/resctrl.h     |  1 +
 .../testing/selftests/resctrl/resctrl_tests.c |  1 +
 3 files changed, 93 insertions(+)

diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c
index 371a2f26dc47..a06c57954740 100644
--- a/tools/testing/selftests/resctrl/cat_test.c
+++ b/tools/testing/selftests/resctrl/cat_test.c
@@ -357,6 +357,89 @@ static bool noncont_cat_feature_check(const struct resctrl_test *test)
 	return resource_info_file_exists(test->resource, "sparse_masks");
 }
 
+/*
+ * L3_CBM_VALIDATE - Verify L3 CBM write validation.
+ *
+ * A full CBM must be accepted. An empty CBM is valid only when min_cbm_bits
+ * is zero. Masks with bits outside cbm_mask or fewer than min_cbm_bits must
+ * be rejected.
+ */
+static int cbm_validate_run_test(const struct resctrl_test *test,
+				 const struct user_params *uparams)
+{
+	unsigned int min_cbm_bits, contiguous_bits;
+	unsigned long long invalid_mask;
+	unsigned int count_of_bits;
+	unsigned long full_mask;
+	unsigned int start;
+	char schemata[64];
+	int ret;
+
+	ret = get_full_cbm(test->resource, &full_mask);
+	if (ret)
+		return ret;
+
+	ret = resource_info_unsigned_get(test->resource, "min_cbm_bits",
+					 &min_cbm_bits);
+	if (ret)
+		return ret;
+
+	count_of_bits = count_bits(full_mask);
+
+	/* A valid full CBM must be accepted. */
+	snprintf(schemata, sizeof(schemata), "%lx", full_mask);
+	if (write_schemata("", schemata, uparams->cpu, test->resource)) {
+		ksft_print_msg("Valid CBM 0x%lx was rejected\n", full_mask);
+		return KSFT_FAIL;
+	}
+
+	ret = write_schemata("", "0", uparams->cpu, test->resource);
+	if (min_cbm_bits && !ret) {
+		ksft_print_msg("Empty CBM was accepted, must be rejected\n");
+		return KSFT_FAIL;
+	}
+	if (!min_cbm_bits && ret) {
+		ksft_print_msg("Empty CBM was rejected, must be accepted\n");
+		return KSFT_FAIL;
+	}
+
+	/* A mask with a bit outside cbm_mask must be rejected. */
+	invalid_mask = (unsigned long long)full_mask | (1ULL << count_of_bits);
+	snprintf(schemata, sizeof(schemata), "%llx", invalid_mask);
+	if (!write_schemata("", schemata, uparams->cpu, test->resource)) {
+		ksft_print_msg("Out-of-range CBM 0x%llx was accepted, must be rejected\n",
+			       invalid_mask);
+		return KSFT_FAIL;
+	}
+
+	/*
+	 * When min_cbm_bits is greater than one, a non-empty mask with fewer
+	 * bits must be rejected.
+	 */
+	if (min_cbm_bits > 1) {
+		contiguous_bits = count_contiguous_bits(full_mask, &start);
+		if (contiguous_bits < min_cbm_bits) {
+			ksft_print_msg("Full CBM has %u contiguous bits, fewer than "
+				       "min_cbm_bits=%u\n",
+				       contiguous_bits, min_cbm_bits);
+			return KSFT_FAIL;
+		}
+
+		invalid_mask = create_bit_mask(start, min_cbm_bits - 1);
+		snprintf(schemata, sizeof(schemata), "%llx", invalid_mask);
+		if (!write_schemata("", schemata, uparams->cpu,
+				    test->resource)) {
+			ksft_print_msg("CBM 0x%llx with too few bits was accepted\n",
+				       invalid_mask);
+			return KSFT_FAIL;
+		}
+	}
+
+	ksft_print_msg("Pass: L3 CBM writes were validated correctly\n");
+
+	return 0;
+}
+
 struct resctrl_test l3_cat_test = {
 	.name = "L3_CAT",
 	.group = "CAT",
@@ -366,6 +449,14 @@ struct resctrl_test l3_cat_test = {
 	.cleanup = cat_test_cleanup,
 };
 
+struct resctrl_test l3_cbm_validate_test = {
+	.name = "L3_CBM_VALIDATE",
+	.group = "CAT",
+	.resource = "L3",
+	.feature_check = test_resource_feature_check,
+	.run_test = cbm_validate_run_test,
+};
+
 struct resctrl_test l3_noncont_cat_test = {
 	.name = "L3_NONCONT_CAT",
 	.group = "CAT",
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index 175101022bf3..a6fc688ed997 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -240,6 +240,7 @@ extern struct resctrl_test mbm_test;
 extern struct resctrl_test mba_test;
 extern struct resctrl_test cmt_test;
 extern struct resctrl_test l3_cat_test;
+extern struct resctrl_test l3_cbm_validate_test;
 extern struct resctrl_test l3_noncont_cat_test;
 extern struct resctrl_test l2_noncont_cat_test;
 
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
index dbcd5eea9fbc..57a4d0815b67 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -19,6 +19,7 @@ static struct resctrl_test *resctrl_tests[] = {
 	&mba_test,
 	&cmt_test,
 	&l3_cat_test,
+	&l3_cbm_validate_test,
 	&l3_noncont_cat_test,
 	&l2_noncont_cat_test,
 };
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.