MB cpas are per control group, implement MBA_SCHEMATA_ISOLATE test to verify a write to one group leaves other groups and the default group untouched.
Create 2 groups, set the first to the max and the second to a lower cap, then read the first after writing the second, each holds its own value. The default group stays unchanged. The lower cap is gran-aligned and at or above min_bandwidth, so read-back is exact and provably below the maximum. Signed-off-by: Richard Cheng <[email protected]> --- .../selftests/resctrl/mba_schemata_test.c | 131 ++++++++++++++++++ tools/testing/selftests/resctrl/resctrl.h | 1 + .../testing/selftests/resctrl/resctrl_tests.c | 1 + 3 files changed, 133 insertions(+) diff --git a/tools/testing/selftests/resctrl/mba_schemata_test.c b/tools/testing/selftests/resctrl/mba_schemata_test.c index 0cd257dcec91..d98946b831b1 100644 --- a/tools/testing/selftests/resctrl/mba_schemata_test.c +++ b/tools/testing/selftests/resctrl/mba_schemata_test.c @@ -388,3 +388,134 @@ struct resctrl_test mba_schemata_inval_test = { .feature_check = mba_schemata_feature_check, .run_test = mba_schemata_inval_run_test, }; + +/* + * MB allocations are per control group: two groups hold different + * percentages on the same domain without disturbing each other or the + * default group. + */ +static int mba_schemata_isolate_run_test(const struct resctrl_test *test, + const struct user_params *uparams) +{ + unsigned int gran, min_bw, low, num_closids, def_before = 0, def_after = 0; + unsigned int got1 = 0, got2 = 0, pct[MB_MAX_DOMAINS]; + int ids[MB_MAX_DOMAINS], n, ret, dom, fail = 0; + char vals[MB_SCHEMATA_LEN], path1[256], path2[256], line[64]; + const char *grp1 = "mba_schemata_iso1", *grp2 = "mba_schemata_iso2"; + + /* + * Isolation works with any CLOSID count, but the + * default group plus the two test groups each need to hold one. + */ + if (resource_info_unsigned_get(test->resource, "num_closids", &num_closids)) + return 1; + if (num_closids < 3) { + ksft_print_msg("Skipping: num_closids=%u < 3, cannot create two test groups\n", + num_closids); + return 0; + } + + if (resource_info_unsigned_get(test->resource, "bandwidth_gran", &gran) || !gran) + return 1; + if (resource_info_unsigned_get(test->resource, "min_bandwidth", &min_bw)) + return 1; + + /* Enumerate the real MB domain ids from the default schemata. */ + ret = resctrl_get_schemata("", test->resource, vals, sizeof(vals)); + if (ret) { + ksft_print_msg("Fail: could not read %s schemata line (ret=%d)\n", + test->resource, ret); + return 1; + } + n = parse_mb_schemata(vals, ids, pct, MB_MAX_DOMAINS); + if (n < 1) { + ksft_print_msg("Fail: could not parse %s schemata \"%s\"\n", + test->resource, vals); + return 1; + } + dom = ids[0]; + + /* + * grp2's cap must stay provably below grp1's 100% even after the + * kernel rounds it to bandwidth_gran: align it here, at or above + * min_bandwidth, and expect an exact read-back. If no aligned value + * below the maximum exists, the two groups cannot be told apart. + */ + low = min_bw > 20 ? min_bw : 20; + low = (low + gran - 1) / gran * gran; + if (low >= MB_PERCENT_MAX) { + ksft_print_msg("Skipping: no %s cap below %u representable (min_bw=%u, gran=%u)\n", + test->resource, MB_PERCENT_MAX, min_bw, gran); + return 0; + } + + if (mb_read_domain("", test->resource, dom, &def_before)) { + ksft_print_msg("Fail: read default group %s domain %d\n", + test->resource, dom); + return 1; + } + + snprintf(path1, sizeof(path1), "%s/%s", RESCTRL_PATH, grp1); + if (mkdir(path1, 0755) && errno != EEXIST) { + ksft_print_msg("Fail: mkdir %s: %m\n", path1); + return 1; + } + snprintf(path2, sizeof(path2), "%s/%s", RESCTRL_PATH, grp2); + if (mkdir(path2, 0755) && errno != EEXIST) { + ksft_print_msg("Fail: mkdir %s: %m\n", path2); + rmdir(path1); + return 1; + } + + /* Pin the two groups to different caps on the same domain. */ + snprintf(line, sizeof(line), "%s:%d=%u", + test->resource, dom, MB_PERCENT_MAX); + ret = resctrl_write_schemata(grp1, line); + if (ret) { + ksft_print_msg("Fail: write \"%s\" to %s (ret=%d)\n", + line, grp1, ret); + fail = 1; + } + snprintf(line, sizeof(line), "%s:%d=%u", test->resource, dom, low); + ret = resctrl_write_schemata(grp2, line); + if (ret) { + ksft_print_msg("Fail: write \"%s\" to %s (ret=%d)\n", + line, grp2, ret); + fail = 1; + } + + /* Each group keeps its own cap; reading g1 after writing g2. */ + if (mb_read_domain(grp1, test->resource, dom, &got1) || + got1 != MB_PERCENT_MAX) { + ksft_print_msg("Fail: %s domain %d: %u%%, expected %u%%\n", + grp1, dom, got1, MB_PERCENT_MAX); + fail = 1; + } + if (mb_read_domain(grp2, test->resource, dom, &got2) || + got2 != low) { + ksft_print_msg("Fail: %s domain %d: %u%%, expected %u%%\n", + grp2, dom, got2, low); + fail = 1; + } + + /* The default group must be untouched by either write. */ + if (mb_read_domain("", test->resource, dom, &def_after) || + def_after != def_before) { + ksft_print_msg("Fail: default group domain %d changed %u%% -> %u%%\n", + dom, def_before, def_after); + fail = 1; + } + + rmdir(path1); + rmdir(path2); + + return fail; +} + +struct resctrl_test mba_schemata_isolate_test = { + .name = "MBA_SCHEMATA_ISOLATE", + .group = "MBA_SCHEMATA", + .resource = "MB", + .feature_check = mba_schemata_feature_check, + .run_test = mba_schemata_isolate_run_test, +}; diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h index c32ab5c2cc56..07a67ac9292c 100644 --- a/tools/testing/selftests/resctrl/resctrl.h +++ b/tools/testing/selftests/resctrl/resctrl.h @@ -252,5 +252,6 @@ extern struct resctrl_test l2_noncont_cat_test; extern struct resctrl_test mba_schemata_info_test; extern struct resctrl_test mba_schemata_rw_test; extern struct resctrl_test mba_schemata_inval_test; +extern struct resctrl_test mba_schemata_isolate_test; #endif /* RESCTRL_H */ diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c index 7a7184783e6a..583ee97bac20 100644 --- a/tools/testing/selftests/resctrl/resctrl_tests.c +++ b/tools/testing/selftests/resctrl/resctrl_tests.c @@ -24,6 +24,7 @@ static struct resctrl_test *resctrl_tests[] = { &mba_schemata_info_test, &mba_schemata_rw_test, &mba_schemata_inval_test, + &mba_schemata_isolate_test, }; static unsigned int detect_vendor(void) -- 2.43.0

