Test suite for llapi_layout interface.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * These tests exercise the llapi_layout API which abstracts the layout | |
| * of a Lustre file behind an opaque data type. They assume a Lustre file | |
| * system with at least 6 OSTs and a pool names "testpool" containing 6 | |
| * OSTs. For example, | |
| * | |
| * sudo lctl pool_new lustre.testpool | |
| * sudo lctl pool_add lustre.testpool OST[0-5] | |
| * gcc -D LUSTRE_DIR=\"/mnt/lustre/somedir\" -Wall -g -Werror -o test test.c \ | |
| * -llustrepapi | |
| * sudo ./test | |
| * | |
| * Written by: Ned Bass <bass6@llnl.gov> | |
| */ | |
| #include <unistd.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <fcntl.h> | |
| #include <sys/wait.h> | |
| #include <sys/signal.h> | |
| #include <sys/types.h> | |
| #include <assert.h> | |
| #include <errno.h> | |
| #include <lustre/lustreapi.h> | |
| #include <pwd.h> | |
| #include <sys/stat.h> | |
| #define TEST(testfn) { test(&(testfn), #testfn); } | |
| #ifndef LUSTRE_DIR | |
| #define LUSTRE_DIR "/mnt/lustre" | |
| #endif | |
| #define TEST_POOL_NAME "testpool" | |
| /* 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 */ | |
| void test(void (*testfn)(), const char *name) { | |
| pid_t pid = fork(); | |
| if (pid > 0) { | |
| /* Check the child's return value */ | |
| int status = 0; | |
| wait(&status); | |
| /* Non-zero value = test failed */ | |
| printf("%s:\t%s\n", name, status ? "fail" : "pass"); | |
| } else if (pid == 0) { | |
| /* Run the test in the child process. Exit with 0 for success, | |
| non-zero for failure */ | |
| testfn(); | |
| exit(0); | |
| } else { | |
| printf("Fork failed!\n"); | |
| } | |
| } | |
| #define T1FILE LUSTRE_DIR "/t1" | |
| #define T1_STRIPE_COUNT 5 | |
| #define T1_STRIPE_SIZE 1048576 | |
| #define T1_OST_OFFSET 3 | |
| /* Sanity test. Read and write layout attributes then create a new file. */ | |
| void test1() | |
| { | |
| int rc; | |
| lustre_layout_t *layout = llapi_layout_alloc(); | |
| assert(layout != NULL); | |
| rc = unlink(T1FILE); | |
| assert(rc == 0 || errno == ENOENT); | |
| assert(llapi_layout_stripe_count_set(layout, T1_STRIPE_COUNT) == 0); | |
| assert(llapi_layout_stripe_count(layout) == T1_STRIPE_COUNT); | |
| assert(llapi_layout_stripe_size_set(layout, T1_STRIPE_SIZE) == 0); | |
| assert(llapi_layout_stripe_size(layout) == T1_STRIPE_SIZE); | |
| assert(llapi_layout_pool_name_set(layout, TEST_POOL_NAME) == 0); | |
| assert(strcmp(llapi_layout_pool_name(layout), TEST_POOL_NAME) == 0); | |
| rc = llapi_layout_ost_index_set(layout, 0, T1_OST_OFFSET); | |
| assert(rc == 0); | |
| rc = llapi_layout_file_create(layout, T1FILE, 0660, 0); | |
| assert(rc >= 0); | |
| assert(close(rc) == 0); | |
| llapi_layout_free(layout); | |
| } | |
| void __test2_helper(lustre_layout_t *layout) | |
| { | |
| int ost0; | |
| int ost1; | |
| int obj0; | |
| int obj1; | |
| assert(llapi_layout_stripe_count(layout) == T1_STRIPE_COUNT); | |
| assert(llapi_layout_stripe_size(layout) == T1_STRIPE_SIZE); | |
| ost0 = llapi_layout_ost_index(layout, 0); | |
| ost1 = llapi_layout_ost_index(layout, 1); | |
| obj0 = llapi_layout_obj_id(layout, 0); | |
| obj1 = llapi_layout_obj_id(layout, 1); | |
| /* FIXME setting pool name works for ioctl but not fsetxattr :( */ | |
| assert(strcmp(llapi_layout_pool_name(layout), TEST_POOL_NAME) == 0); | |
| assert(ost0 == T1_OST_OFFSET); | |
| assert(ost1 != ost0); | |
| assert(obj0 != 0); | |
| assert(obj1 != 0); | |
| } | |
| /* Read back file layout from test1 by path and verify attributes. */ | |
| void test2() | |
| { | |
| errno = 0; | |
| lustre_layout_t *layout = llapi_layout_lookup_bypath(T1FILE); | |
| assert(layout != NULL); | |
| assert(errno == 0); | |
| __test2_helper(layout); | |
| llapi_layout_free(layout); | |
| } | |
| /* Read back file layout from test1 by open fd and verify attributes. */ | |
| void test3() | |
| { | |
| int fd; | |
| fd = open(T1FILE, O_RDONLY); | |
| assert(fd != -1); | |
| errno = 0; | |
| lustre_layout_t *layout = llapi_layout_lookup_byfd(fd); | |
| assert(close(fd) == 0); | |
| assert(layout != NULL); | |
| assert(errno == 0); | |
| __test2_helper(layout); | |
| llapi_layout_free(layout); | |
| } | |
| #define T4FILE LUSTRE_DIR "/t4" | |
| #define T4_STRIPE_COUNT 5 | |
| #define T4_STRIPE_SIZE 2097152 | |
| /* Create a file with 'lfs setstripe' then verify it's layout */ | |
| void test4() | |
| { | |
| int rc; | |
| int ost0; | |
| int ost1; | |
| int obj0; | |
| int obj1; | |
| const char *lfs = getenv("LFS"); | |
| char cmd[4096]; | |
| if (lfs == NULL) | |
| lfs = "/usr/bin/lfs"; | |
| rc = unlink(T4FILE); | |
| assert(rc == 0 || errno == ENOENT); | |
| snprintf(cmd, 4096, "%s setstripe -p %s -c %d -s %d %s\n", lfs, | |
| TEST_POOL_NAME, T4_STRIPE_COUNT, T4_STRIPE_SIZE, T4FILE); | |
| assert(system(cmd) == 0); | |
| errno = 0; | |
| lustre_layout_t *layout = llapi_layout_lookup_bypath(T4FILE); | |
| assert(layout != NULL); | |
| assert(errno == 0); | |
| assert(llapi_layout_stripe_count(layout) == T4_STRIPE_COUNT); | |
| assert(llapi_layout_stripe_size(layout) == T4_STRIPE_SIZE); | |
| assert(strcmp(llapi_layout_pool_name(layout), TEST_POOL_NAME) == 0); | |
| ost0 = llapi_layout_ost_index(layout, 0); | |
| ost1 = llapi_layout_ost_index(layout, 1); | |
| obj0 = llapi_layout_obj_id(layout, 0); | |
| obj1 = llapi_layout_obj_id(layout, 1); | |
| assert(ost0 != ost1); | |
| assert(obj0 != 0); | |
| assert(obj1 != 0); | |
| llapi_layout_free(layout); | |
| } | |
| #define T5FILE LUSTRE_DIR "/t5" | |
| /* llapi_layout_lookup_bypath() returns ENOENT in errno when expected. */ | |
| void test5() | |
| { | |
| int rc; | |
| rc = unlink(T5FILE); | |
| assert(rc == 0 || errno == ENOENT); | |
| errno = 0; | |
| lustre_layout_t *layout = llapi_layout_lookup_bypath(T5FILE); | |
| assert(layout == NULL); | |
| assert(errno == ENOENT); | |
| } | |
| /* llapi_layout_lookup_byfd() returns EBADF in errno when expected. */ | |
| void test6() | |
| { | |
| int rc; | |
| rc = unlink(T5FILE); | |
| assert(rc == 0 || errno == ENOENT); | |
| errno = 0; | |
| lustre_layout_t *layout = llapi_layout_lookup_byfd(9999); | |
| assert(layout == NULL); | |
| assert(errno == EBADF); | |
| } | |
| #define T7FILE LUSTRE_DIR "/t7" | |
| /* llapi_layout_lookup_bypath() returns EACCES in errno when expected. */ | |
| void test7() | |
| { | |
| int fd; | |
| int rc; | |
| uid_t myuid = getuid(); | |
| assert(myuid == 0); /* Need root for this test. */ | |
| /* Create file as root */ | |
| rc = unlink(T7FILE); | |
| assert(rc == 0 || errno == ENOENT); | |
| fd = open(T7FILE, O_CREAT); | |
| assert(fd != -1); | |
| assert(fchmod(fd, 0400) == 0); | |
| assert(close(fd) == 0); | |
| /* Become unprivileged user */ | |
| struct passwd *pw = getpwnam("nobody"); | |
| assert(pw != NULL); | |
| assert(seteuid(pw->pw_uid) == 0); | |
| errno = 0; | |
| lustre_layout_t *layout = llapi_layout_lookup_bypath(T7FILE); | |
| assert(layout == NULL); | |
| assert(errno == EACCES); | |
| assert(seteuid(myuid) == 0); | |
| } | |
| #define T8FILE LUSTRE_DIR "/t8" | |
| /* llapi_layout_lookup_bypath() returns ENODATA in errno for file with no | |
| * striping attributes. */ | |
| void test8() | |
| { | |
| int fd; | |
| int rc; | |
| lustre_layout_t *layout; | |
| rc = unlink(T8FILE); | |
| assert(rc == 0 || errno == ENOENT); | |
| fd = open(T8FILE, O_CREAT, 0640); | |
| assert(fd != -1); | |
| assert(close(fd) == 0); | |
| errno = 0; | |
| layout = llapi_layout_lookup_bypath(T8FILE); | |
| assert(layout == NULL); | |
| assert(errno == ENODATA); | |
| } | |
| #define T10FILE LUSTRE_DIR "/t10" | |
| #define T10_STRIPE_COUNT 2 | |
| #define T10_STRIPE_SIZE 1048576 | |
| /* llapi_layout_create_file() returns EEXIST in errno for | |
| * already-existing file. */ | |
| void test10() | |
| { | |
| int rc; | |
| int fd; | |
| lustre_layout_t *layout; | |
| (void) unlink(T10FILE); | |
| layout = llapi_layout_alloc(); | |
| llapi_layout_stripe_count_set(layout, T10_STRIPE_COUNT); | |
| llapi_layout_stripe_size_set(layout, T10_STRIPE_SIZE); | |
| fd = llapi_layout_file_create(layout, T10FILE, 0750, 0); | |
| assert(fd >= 0); | |
| assert(close(fd) == 0); | |
| rc = llapi_layout_file_create(layout, T10FILE, 0750, 0); | |
| assert(rc < 0); | |
| assert(errno == EEXIST); | |
| llapi_layout_free(layout); | |
| } | |
| /* Verify stripe_count interfaces return errors as expected */ | |
| void test11() | |
| { | |
| int rc; | |
| lustre_layout_t *layout; | |
| layout = llapi_layout_alloc(); | |
| assert(layout != NULL); | |
| /* stripe count less than -1 (-1 means use all available OSTs) */ | |
| errno = 0; | |
| rc = llapi_layout_stripe_count_set(layout, -2); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* NULL layout */ | |
| errno = 0; | |
| rc = llapi_layout_stripe_count_set(NULL, 2); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* NULL layout */ | |
| errno = 0; | |
| rc = llapi_layout_stripe_count(NULL); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* stripe count too large */ | |
| errno = 0; | |
| rc = llapi_layout_stripe_count_set(layout, LOV_MAX_STRIPE_COUNT + 1); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| llapi_layout_free(layout); | |
| } | |
| /* Verify stripe_size interfaces return errors as expected */ | |
| void test12() | |
| { | |
| int rc; | |
| lustre_layout_t *layout; | |
| layout = llapi_layout_alloc(); | |
| assert(layout != NULL); | |
| /* negative stripe size */ | |
| errno = 0; | |
| rc = llapi_layout_stripe_size_set(layout, -1); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* stripe size too big */ | |
| errno = 0; | |
| rc = llapi_layout_stripe_size_set(layout, 1ULL << 32); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* NULL layout */ | |
| errno = 0; | |
| rc = llapi_layout_stripe_size_set(NULL, 1048576); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* NULL layout */ | |
| errno = 0; | |
| rc = llapi_layout_stripe_size(NULL); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| llapi_layout_free(layout); | |
| } | |
| /* Verify pool_name interfaces return errors as expected */ | |
| void test13() | |
| { | |
| int rc; | |
| lustre_layout_t *layout; | |
| const char *poolname; | |
| layout = llapi_layout_alloc(); | |
| assert(layout != NULL); | |
| /* NULL layout */ | |
| errno = 0; | |
| rc = llapi_layout_pool_name_set(NULL, "foo"); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* NULL pool name */ | |
| errno = 0; | |
| rc = llapi_layout_pool_name_set(layout, NULL); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* NULL layout */ | |
| errno = 0; | |
| poolname = llapi_layout_pool_name(NULL); | |
| assert(poolname == NULL); | |
| assert(errno = EINVAL); | |
| llapi_layout_free(layout); | |
| } | |
| #define T14FILE LUSTRE_DIR "/t14" | |
| #define T14_STRIPE_COUNT 2 | |
| /* Verify ost_index interfaces return errors as expected */ | |
| void test14() | |
| { | |
| int rc; | |
| lustre_layout_t *layout; | |
| layout = llapi_layout_alloc(); | |
| assert(layout != NULL); | |
| /* Only setting OST index for stripe 0 is supported for now. */ | |
| errno = 0; | |
| rc = llapi_layout_ost_index_set(layout, 1, 1); | |
| assert(rc == -1); | |
| assert(errno = EOPNOTSUPP); | |
| /* OST index less than -1 (-1 means let MDS choose) */ | |
| errno = 0; | |
| rc = llapi_layout_ost_index_set(layout, 0, -2); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* NULL layout */ | |
| errno = 0; | |
| rc = llapi_layout_ost_index_set(NULL, 0, 1); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* NULL layout */ | |
| errno = 0; | |
| rc = llapi_layout_ost_index(NULL, 0); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* Layout not read from file so has no OST data. */ | |
| errno = 0; | |
| rc = llapi_layout_ost_index(layout, 0); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| /* n greater than stripe count*/ | |
| rc = unlink(T14FILE); | |
| assert(rc == 0 || errno == ENOENT); | |
| assert(llapi_layout_stripe_count_set(layout, T14_STRIPE_COUNT) == 0); | |
| rc = llapi_layout_file_create(layout, T14FILE, 0644, 0); | |
| assert(rc >= 0); | |
| close(rc); | |
| llapi_layout_free(layout); | |
| layout = llapi_layout_lookup_bypath(T14FILE); | |
| errno = 0; | |
| rc = llapi_layout_ost_index(layout, 3); | |
| assert(rc == -1); | |
| assert(errno = EINVAL); | |
| llapi_layout_free(layout); | |
| } | |
| /* Verify llapi_layout_file_create() returns errors as expected */ | |
| void test15() | |
| { | |
| int rc; | |
| /* NULL layout */ | |
| errno = 0; | |
| rc = llapi_layout_file_create(NULL, "foo", 0, 0); | |
| assert(rc == -1); | |
| assert(errno == EINVAL); | |
| } | |
| #define T16FILE LUSTRE_DIR "/t16" | |
| #define T16_STRIPE_COUNT 2 | |
| /* Can't change striping attributes of existing file. */ | |
| void test16() | |
| { | |
| int rc; | |
| lustre_layout_t *layout; | |
| rc = unlink(T16FILE); | |
| assert(rc == 0 || errno == ENOENT); | |
| errno = 0; | |
| layout = llapi_layout_alloc(); | |
| assert(layout != NULL); | |
| assert(llapi_layout_stripe_count_set(layout, T16_STRIPE_COUNT) == 0); | |
| rc = llapi_layout_file_create(layout, T16FILE, 0640, 0); | |
| assert(rc >= 0); | |
| assert(errno == 0); | |
| assert(close(rc) == 0); | |
| assert(llapi_layout_stripe_count_set(layout, T16_STRIPE_COUNT + 1) == 0); | |
| rc = llapi_layout_file_create(layout, T16FILE, 0640, 0); | |
| assert(rc < 0); | |
| assert(errno == EEXIST); | |
| llapi_layout_free(layout); | |
| layout = llapi_layout_lookup_bypath(T16FILE); | |
| assert(layout != NULL); | |
| assert(llapi_layout_stripe_count(layout) == T16_STRIPE_COUNT); | |
| llapi_layout_free(layout); | |
| } | |
| #define T17FILE LUSTRE_DIR "/t17" | |
| /* Default stripe attributes are applied as expected. */ | |
| void test17() | |
| { | |
| int rc; | |
| lustre_layout_t *dirlayout; | |
| lustre_layout_t *filelayout; | |
| rc = unlink(T17FILE); | |
| assert(rc == 0 || errno == ENOENT); | |
| assert(dirlayout = llapi_layout_lookup_bypath(LUSTRE_DIR)); | |
| assert(filelayout = llapi_layout_alloc()); | |
| rc = llapi_layout_file_create(filelayout, T17FILE, 0640, 0); | |
| assert(rc >= 0); | |
| assert(close(rc) == 0); | |
| llapi_layout_free(filelayout); | |
| assert(filelayout = llapi_layout_lookup_bypath(T17FILE)); | |
| assert(llapi_layout_stripe_count(filelayout) == | |
| llapi_layout_stripe_count(dirlayout)); | |
| assert(llapi_layout_stripe_size(filelayout) == | |
| llapi_layout_stripe_size(dirlayout)); | |
| llapi_layout_free(filelayout); | |
| llapi_layout_free(dirlayout); | |
| } | |
| #define T18FILE LUSTRE_DIR "/t18" | |
| /* Setting stripe count to -1 uses all available OSTs. */ | |
| void test18() | |
| { | |
| int rc; | |
| int fd; | |
| int ost_count; | |
| lustre_layout_t *layout; | |
| rc = unlink(T18FILE); | |
| assert(rc == 0 || errno == ENOENT); | |
| assert(layout = llapi_layout_alloc()); | |
| llapi_layout_stripe_count_set(layout, -1); | |
| rc = llapi_layout_file_create(layout, T18FILE, 0640, 0); | |
| assert(rc >= 0); | |
| assert(close(rc) == 0); | |
| llapi_layout_free(layout); | |
| /* Get number of available OSTs */ | |
| fd = open(T18FILE, O_RDONLY); | |
| assert(fd != -1); | |
| llapi_lov_get_uuids(fd, NULL, &ost_count); | |
| assert(close(fd) == 0); | |
| assert(layout = llapi_layout_lookup_bypath(T18FILE)); | |
| assert(llapi_layout_stripe_count(layout) == ost_count); | |
| llapi_layout_free(layout); | |
| } | |
| void sigsegv(int signal) { | |
| printf("Segmentation fault\n"); | |
| exit(1); | |
| } | |
| int main(int argc, char *argv[]) { | |
| signal(SIGSEGV, sigsegv); | |
| TEST(test1); | |
| TEST(test2); | |
| TEST(test3); | |
| TEST(test4); | |
| TEST(test5); | |
| TEST(test6); | |
| TEST(test7); | |
| TEST(test8); | |
| TEST(test10); | |
| TEST(test11); | |
| TEST(test12); | |
| TEST(test13); | |
| TEST(test14); | |
| TEST(test15); | |
| TEST(test16); | |
| TEST(test17); | |
| TEST(test18); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment