From 066ead4d1eecd0e3586582b4866f12b1a1a8f628 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Mon, 14 Apr 2025 17:31:09 -0600 Subject: [PATCH] LU-15762 tests: skip llapi_hsm_test113 on old server Skip sanity-hsm test_500 sub-subtest 113 for old server interop. This requires adding some infrastructure to allow skipping some sub-subtests in llapi_hsm_test.c. Moved from llapi_layout_test.c to llapi_test_utils.c and enhanced to allow non-contiguous test numbering and sharing between test files. Modify llapi_layout_test.c to include these same improvements. Update code style in sanity-hsm test_500 and sanity test_27D so both modified test programs run in review-subtest-change sessions. Fix version check in sanity/27D that always skipped sub-subtest 34. Test-Parameters: trivial testlist=sanity-hsm env=ONLY=500 serverversion=2.14 Fixes: f684172237 ("LU-11085 mdt: revise recording of hsm progress updates.") Signed-off-by: Andreas Dilger Change-Id: I1d234632444404346142e45e74b61ffbe6500c1e Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/58786 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Jian Yu Reviewed-by: Rajeev Mishra Reviewed-by: Nikitas Angelinas Reviewed-by: Oleg Drokin --- lustre/tests/Makefile.am | 2 + lustre/tests/llapi_hsm_test.c | 251 +++++++++++--------------------- lustre/tests/llapi_layout_test.c | 300 ++++++++------------------------------- lustre/tests/llapi_test_utils.c | 194 +++++++++++++++++++++++++ lustre/tests/llapi_test_utils.h | 48 +++++++ lustre/tests/sanity-hsm.sh | 24 ++-- lustre/tests/sanity.sh | 25 ++-- 7 files changed, 411 insertions(+), 433 deletions(-) create mode 100644 lustre/tests/llapi_test_utils.c create mode 100644 lustre/tests/llapi_test_utils.h diff --git a/lustre/tests/Makefile.am b/lustre/tests/Makefile.am index 9c8d166..47c55c0 100644 --- a/lustre/tests/Makefile.am +++ b/lustre/tests/Makefile.am @@ -108,7 +108,9 @@ endif # NO_STRINGOP_OVERFLOW mmap_sanity_LDADD = $(LIBLUSTREAPI) $(PTHREAD_LIBS) multiop_LDADD = $(LIBLUSTREAPI) $(PTHREAD_LIBS) +llapi_layout_test_SOURCES = llapi_layout_test.c llapi_test_utils.c llapi_test_utils.h llapi_layout_test_LDADD = $(LIBLUSTREAPI) +llapi_hsm_test_SOURCES = llapi_hsm_test.c llapi_test_utils.c llapi_test_utils.h llapi_hsm_test_LDADD = $(LIBLUSTREAPI) group_lock_test_LDADD = $(LIBLUSTREAPI) llapi_fid_test_LDADD = $(LIBLUSTREAPI) diff --git a/lustre/tests/llapi_hsm_test.c b/lustre/tests/llapi_hsm_test.c index 890fb4a..e5a3364 100644 --- a/lustre/tests/llapi_hsm_test.c +++ b/lustre/tests/llapi_hsm_test.c @@ -1,85 +1,33 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright 2014, 2015 Cray Inc, all rights reserved. - * * Copyright (c) 2015, Intel Corporation. - */ -/* Some portions are extracted from llapi_layout_test.c */ - -/* The purpose of this test is to check some HSM functions. HSM must - * be enabled before running it: - * lctl set_param mdt.$FSNAME-MDT0000.hsm_control=enabled + * Copyright (c) 2025, DataDirect Networks, Inc. All rights reserved. */ -/* All tests return 0 on success and non zero on error. The program will - * exit as soon a non zero error is returned. - */ -#include #include #include -#include -#include #include -#include +#include +#include +#include #include +#include "llapi_test_utils.h" -static char fsmountdir[PATH_MAX]; /* Lustre mountpoint */ -static char *lustre_dir; /* Test directory inside Lustre */ -static bool is_bitmap; - -#define ERROR(fmt, ...) \ - fprintf(stderr, "%s: %s:%d: %s: " fmt "\n", \ - program_invocation_short_name, __FILE__, __LINE__, \ - __func__, ## __VA_ARGS__); - -#define DIE(fmt, ...) \ - do { \ - ERROR(fmt, ## __VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } while (0) - -#define ASSERTF(cond, fmt, ...) \ - do { \ - if (!(cond)) \ - DIE("assertion '%s' failed: "fmt, \ - #cond, ## __VA_ARGS__); \ - } while (0) \ - -#define PERFORM(testfn) \ - do { \ - fprintf(stderr, "Starting test " #testfn " at %llu\n", \ - (unsigned long long)time(NULL)); \ - testfn(); \ - fprintf(stderr, "Finishing test " #testfn " at %llu\n", \ - (unsigned long long)time(NULL)); \ - } while (0) - -/* Register and unregister 2000 times. Ensures there is no fd leak - * since there is usually 1024 fd per process. - */ -static int test1(void) +static bool is_bitmap; /* use old bitmap interface */ +static char lustre_dir[PATH_MAX - 5]; /* Lustre test directory */ + +static void usage(char *prog) +{ + printf("Usage: %s [-d LUSTRE_DIR] [-s SKIP[,SKIP...]] [-t ONLY[,ONLY...]\n", + prog); + exit(0); +} + +#define T1_DESC "Register/unregister copytool 2000x to check for leaks" +static void test1(void) { int i; int rc; @@ -97,12 +45,10 @@ static int test1(void) "llapi_hsm_copytool_unregister failed: %s, loop=%d", strerror(-rc), i); } - - return 0; } -/* Re-register */ -static int test2(void) +#define T2_DESC "Re/un-register copytool multiple times without error" +static void test2(void) { int rc; struct hsm_copytool_private *ctdata1; @@ -123,12 +69,10 @@ static int test2(void) rc = llapi_hsm_copytool_unregister(&ctdata1); ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s", strerror(-rc)); - - return 0; } -/* Bad parameters to llapi_hsm_copytool_register(). */ -static int test3(void) +#define T3_DESC "Pass bad parameters to llapi_hsm_copytool_register()" +static void test3(void) { int rc; struct hsm_copytool_private *ctdata; @@ -169,24 +113,20 @@ static int test3(void) rc = llapi_hsm_copytool_register(&ctdata, "/tmp", 0, NULL, 0); ASSERTF(rc == -ENOENT, "llapi_hsm_copytool_register error: %s", strerror(-rc)); - - return 0; } -/* Bad parameters to llapi_hsm_copytool_unregister(). */ -static int test4(void) +#define T4_DESC "Bad parameters to llapi_hsm_copytool_unregister()" +static void test4(void) { int rc; rc = llapi_hsm_copytool_unregister(NULL); ASSERTF(rc == -EINVAL, "llapi_hsm_copytool_unregister error: %s", strerror(-rc)); - - return 0; } -/* Test llapi_hsm_copytool_recv in non blocking mode */ -static int test5(void) +#define T5_DESC "Test llapi_hsm_copytool_recv() in non-blocking mode" +static void test5(void) { int rc; int i; @@ -209,12 +149,10 @@ static int test5(void) rc = llapi_hsm_copytool_unregister(&ctdata); ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s", strerror(-rc)); - - return 0; } -/* Test llapi_hsm_copytool_recv with bogus parameters */ -static int test6(void) +#define T6_DESC "Test llapi_hsm_copytool_recv() with bogus parameters" +static void test6(void) { struct hsm_copytool_private *ctdata; struct hsm_action_list *hal; @@ -244,12 +182,10 @@ static int test6(void) rc = llapi_hsm_copytool_unregister(&ctdata); ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s", strerror(-rc)); - - return 0; } -/* Test polling (without actual traffic) */ -static int test7(void) +#define T7_DESC "Test event polling (without actual traffic)" +static void test7(void) { int rc; struct hsm_copytool_private *ctdata; @@ -285,8 +221,6 @@ static int test7(void) rc = llapi_hsm_copytool_unregister(&ctdata); ASSERTF(rc == 0, "llapi_hsm_copytool_unregister failed: %s", strerror(-rc)); - - return 0; } /* Create the testfile of a given length. It returns a valid file descriptor. */ @@ -317,7 +251,7 @@ static int create_testfile(size_t length) return fd; } -/* Test llapi_hsm_state_get. */ +#define T50_DESC "Test llapi_hsm_state_get()/get_fd()" static void test50(void) { struct hsm_user_state hus; @@ -358,7 +292,7 @@ static void test50(void) hus.hus_in_progress_action); } -/* Test llapi_hsm_state_set. */ +#define T51_DESC "Test llapi_hsm_state_set_fd()" static void test51(void) { int rc; @@ -488,7 +422,7 @@ static void test51(void) close(fd); } -/* Test llapi_hsm_current_action */ +#define T52_DESC "Test llapi_hsm_current_action()" static void test52(void) { int rc; @@ -589,7 +523,7 @@ static void helper_archiving(void (*progress) "state=%u", hus.hus_states); } -/* Simple archive. No progress. */ +#define T100_DESC "Simple archive creation with no progress reported." static void test100(void) { const size_t length = 100; @@ -597,7 +531,7 @@ static void test100(void) helper_archiving(NULL, length); } -/* Archive, with a report every byte. */ +#define T101_DESC "Simple archive creation with progress every byte." static void test101_progress(struct hsm_copyaction_private *hcp, size_t length) { int i; @@ -632,7 +566,7 @@ static void test101(void) helper_archiving(test101_progress, length); } -/* Archive, with a report every byte, backwards. */ +#define T102_DESC "Archive creation with progress every byte, backwards" static void test102_progress(struct hsm_copyaction_private *hcp, size_t length) { int i; @@ -667,7 +601,7 @@ static void test102(void) helper_archiving(test102_progress, length); } -/* Archive, with a single report. */ +#define T103_DESC "Archive creation with a single progress report" static void test103_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -698,7 +632,7 @@ static void test103(void) helper_archiving(test103_progress, length); } -/* Archive, with 2 reports. */ +#define T104_DESC "Archive creation with two progress reports" static void test104_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -735,7 +669,7 @@ static void test104(void) helper_archiving(test104_progress, length); } -/* Archive, with 1 bogus report. */ +#define T105_DESC "Archive creation with one bogus progress report" static void test105_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -768,7 +702,7 @@ static void test105(void) helper_archiving(test105_progress, length); } -/* Archive, with 1 empty report. */ +#define T106_DESC "Archive creation with one empty progress report" static void test106_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -799,7 +733,7 @@ static void test106(void) helper_archiving(test106_progress, length); } -/* Archive, with 1 bogus report. */ +#define T107_DESC "Archive creation with one bogus progress report" static void test107_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -830,7 +764,7 @@ static void test107(void) helper_archiving(test107_progress, length); } -/* Archive, with same report, many times. */ +#define T108_DESC "Archive creation with same progress report each time" static void test108_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -864,7 +798,7 @@ static void test108(void) helper_archiving(test108_progress, length); } -/* Archive, 1 report, with large number. */ +#define T109_DESC "Archive creation with one report, with large number" static void test109_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -895,7 +829,7 @@ static void test109(void) helper_archiving(test109_progress, length); } -/* Archive, with 10 reports, checking progress. */ +#define T110_DESC "Archive with 10 progress reports, checking progress" static void test110_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -930,7 +864,7 @@ static void test110(void) helper_archiving(test110_progress, length); } -/* Archive, with 10 reports in reverse order, checking progress. */ +#define T111_DESC "Archive with 10 reports in reverse, checking progress" static void test111_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -965,7 +899,7 @@ static void test111(void) helper_archiving(test111_progress, length); } -/* Archive, with 10 reports, and duplicating them, checking progress. */ +#define T112_DESC "Archive with 10 reports, duplicated, check progress" static void test112_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -1019,7 +953,7 @@ static void test112(void) helper_archiving(test112_progress, length); } -/* Archive, with 9 reports, each covering 20%, so many overlap. */ +#define T113_DESC "Archive with 9 reports, with 20% overlapping coverage" static void test113_progress(struct hsm_copyaction_private *hcp, size_t length) { int rc; @@ -1054,23 +988,52 @@ static void test113(void) helper_archiving(test113_progress, length); } -static void usage(char *prog) -{ - fprintf(stderr, "Usage: %s [-d lustre_dir]\n", prog); - exit(EXIT_FAILURE); -} +static struct test_tbl_entry test_tbl[] = { + TEST_REGISTER(1), + TEST_REGISTER(2), + TEST_REGISTER(3), + TEST_REGISTER(4), + TEST_REGISTER(5), + TEST_REGISTER(6), + TEST_REGISTER(7), + TEST_REGISTER(50), + TEST_REGISTER(51), + TEST_REGISTER(52), + TEST_REGISTER(100), + TEST_REGISTER(101), + TEST_REGISTER(102), + TEST_REGISTER(103), + TEST_REGISTER(104), + TEST_REGISTER(105), + TEST_REGISTER(106), + TEST_REGISTER(107), + TEST_REGISTER(108), + TEST_REGISTER(109), + TEST_REGISTER(110), + TEST_REGISTER(111), + TEST_REGISTER(112), + TEST_REGISTER(113), + TEST_REGISTER_END +}; static void process_args(int argc, char *argv[]) { int c; - while ((c = getopt(argc, argv, "bd:")) != -1) { + while ((c = getopt(argc, argv, "bd:s:t:")) != -1) { switch (c) { - case 'd': - lustre_dir = optarg; - break; case 'b': is_bitmap = true; + case 'd': + if (snprintf(lustre_dir, sizeof(lustre_dir), "%s", + optarg) >= sizeof(lustre_dir)) + DIE("Error: test directory name too long\n"); + break; + case 's': + set_tests_to_skip(optarg, test_tbl); + break; + case 't': + set_tests_to_run(optarg, test_tbl); break; case '?': default: @@ -1083,49 +1046,7 @@ static void process_args(int argc, char *argv[]) int main(int argc, char *argv[]) { - char fsname[8 + 1]; - int rc; - process_args(argc, argv); - if (lustre_dir == NULL) - lustre_dir = "/mnt/lustre"; - - rc = llapi_search_mounts(lustre_dir, 0, fsmountdir, fsname); - if (rc != 0) { - fprintf(stderr, "Error: %s: not a Lustre filesystem\n", - lustre_dir); - return EXIT_FAILURE; - } - /* Play nice with Lustre test scripts. Non-line buffered output - * stream under I/O redirection may appear incorrectly. - */ - setvbuf(stdout, NULL, _IOLBF, 0); - - PERFORM(test1); - PERFORM(test2); - PERFORM(test3); - PERFORM(test4); - PERFORM(test5); - PERFORM(test6); - PERFORM(test7); - PERFORM(test50); - PERFORM(test51); - PERFORM(test52); - PERFORM(test100); - PERFORM(test101); - PERFORM(test102); - PERFORM(test103); - PERFORM(test104); - PERFORM(test105); - PERFORM(test106); - PERFORM(test107); - PERFORM(test108); - PERFORM(test109); - PERFORM(test110); - PERFORM(test111); - PERFORM(test112); - PERFORM(test113); - - return EXIT_SUCCESS; + return run_tests(lustre_dir, test_tbl); } diff --git a/lustre/tests/llapi_layout_test.c b/lustre/tests/llapi_layout_test.c index 0e16f1b..b4d45a0 100644 --- a/lustre/tests/llapi_layout_test.c +++ b/lustre/tests/llapi_layout_test.c @@ -1,26 +1,7 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016, 2017, Intel Corporation. + * Copyright (c) 2025, DataDirect Networks, Inc. All rights reserved. */ /* * These tests exercise the llapi_layout API which abstracts the layout @@ -34,47 +15,25 @@ * sudo ./llapi_layout_test */ -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include +#include #include #include +#include +#include +#include #include +#include -#define ERROR(fmt, ...) \ - fprintf(stderr, "%s: %s:%d: %s: " fmt "\n", \ - program_invocation_short_name, __FILE__, __LINE__, \ - __func__, ## __VA_ARGS__); - -#define DIE(fmt, ...) \ -do { \ - ERROR(fmt, ## __VA_ARGS__); \ - exit(EXIT_FAILURE); \ -} while (0) +#include +#include "llapi_test_utils.h" -#define ASSERTF(cond, fmt, ...) \ -do { \ - if (!(cond)) \ - DIE("assertion '%s' failed: "fmt, #cond, ## __VA_ARGS__);\ -} while (0) \ +static char *poolname = "testpool"; +static int num_osts = 2; +static char lustre_dir[PATH_MAX - 5]; /* Lustre test directory */ #define IN_RANGE(value, low, high) ((value >= low) && (value <= high)) -static char *lustre_dir; -static char *poolname; -static bool run_list_provided; -static int num_osts = -1; - static void usage(char *prog) { printf("Usage: %s [-d lustre_dir] [-p pool_name] [-o num_osts] " @@ -1751,155 +1710,45 @@ static void test34(void) ASSERTF(rc == 0, "errno %d", errno); } -#define TEST_DESC_LEN 80 -struct test_tbl_entry { - void (*tte_fn)(void); - char tte_desc[TEST_DESC_LEN]; - bool tte_skip; -}; - static struct test_tbl_entry test_tbl[] = { - { .tte_fn = &test0, .tte_desc = T0_DESC, .tte_skip = false }, - { .tte_fn = &test1, .tte_desc = T1_DESC, .tte_skip = false }, - { .tte_fn = &test2, .tte_desc = T2_DESC, .tte_skip = false }, - { .tte_fn = &test3, .tte_desc = T3_DESC, .tte_skip = false }, - { .tte_fn = &test4, .tte_desc = T4_DESC, .tte_skip = false }, - { .tte_fn = &test5, .tte_desc = T5_DESC, .tte_skip = false }, - { .tte_fn = &test6, .tte_desc = T6_DESC, .tte_skip = false }, - { .tte_fn = &test7, .tte_desc = T7_DESC, .tte_skip = false }, - { .tte_fn = &test8, .tte_desc = T8_DESC, .tte_skip = false }, - { .tte_fn = &test9, .tte_desc = T9_DESC, .tte_skip = false }, - { .tte_fn = &test10, .tte_desc = T10_DESC, .tte_skip = false }, - { .tte_fn = &test11, .tte_desc = T11_DESC, .tte_skip = false }, - { .tte_fn = &test12, .tte_desc = T12_DESC, .tte_skip = false }, - { .tte_fn = &test13, .tte_desc = T13_DESC, .tte_skip = false }, - { .tte_fn = &test14, .tte_desc = T14_DESC, .tte_skip = false }, - { .tte_fn = &test15, .tte_desc = T15_DESC, .tte_skip = false }, - { .tte_fn = &test16, .tte_desc = T16_DESC, .tte_skip = false }, - { .tte_fn = &test17, .tte_desc = T17_DESC, .tte_skip = false }, - { .tte_fn = &test18, .tte_desc = T18_DESC, .tte_skip = false }, - { .tte_fn = &test19, .tte_desc = T19_DESC, .tte_skip = false }, - { .tte_fn = &test20, .tte_desc = T20_DESC, .tte_skip = false }, - { .tte_fn = &test21, .tte_desc = T21_DESC, .tte_skip = false }, - { .tte_fn = &test22, .tte_desc = T22_DESC, .tte_skip = false }, - { .tte_fn = &test23, .tte_desc = T23_DESC, .tte_skip = false }, - { .tte_fn = &test24, .tte_desc = T24_DESC, .tte_skip = false }, - { .tte_fn = &test25, .tte_desc = T25_DESC, .tte_skip = false }, - { .tte_fn = &test26, .tte_desc = T26_DESC, .tte_skip = false }, - { .tte_fn = &test27, .tte_desc = T27_DESC, .tte_skip = false }, - { .tte_fn = &test28, .tte_desc = T28_DESC, .tte_skip = false }, - { .tte_fn = &test29, .tte_desc = T29_DESC, .tte_skip = false }, - { .tte_fn = &test30, .tte_desc = T30_DESC, .tte_skip = false }, - { .tte_fn = &test31, .tte_desc = T31_DESC, .tte_skip = false }, - { .tte_fn = &test32, .tte_desc = T32_DESC, .tte_skip = false }, - { .tte_fn = &test33, .tte_desc = T33_DESC, .tte_skip = false }, - { .tte_fn = &test34, .tte_desc = T34_DESC, .tte_skip = false }, + TEST_REGISTER(0), + TEST_REGISTER(1), + TEST_REGISTER(2), + TEST_REGISTER(3), + TEST_REGISTER(4), + TEST_REGISTER(5), + TEST_REGISTER(6), + TEST_REGISTER(7), + TEST_REGISTER(8), + TEST_REGISTER(9), + TEST_REGISTER(10), + TEST_REGISTER(11), + TEST_REGISTER(12), + TEST_REGISTER(13), + TEST_REGISTER(14), + TEST_REGISTER(15), + TEST_REGISTER(16), + TEST_REGISTER(17), + TEST_REGISTER(18), + TEST_REGISTER(19), + TEST_REGISTER(20), + TEST_REGISTER(21), + TEST_REGISTER(22), + TEST_REGISTER(23), + TEST_REGISTER(24), + TEST_REGISTER(25), + TEST_REGISTER(26), + TEST_REGISTER(27), + TEST_REGISTER(28), + TEST_REGISTER(29), + TEST_REGISTER(30), + TEST_REGISTER(31), + TEST_REGISTER(32), + TEST_REGISTER(33), + TEST_REGISTER(34), + TEST_REGISTER_END }; -#define NUM_TESTS (sizeof(test_tbl) / sizeof(struct test_tbl_entry)) - -static void print_test_desc(int test_num, const char *test_desc, - const char *status) -{ - int i; - - printf(" test %2d: %s ", test_num, test_desc); - for (i = 0; i < TEST_DESC_LEN - strlen(test_desc); i++) - printf("."); - printf(" %s\n", status); -} - -/* This function runs a single test by forking the process. This way, - * if there is a segfault during a test, the test program won't crash. - */ -static int test(void (*test_fn)(), const char *test_desc, bool test_skip, - int test_num) -{ - int rc = 0; - pid_t pid; - char status_buf[128]; - - if (test_skip) { - if (!run_list_provided) - print_test_desc(test_num, test_desc, "skip"); - return 0; - } - - pid = fork(); - if (pid < 0) { - ERROR("cannot fork: %s", strerror(errno)); - } else if (pid > 0) { - int status = 0; - - /* Non-zero value indicates failure. */ - wait(&status); - if (status == 0) { - strncpy(status_buf, "pass", sizeof(status_buf)); - } else if WIFSIGNALED(status) { - snprintf(status_buf, sizeof(status_buf), - "fail (exit status %d, killed by SIG%d)", - WEXITSTATUS(status), WTERMSIG(status)); - rc = -1; - } else { - snprintf(status_buf, sizeof(status_buf), - "fail (exit status %d)", WEXITSTATUS(status)); - rc = -1; - } - print_test_desc(test_num, test_desc, status_buf); - } else if (pid == 0) { - /* Run the test in the child process. Exit with 0 for success, - * non-zero for failure - */ - test_fn(); - exit(0); - } - - return rc; -} - -/* 'str_tests' are the tests to be skipped, such as "1,3,4,.." */ -static void set_tests_skipped(char *str_tests) -{ - char *ptr = str_tests; - int tstno; - - if (ptr == NULL || strlen(ptr) == 0) - return; - - while (*ptr != '\0') { - tstno = strtoul(ptr, &ptr, 0); - if (tstno >= 0 && tstno < NUM_TESTS) - test_tbl[tstno].tte_skip = true; - if (*ptr == ',') - ptr++; - else - break; - } -} - -static void set_tests_to_run(char *str_tests) -{ - char *ptr = str_tests; - int tstno; - int i = 0; - - if (ptr == NULL || strlen(ptr) == 0) - return; - - for (i = 0; i < NUM_TESTS ; i++) - test_tbl[i].tte_skip = true; - - while (*ptr != '\0') { - tstno = strtoul(ptr, &ptr, 0); - if (tstno >= 0 && tstno < NUM_TESTS) - test_tbl[tstno].tte_skip = false; - if (*ptr == ',') - ptr++; - else - break; - } -} - static void process_args(int argc, char *argv[]) { int c; @@ -1907,20 +1756,23 @@ static void process_args(int argc, char *argv[]) while ((c = getopt(argc, argv, "d:p:o:s:t:")) != -1) { switch (c) { case 'd': - lustre_dir = optarg; + if (snprintf(lustre_dir, sizeof(lustre_dir), "%s", + optarg) >= sizeof(lustre_dir)) + DIE("Error: test directory name too long\n"); break; case 'p': poolname = optarg; break; case 'o': num_osts = atoi(optarg); + if (num_osts < 2) + DIE("Error: at least 2 OSTS are required\n"); break; case 's': - set_tests_skipped(optarg); + set_tests_to_skip(optarg, test_tbl); break; case 't': - run_list_provided = true; - set_tests_to_run(optarg); + set_tests_to_run(optarg, test_tbl); break; case '?': fprintf(stderr, "Unknown option '%c'\n", optopt); @@ -1931,47 +1783,7 @@ static void process_args(int argc, char *argv[]) int main(int argc, char *argv[]) { - int rc = 0; - int i; - struct stat s; - char fsname[8 + 1]; - - llapi_msg_set_level(LLAPI_MSG_OFF); - process_args(argc, argv); - if (lustre_dir == NULL) - lustre_dir = "/mnt/lustre"; - if (poolname == NULL) - poolname = "testpool"; - if (num_osts == -1) - num_osts = 2; - - if (num_osts < 2) - DIE("Error: at least 2 OSTS are required\n"); - - if (stat(lustre_dir, &s) < 0) - DIE("cannot stat %s: %s\n", lustre_dir, strerror(errno)); - else if (!S_ISDIR(s.st_mode)) - DIE("%s: not a directory\n", lustre_dir); - - rc = llapi_search_fsname(lustre_dir, fsname); - if (rc != 0) { - fprintf(stderr, "Error: %s: not a Lustre filesystem\n", - lustre_dir); - exit(EXIT_FAILURE); - } - - /* Play nice with Lustre test scripts. Non-line buffered output - * stream under I/O redirection may appear incorrectly. - */ - setvbuf(stdout, NULL, _IOLBF, 0); - - for (i = 0; i < NUM_TESTS; i++) { - struct test_tbl_entry *tst = &test_tbl[i]; - - if (test(tst->tte_fn, tst->tte_desc, tst->tte_skip, i) != 0) - rc++; - } - return rc; + return run_tests(lustre_dir, test_tbl); } diff --git a/lustre/tests/llapi_test_utils.c b/lustre/tests/llapi_test_utils.c new file mode 100644 index 0000000..05a66f0 --- /dev/null +++ b/lustre/tests/llapi_test_utils.c @@ -0,0 +1,194 @@ +// SPDX License Identifier: GPL-2.0 +/* Basic framework for Lustre llapi tests. + * All tests return 0 on success and non-zero on error. + * The program will run all tests unless a list of tests to skip is provided. + */ +/* + * Copyright 2014, 2015 Cray Inc, all rights reserved. + * Copyright (c) 2015, Intel Corporation. + * Copyright (c) 2025, DataDirect Networks, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "llapi_test_utils.h" + +static bool run_list_provided; +char fsmountdir[PATH_MAX]; /* Lustre mountpoint */ + +static void print_test_desc(int test_num, const char *test_desc, + const char *status) +{ + int i; + + i = printf(" test%u @%llu: %s ", test_num, + (unsigned long long)time(NULL), test_desc); + for (; i < TEST_DESC_LEN; i++) + printf("."); + printf(" %s\n", status); +} + +/* This function runs a single test by forking the process. This way, + * if there is a segfault during a test, the test program won't crash. + */ +static int test(void (*test_fn)(), const char *test_desc, bool test_skip, + int test_num) +{ + int rc = 0; + pid_t pid; + char status_buf[128]; + + if (test_skip) { + if (!run_list_provided) + print_test_desc(test_num, test_desc, "skip"); + return 0; + } + + pid = fork(); + if (pid < 0) { + ERROR("cannot fork: %s", strerror(errno)); + } else if (pid > 0) { + int status = 0; + + /* Non-zero value indicates failure. */ + wait(&status); + if (status == 0) { + strncpy(status_buf, "pass", sizeof(status_buf)); + } else if WIFSIGNALED(status) { + snprintf(status_buf, sizeof(status_buf), + "fail (exit status %d, killed by SIG%d)", + WEXITSTATUS(status), WTERMSIG(status)); + rc = -1; + } else { + snprintf(status_buf, sizeof(status_buf), + "fail (exit status %d)", WEXITSTATUS(status)); + rc = -1; + } + print_test_desc(test_num, test_desc, status_buf); + } else if (pid == 0) { + /* Run the test in the child process. + * Exit 0 here for success, non-zero from test_fn() on error. + */ + test_fn(); + exit(0); + } + + return rc; +} + +/* 'str_tests' are the tests to be skipped, such as "1,3,4,..." */ +void set_tests_to_skip(const char *str_tests, struct test_tbl_entry *tst_tbl) +{ + const char *ptr = str_tests; + + if (tst_tbl == NULL || ptr == NULL || strlen(ptr) == 0) + return; + + while (*ptr != '\0') { + struct test_tbl_entry *tst; + char *end; + unsigned long tstno = strtoul(ptr, &end, 0); + + if (tstno > UINT_MAX || errno) + DIE("Error: invalid test number '%s'", ptr); + + for (tst = tst_tbl; tst->tte_fn != NULL; tst++) { + if (tst->tte_num == tstno) { + tst->tte_skip = true; + break; + } + } + if (tst->tte_skip == false) + DIE("Error: test %lu not found", tstno); + + if (*end == ',') + ptr = end + 1; + else + break; + } +} + +/* 'str_tests' are the tests to be run, such as "5,6,7,..." */ +void set_tests_to_run(const char *str_tests, struct test_tbl_entry *tst_tbl) +{ + struct test_tbl_entry *tst; + const char *ptr = str_tests; + + if (tst_tbl == NULL || ptr == NULL || strlen(ptr) == 0) + return; + + run_list_provided = true; + for (tst = tst_tbl; tst->tte_fn != NULL; tst++) + tst->tte_skip = true; + + while (*ptr != '\0') { + struct test_tbl_entry *tst; + char *end; + unsigned long tstno = strtoul(ptr, &end, 0); + + if (tstno > UINT_MAX || errno) + DIE("Error: invalid test number '%s'", ptr); + + for (tst = tst_tbl; tst->tte_fn != NULL; tst++) { + if (tst->tte_num == tstno) { + tst->tte_skip = false; + break; + } + } + if (tst->tte_skip == true) + DIE("Error: test %lu not found", tstno); + if (*end == ',') + ptr = end + 1; + else + break; + } +} + +int run_tests(const char *lustre_dir, struct test_tbl_entry *tst_tbl) +{ + struct test_tbl_entry *tst; + char fsname[8 + 1]; + struct stat st; + int rc; + + if (lustre_dir == NULL) + DIE("no test directory provided\n"); + + if (tst_tbl == NULL) + DIE("no test table provided\n"); + + llapi_msg_set_level(LLAPI_MSG_OFF); + + if (stat(lustre_dir, &st) < 0) + DIE("cannot stat %s: %s\n", lustre_dir, strerror(errno)); + else if (!S_ISDIR(st.st_mode)) + DIE("%s: not a directory\n", lustre_dir); + + rc = llapi_search_mounts(lustre_dir, 0, fsmountdir, fsname); + if (rc != 0) { + fprintf(stderr, "Error: %s: not a Lustre filesystem\n", + lustre_dir); + return EXIT_FAILURE; + } + + /* Play nice with Lustre test scripts. Non-line buffered output + * stream under I/O redirection may appear incorrectly. + */ + setvbuf(stdout, NULL, _IOLBF, 0); + + for (tst = tst_tbl; tst->tte_fn != NULL; tst++) { + if (test(tst->tte_fn, tst->tte_desc, tst->tte_skip, + tst->tte_num)) + rc++; + } + + return rc; +} diff --git a/lustre/tests/llapi_test_utils.h b/lustre/tests/llapi_test_utils.h new file mode 100644 index 0000000..b5bcdd9 --- /dev/null +++ b/lustre/tests/llapi_test_utils.h @@ -0,0 +1,48 @@ +/* SPDX License Identifier: GPL-2.0 */ + +#include +#include +#include +#include + +#define ERROR(fmt, ...) \ + fprintf(stderr, "%s: %s:%d: %s: " fmt "\n", \ + program_invocation_short_name, __FILE__, __LINE__, \ + __func__, ## __VA_ARGS__) + +#define DIE(fmt, ...) \ +do { \ + ERROR(fmt, ## __VA_ARGS__); \ + exit(EXIT_FAILURE); \ +} while (0) + +#define ASSERTF(cond, fmt, ...) \ +do { \ + if (!(cond)) \ + DIE("assertion '%s' failed: "fmt, #cond, ## __VA_ARGS__);\ +} while (0) + +#define TEST_DESC_LEN 80 +struct test_tbl_entry { + void (*tte_fn)(void); + char tte_desc[TEST_DESC_LEN]; + unsigned int tte_num; + bool tte_skip; +}; + +#define TEST_REGISTER(num) \ + { .tte_fn = &test ## num, .tte_desc = T ## num ## _DESC, .tte_num = num} +#define TEST_REGISTER_END { .tte_fn = NULL } + +extern char fsmountdir[PATH_MAX]; /* Lustre mountpoint */ + +/* Run all tests declared in @tst_tbl until a NULL entry is found. + * The tests are run by forking the process. That way, if test segfaults, + * the test program won't crash. + * Tests may be skipped by setting .tte_skip = true. + */ +int run_tests(const char *lustre_dir, struct test_tbl_entry *tst_tbl); + +/* 'str_tests' are the tests to be skipped/run, such as "1,3,4,.." */ +void set_tests_to_skip(const char *str_tests, struct test_tbl_entry *tst_tbl); +void set_tests_to_run(const char *str_tests, struct test_tbl_entry *tst_tbl); diff --git a/lustre/tests/sanity-hsm.sh b/lustre/tests/sanity-hsm.sh index cfc5cf9..1a7002a 100755 --- a/lustre/tests/sanity-hsm.sh +++ b/lustre/tests/sanity-hsm.sh @@ -5800,20 +5800,22 @@ run_test 411 "hsm_ops rbac role" test_500() { - [ "$MDS1_VERSION" -lt $(version_code 2.6.92) ] && - skip "HSM migrate is not supported" + local bitmap_opt="" + + (( $MDS1_VERSION >= $(version_code 2.6.92-47-g1fe3ae8dab) )) || + skip "need MDS >= 2.6.92.47 for HSM migrate support" test_mkdir -p $DIR/$tdir - if [ "$CLIENT_VERSION" -lt $(version_code 2.11.56) ] || - [ "$MDS1_VERSION" -lt $(version_code 2.11.56) ]; - then - llapi_hsm_test -d $DIR/$tdir -b || - error "One llapi HSM test failed" - else - llapi_hsm_test -d $DIR/$tdir || - error "One llapi HSM test failed" - fi + (( $CLIENT_VERSION >= $(version_code 2.11.56-179-g3bfb6107ba) && + $MDS1_VERSION >= $(version_code 2.11.56-179-g3bfb6107ba) )) || + bitmap_opt="-b" + + (( $MDS1_VERSION >= $(version_code 2.14.50-142-gf684172237) )) || + SKIP500+=" -s 113" + + llapi_hsm_test -d $DIR/$tdir $bitmap_opt $SKIP500 || + error "llapi HSM testing failed" } run_test 500 "various LLAPI HSM tests" diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 242d43e..ee16f20 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -2575,7 +2575,7 @@ test_27Cj() { run_test 27Cj "overstriping with -C for max values in multiple of targets" test_27D() { - [ $OSTCOUNT -lt 2 ] && skip_env "needs >= 2 OSTs" + (( $OSTCOUNT >= 2 )) || skip_env "needs >= 2 OSTs" remote_mds_nodsh && skip "remote MDS with nodsh" local POOL=${POOL:-testpool} @@ -2589,18 +2589,17 @@ test_27D() { pool_add $POOL || error "pool_add failed" pool_add_targets $POOL $ost_range || error "pool_add_targets failed" - local skip27D - [ $MDS1_VERSION -lt $(version_code 2.8.55) ] && - skip27D+="-s 29" - [ $MDS1_VERSION -lt $(version_code 2.9.55) ] || - [ $CLIENT_VERSION -lt $(version_code 2.9.55) ] && - skip27D+=" -s 30,31" - [[ ! $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping || - $OSTCOUNT -ge $(($LOV_MAX_STRIPE_COUNT / 2)) ]] && - skip27D+=" -s 32,33" - [[ $MDS_VERSION -lt $(version_code $SEL_VER) ]] && - skip27D+=" -s 34" - llapi_layout_test -d$DIR/$tdir -p$POOL -o$OSTCOUNT $skip27D || + (( $MDS1_VERSION >= $(version_code 2.8.55) )) || + SKIP27D+=" -s 29" + (( $MDS1_VERSION >= $(version_code 2.9.55) && + $CLIENT_VERSION >= $(version_code 2.9.55) )) || + SKIP27D+=" -s 30,31" + [[ $($LCTL get_param mdc.*.import) =~ connect_flags.*overstriping ]] && + (( $OSTCOUNT < $LOV_MAX_STRIPE_COUNT / 2)) || + SKIP27D+=" -s 32,33" + (( $MDS1_VERSION >= $(version_code $SEL_VER) )) || + SKIP27D+=" -s 34" + llapi_layout_test -d$DIR/$tdir -p$POOL -o$OSTCOUNT $SKIP27D || error "llapi_layout_test failed" destroy_test_pools || error "destroy test pools failed" -- 1.8.3.1