// 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 * of a Lustre file behind an opaque data type. They assume a Lustre * file system with at least 2 OSTs and a pool containing at least the * first 2 OSTs. For example, * * sudo lctl pool_new lustre.testpool * sudo lctl pool_add lustre.testpool OST[0-1] * gcc -Wall -g -Werror -o llapi_layout_test llapi_layout_test.c -llustreapi * sudo ./llapi_layout_test */ #include #include #include #include #include #include #include #include #include #include #include "llapi_test_utils.h" 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 void usage(char *prog) { printf("Usage: %s [-d lustre_dir] [-p pool_name] [-o num_osts] " "[-s $n,$m,... (skip tests)] [-t $n,$m,... (run tests)]\n", prog); exit(0); } #define T0FILE "t0" #define T0_STRIPE_COUNT num_osts #define T0_STRIPE_SIZE 1048576 #define T0_OST_OFFSET (num_osts - 1) #define T0_DESC "Read/write layout attributes then create a file" static void test0(void) { int rc; int fd; uint64_t count; uint64_t size; struct llapi_layout *layout = llapi_layout_alloc(); char path[PATH_MAX]; char mypool[LOV_MAXPOOLNAME + 1] = { '\0' }; ASSERTF(layout != NULL, "errno %d", errno); snprintf(path, sizeof(path), "%s/%s", lustre_dir, T0FILE); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); /* stripe count */ rc = llapi_layout_stripe_count_set(layout, T0_STRIPE_COUNT); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(rc == 0 && count == T0_STRIPE_COUNT, "%"PRIu64" != %d", count, T0_STRIPE_COUNT); /* stripe size */ rc = llapi_layout_stripe_size_set(layout, T0_STRIPE_SIZE); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_stripe_size_get(layout, &size); ASSERTF(rc == 0 && size == T0_STRIPE_SIZE, "%"PRIu64" != %d", size, T0_STRIPE_SIZE); /* pool_name */ rc = llapi_layout_pool_name_set(layout, poolname); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_pool_name_get(layout, mypool, sizeof(mypool)); ASSERTF(rc == 0, "errno = %d", errno); rc = strcmp(mypool, poolname); ASSERTF(rc == 0, "%s != %s", mypool, poolname); /* ost_index */ rc = llapi_layout_ost_index_set(layout, 0, T0_OST_OFFSET); ASSERTF(rc == 0, "errno = %d", errno); /* create */ fd = llapi_layout_file_create(path, 0, 0660, layout); ASSERTF(fd >= 0, "path = %s, errno = %d", path, errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); llapi_layout_free(layout); } static void __test1_helper(struct llapi_layout *layout) { uint64_t ost0; uint64_t ost1; uint64_t size; uint64_t count; int rc; char mypool[LOV_MAXPOOLNAME + 1] = { '\0' }; rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(count == T0_STRIPE_COUNT, "%"PRIu64" != %d", count, T0_STRIPE_COUNT); rc = llapi_layout_stripe_size_get(layout, &size); ASSERTF(size == T0_STRIPE_SIZE, "%"PRIu64" != %d", size, T0_STRIPE_SIZE); rc = llapi_layout_pool_name_get(layout, mypool, sizeof(mypool)); ASSERTF(rc == 0, "errno = %d", errno); rc = strcmp(mypool, poolname); ASSERTF(rc == 0, "%s != %s", mypool, poolname); rc = llapi_layout_ost_index_get(layout, 0, &ost0); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_ost_index_get(layout, 1, &ost1); ASSERTF(rc == 0, "errno = %d", errno); ASSERTF(ost0 == T0_OST_OFFSET, "%"PRIu64" != %d", ost0, T0_OST_OFFSET); ASSERTF(ost1 != ost0, "%"PRIu64" == %"PRIu64, ost0, ost1); } #define T1_DESC "Read test0 file by path and verify attributes" static void test1(void) { char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T0FILE); struct llapi_layout *layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); __test1_helper(layout); llapi_layout_free(layout); } #define T2_DESC "Read test0 file by FD and verify attributes" static void test2(void) { int fd; int rc; char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T0FILE); fd = open(path, O_RDONLY); ASSERTF(fd >= 0, "open(%s): errno = %d", path, errno); struct llapi_layout *layout = llapi_layout_get_by_fd(fd, 0); ASSERTF(layout != NULL, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "close(%s): errno = %d", path, errno); __test1_helper(layout); llapi_layout_free(layout); } #define T3_DESC "Read test0 file by FID and verify attributes" static void test3(void) { int rc; struct llapi_layout *layout; struct lu_fid fid; char fidstr[4096]; char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T0FILE); rc = llapi_path2fid(path, &fid); ASSERTF(rc == 0, "rc = %d, errno = %d", rc, errno); snprintf(fidstr, sizeof(fidstr), "0x%"PRIx64":0x%x:0x%x", (uint64_t)fid.f_seq, fid.f_oid, fid.f_ver); errno = 0; layout = llapi_layout_get_by_fid(path, &fid, 0); ASSERTF(layout != NULL, "fidstr = %s, errno = %d", fidstr, errno); __test1_helper(layout); llapi_layout_free(layout); } #define T4FILE "t4" #define T4_STRIPE_COUNT 2 #define T4_STRIPE_SIZE 2097152 #define T4_DESC "Verify compatibility with 'lfs setstripe'" static void test4(void) { int rc; uint64_t ost0; uint64_t ost1; uint64_t count; uint64_t size; const char *lfs = getenv("LFS"); char mypool[LOV_MAXPOOLNAME + 1] = { '\0' }; char cmd[PATH_MAX + 128]; char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T4FILE); if (lfs == NULL) lfs = "/usr/bin/lfs"; rc = unlink(path); ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno); snprintf(cmd, sizeof(cmd), "%s setstripe %s %s -c %d -S %d %s", lfs, strlen(poolname) > 0 ? "-p" : "", poolname, T4_STRIPE_COUNT, T4_STRIPE_SIZE, path); rc = system(cmd); ASSERTF(rc == 0, "system(%s): exit status %d", cmd, WEXITSTATUS(rc)); errno = 0; struct llapi_layout *layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(count == T4_STRIPE_COUNT, "%"PRIu64" != %d", count, T4_STRIPE_COUNT); rc = llapi_layout_stripe_size_get(layout, &size); ASSERTF(size == T4_STRIPE_SIZE, "%"PRIu64" != %d", size, T4_STRIPE_SIZE); rc = llapi_layout_pool_name_get(layout, mypool, sizeof(mypool)); ASSERTF(rc == 0, "errno = %d", errno); rc = strcmp(mypool, poolname); ASSERTF(rc == 0, "%s != %s", mypool, poolname); rc = llapi_layout_ost_index_get(layout, 0, &ost0); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_ost_index_get(layout, 1, &ost1); ASSERTF(rc == 0, "errno = %d", errno); ASSERTF(ost1 != ost0, "%"PRIu64" == %"PRIu64, ost0, ost1); llapi_layout_free(layout); } #define T5FILE "t5" #define T5_DESC "llapi_layout_get_by_path ENOENT handling" static void test5(void) { int rc; char path[PATH_MAX]; struct llapi_layout *layout; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T5FILE); rc = unlink(path); ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno); errno = 0; layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout == NULL && errno == ENOENT, "errno = %d", errno); } #define T6_DESC "llapi_layout_get_by_fd EBADF handling" static void test6(void) { errno = 0; struct llapi_layout *layout = llapi_layout_get_by_fd(9999, 0); ASSERTF(layout == NULL && errno == EBADF, "errno = %d", errno); } #define T7FILE "t7" #define T7_DESC "llapi_layout_get_by_path EACCES handling" static void test7(void) { int fd; int rc; uid_t myuid = getuid(); char path[PATH_MAX]; const char *runas = getenv("RUNAS_ID"); struct passwd *pw; uid_t uid; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T7FILE); ASSERTF(myuid == 0, "myuid = %d", myuid); /* Need root for this test. */ /* Create file as root */ rc = unlink(path); ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno); fd = open(path, O_CREAT, 0400); ASSERTF(fd > 0, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); /* Become unprivileged user */ if (runas != NULL) { uid = atoi(runas); ASSERTF(uid != 0, "runas = %s", runas); } else { pw = getpwnam("nobody"); ASSERTF(pw != NULL, "errno = %d", errno); uid = pw->pw_uid; } rc = seteuid(uid); ASSERTF(rc == 0, "errno = %d", errno); errno = 0; struct llapi_layout *layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout == NULL && errno == EACCES, "errno = %d", errno); rc = seteuid(myuid); ASSERTF(rc == 0, "errno = %d", errno); } /* llapi_layout_get_by_path() returns default layout for file with no * striping attributes. */ #define T8FILE "t8" #define T8_DESC "llapi_layout_get_by_path ENODATA handling" static void test8(void) { int fd; int rc; struct llapi_layout *layout; uint64_t count; uint64_t size; uint64_t pattern; char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T8FILE); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); fd = open(path, O_CREAT, 0640); ASSERTF(fd >= 0, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d\n", errno); rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(count == LLAPI_LAYOUT_DEFAULT, "count = %"PRIu64"\n", count); rc = llapi_layout_stripe_size_get(layout, &size); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(size == LLAPI_LAYOUT_DEFAULT, "size = %"PRIu64"\n", size); rc = llapi_layout_pattern_get(layout, &pattern); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(pattern == LLAPI_LAYOUT_DEFAULT, "pattern = %"PRIu64"\n", pattern); llapi_layout_free(layout); } /* Verify llapi_layout_patter_set() return values for various inputs. */ #define T9_DESC "verify llapi_layout_pattern_set() return values" static void test9(void) { struct llapi_layout *layout; int rc; layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno = %d\n", errno); errno = 0; rc = llapi_layout_pattern_set(layout, LLAPI_LAYOUT_INVALID); ASSERTF(rc == -1 && errno == EOPNOTSUPP, "rc = %d, errno = %d", rc, errno); errno = 0; rc = llapi_layout_pattern_set(NULL, LLAPI_LAYOUT_DEFAULT); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); errno = 0; rc = llapi_layout_pattern_set(layout, LLAPI_LAYOUT_DEFAULT); ASSERTF(rc == 0, "rc = %d, errno = %d", rc, errno); errno = 0; rc = llapi_layout_pattern_set(layout, LLAPI_LAYOUT_RAID0); ASSERTF(rc == 0, "rc = %d, errno = %d", rc, errno); llapi_layout_free(layout); } /* Verify stripe_count interfaces return errors as expected */ #define T10_DESC "stripe_count error handling" static void test10(void) { int rc; uint64_t count; struct llapi_layout *layout; layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno = %d", errno); /* invalid stripe count */ errno = 0; rc = llapi_layout_stripe_count_set(layout, LLAPI_LAYOUT_INVALID); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); errno = 0; rc = llapi_layout_stripe_count_set(layout, -1); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* NULL layout */ errno = 0; rc = llapi_layout_stripe_count_set(NULL, 2); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* NULL layout */ errno = 0; rc = llapi_layout_stripe_count_get(NULL, &count); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* NULL count */ errno = 0; rc = llapi_layout_stripe_count_get(layout, NULL); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* stripe count too large */ errno = 0; rc = llapi_layout_stripe_count_set(layout, LOV_MAX_STRIPE_COUNT + 1); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); llapi_layout_free(layout); } /* Verify stripe_size interfaces return errors as expected */ #define T11_DESC "stripe_size error handling" static void test11(void) { int rc; uint64_t size; struct llapi_layout *layout; layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno = %d", errno); /* negative stripe size */ errno = 0; rc = llapi_layout_stripe_size_set(layout, -1); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* invalid stripe size */ errno = 0; rc = llapi_layout_stripe_size_set(layout, LLAPI_LAYOUT_INVALID); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* stripe size too big */ errno = 0; rc = llapi_layout_stripe_size_set(layout, (1ULL << 33)); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* NULL layout */ errno = 0; rc = llapi_layout_stripe_size_set(NULL, 1048576); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); errno = 0; rc = llapi_layout_stripe_size_get(NULL, &size); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* NULL size */ errno = 0; rc = llapi_layout_stripe_size_get(layout, NULL); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); llapi_layout_free(layout); } /* Verify pool_name interfaces return errors as expected */ #define T12_DESC "pool_name error handling" static void test12(void) { int rc; struct llapi_layout *layout; char mypool[LOV_MAXPOOLNAME + 1] = { '\0' }; layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno = %d", errno); /* NULL layout */ errno = 0; rc = llapi_layout_pool_name_set(NULL, "foo"); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* NULL pool name */ errno = 0; rc = llapi_layout_pool_name_set(layout, NULL); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* NULL layout */ errno = 0; rc = llapi_layout_pool_name_get(NULL, mypool, sizeof(mypool)); ASSERTF(errno == EINVAL, "poolname = %s, errno = %d", poolname, errno); /* NULL buffer */ errno = 0; rc = llapi_layout_pool_name_get(layout, NULL, sizeof(mypool)); ASSERTF(errno == EINVAL, "poolname = %s, errno = %d", poolname, errno); /* Pool name too long*/ errno = 0; rc = llapi_layout_pool_name_set(layout, "0123456789abcdef"); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); llapi_layout_free(layout); } /* Verify ost_index interface returns errors as expected */ #define T13FILE "t13" #define T13_STRIPE_COUNT 2 #define T13_DESC "ost_index error handling" static void test13(void) { int rc; int fd; uint64_t idx; struct llapi_layout *layout; char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T13FILE); layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno = %d", errno); /* invalid OST index */ errno = 0; rc = llapi_layout_ost_index_set(layout, 0, LLAPI_LAYOUT_INVALID); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); errno = 0; rc = llapi_layout_ost_index_set(layout, 0, -1); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* NULL layout */ errno = 0; rc = llapi_layout_ost_index_set(NULL, 0, 1); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); errno = 0; rc = llapi_layout_ost_index_get(NULL, 0, &idx); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* NULL index */ errno = 0; rc = llapi_layout_ost_index_get(layout, 0, NULL); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* Layout not read from file so has no OST data. */ errno = 0; rc = llapi_layout_stripe_count_set(layout, T13_STRIPE_COUNT); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_ost_index_get(layout, 0, &idx); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); /* n greater than stripe count*/ rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); rc = llapi_layout_stripe_count_set(layout, T13_STRIPE_COUNT); ASSERTF(rc == 0, "errno = %d", errno); fd = llapi_layout_file_create(path, 0, 0644, layout); ASSERTF(fd >= 0, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); llapi_layout_free(layout); layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); errno = 0; rc = llapi_layout_ost_index_get(layout, T13_STRIPE_COUNT + 1, &idx); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); llapi_layout_free(layout); } /* Verify llapi_layout_file_create() returns errors as expected */ #define T14_DESC "llapi_layout_file_create error handling" static void test14(void) { int rc; struct llapi_layout *layout = llapi_layout_alloc(); /* NULL path */ errno = 0; rc = llapi_layout_file_create(NULL, 0, 0, layout); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d", rc, errno); llapi_layout_free(layout); } /* Can't change striping attributes of existing file. */ #define T15FILE "t15" #define T15_STRIPE_COUNT 2 #define T15_DESC "Can't change striping attributes of existing file" static void test15(void) { int rc; int fd; uint64_t count; struct llapi_layout *layout; char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T15FILE); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_stripe_count_set(layout, T15_STRIPE_COUNT); ASSERTF(rc == 0, "errno = %d", errno); errno = 0; fd = llapi_layout_file_create(path, 0, 0640, layout); ASSERTF(fd >= 0, "fd = %d, errno = %d", fd, errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_stripe_count_set(layout, T15_STRIPE_COUNT - 1); errno = 0; fd = llapi_layout_file_open(path, 0, 0640, layout); ASSERTF(fd >= 0, "fd = %d, errno = %d", fd, errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); llapi_layout_free(layout); layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(rc == 0 && count == T15_STRIPE_COUNT, "rc = %d, %"PRIu64" != %d", rc, count, T15_STRIPE_COUNT); llapi_layout_free(layout); } /* Default stripe attributes are applied as expected. */ #define T16FILE "t16" #define T16_DESC "Default stripe attributes are applied as expected" static void test16(void) { int rc; int fd; struct llapi_layout *deflayout; struct llapi_layout *filelayout; char path[PATH_MAX]; uint64_t fsize; uint64_t fcount; uint64_t dsize; uint64_t dcount; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T16FILE); rc = unlink(path); ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno); deflayout = llapi_layout_get_by_path(lustre_dir, LAYOUT_GET_EXPECTED); ASSERTF(deflayout != NULL, "errno = %d", errno); rc = llapi_layout_stripe_size_get(deflayout, &dsize); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_stripe_count_get(deflayout, &dcount); ASSERTF(rc == 0, "errno = %d", errno); /* First, with a default struct llapi_layout */ filelayout = llapi_layout_alloc(); ASSERTF(filelayout != NULL, "errno = %d", errno); fd = llapi_layout_file_create(path, 0, 0640, filelayout); ASSERTF(fd >= 0, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); llapi_layout_free(filelayout); filelayout = llapi_layout_get_by_path(path, 0); ASSERTF(filelayout != NULL, "errno = %d", errno); rc = llapi_layout_stripe_count_get(filelayout, &fcount); ASSERTF(rc == 0, "errno = %d", errno); ASSERTF(fcount == dcount || dcount == LLAPI_LAYOUT_DEFAULT || IN_RANGE(dcount, LLAPI_LAYOUT_WIDE_MIN, LLAPI_LAYOUT_WIDE_MAX), "%"PRIu64" != %"PRIu64, fcount, dcount); rc = llapi_layout_stripe_size_get(filelayout, &fsize); ASSERTF(rc == 0, "errno = %d", errno); ASSERTF(fsize == dsize, "%"PRIu64" != %"PRIu64, fsize, dsize); /* NULL layout also implies default layout */ rc = unlink(path); ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno); fd = llapi_layout_file_create(path, 0, 0640, filelayout); ASSERTF(fd >= 0, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); filelayout = llapi_layout_get_by_path(path, 0); ASSERTF(filelayout != NULL, "errno = %d", errno); rc = llapi_layout_stripe_count_get(filelayout, &fcount); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_stripe_size_get(filelayout, &fsize); ASSERTF(rc == 0, "errno = %d", errno); ASSERTF(fcount == dcount || dcount == LLAPI_LAYOUT_DEFAULT || IN_RANGE(dcount, LLAPI_LAYOUT_WIDE_MIN, LLAPI_LAYOUT_WIDE_MAX), "%"PRIu64" != %"PRIu64, fcount, dcount); ASSERTF(fsize == dsize, "%"PRIu64" != %"PRIu64, fsize, dsize); llapi_layout_free(filelayout); llapi_layout_free(deflayout); } /* Setting stripe count to LLAPI_LAYOUT_WIDE uses all available OSTs. */ #define T17FILE "t17" #define T17_DESC "LLAPI_LAYOUT_WIDE is honored" static void test17(void) { int rc; int fd; int osts_all; uint64_t osts_layout; struct llapi_layout *layout; char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T17FILE); rc = unlink(path); ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno); layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_stripe_count_set(layout, LLAPI_LAYOUT_WIDE); ASSERTF(rc == 0, "errno = %d", errno); fd = llapi_layout_file_create(path, 0, 0640, layout); ASSERTF(fd >= 0, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); llapi_layout_free(layout); /* Get number of available OSTs */ fd = open(path, O_RDONLY); ASSERTF(fd >= 0, "errno = %d", errno); rc = llapi_lov_get_uuids(fd, NULL, &osts_all); ASSERTF(rc == 0, "rc = %d, errno = %d", rc, errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_stripe_count_get(layout, &osts_layout); ASSERTF(osts_layout == osts_all, "%"PRIu64" != %d", osts_layout, osts_all); llapi_layout_free(layout); } /* Setting pool with "fsname.pool" notation. */ #define T18FILE "t18" #define T18_DESC "Setting pool with fsname.pool notation" static void test18(void) { int rc; int fd; struct llapi_layout *layout = llapi_layout_alloc(); char path[PATH_MAX]; char pool[LOV_MAXPOOLNAME*2 + 1]; char mypool[LOV_MAXPOOLNAME + 1] = { '\0' }; snprintf(pool, sizeof(pool), "lustre.%s", poolname); snprintf(path, sizeof(path), "%s/%s", lustre_dir, T18FILE); ASSERTF(layout != NULL, "errno = %d", errno); rc = unlink(path); ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno); rc = llapi_layout_pool_name_set(layout, pool); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_pool_name_get(layout, mypool, sizeof(mypool)); ASSERTF(rc == 0, "errno = %d", errno); rc = strcmp(mypool, poolname); ASSERTF(rc == 0, "%s != %s", mypool, poolname); fd = llapi_layout_file_create(path, 0, 0640, layout); ASSERTF(fd >= 0, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); llapi_layout_free(layout); layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_pool_name_get(layout, mypool, sizeof(mypool)); ASSERTF(rc == 0, "errno = %d", errno); rc = strcmp(mypool, poolname); ASSERTF(rc == 0, "%s != %s", mypool, poolname); llapi_layout_free(layout); } #define T19_DESC "Maximum length pool name is NULL-terminated" static void test19(void) { struct llapi_layout *layout; char *name = "0123456789abcde"; char mypool[LOV_MAXPOOLNAME + 1] = { '\0' }; int rc; layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_pool_name_set(layout, name); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_pool_name_get(layout, mypool, sizeof(mypool)); ASSERTF(strlen(name) == strlen(mypool), "name = %s, str = %s", name, mypool); llapi_layout_free(layout); } #define T20FILE "t20" #define T20_DESC "LLAPI_LAYOUT_DEFAULT is honored" static void test20(void) { int rc; int fd; struct llapi_layout *deflayout; struct llapi_layout *filelayout; char path[PATH_MAX]; uint64_t fsize; uint64_t fcount; uint64_t dsize; uint64_t dcount; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T20FILE); rc = unlink(path); ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno); filelayout = llapi_layout_alloc(); ASSERTF(filelayout != NULL, "errno = %d", errno); rc = llapi_layout_stripe_size_set(filelayout, LLAPI_LAYOUT_DEFAULT); ASSERTF(rc == 0, "rc = %d, errno = %d", rc, errno); rc = llapi_layout_stripe_count_set(filelayout, LLAPI_LAYOUT_DEFAULT); ASSERTF(rc == 0, "rc = %d, errno = %d", rc, errno); fd = llapi_layout_file_create(path, 0, 0640, filelayout); ASSERTF(fd >= 0, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); llapi_layout_free(filelayout); deflayout = llapi_layout_get_by_path(lustre_dir, LAYOUT_GET_EXPECTED); ASSERTF(deflayout != NULL, "errno = %d", errno); filelayout = llapi_layout_get_by_path(path, 0); ASSERTF(filelayout != NULL, "errno = %d", errno); rc = llapi_layout_stripe_count_get(filelayout, &fcount); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_stripe_count_get(deflayout, &dcount); ASSERTF(rc == 0, "errno = %d", errno); ASSERTF(fcount == dcount || dcount == LLAPI_LAYOUT_DEFAULT || dcount == LLAPI_LAYOUT_WIDE, "%"PRIu64" != %"PRIu64, fcount, dcount); rc = llapi_layout_stripe_size_get(filelayout, &fsize); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_stripe_size_get(deflayout, &dsize); ASSERTF(rc == 0, "errno = %d", errno); ASSERTF(fsize == dsize, "%"PRIu64" != %"PRIu64, fsize, dsize); llapi_layout_free(filelayout); llapi_layout_free(deflayout); } #define T21_DESC "llapi_layout_file_create fails for non-Lustre file" static void test21(void) { struct llapi_layout *layout; char template[PATH_MAX]; int fd; int rc; snprintf(template, sizeof(template), "%s/XXXXXX", P_tmpdir); fd = mkstemp(template); ASSERTF(fd >= 0, "template = %s, errno = %d", template, errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", fd); rc = unlink(template); ASSERTF(rc == 0, "errno = %d", errno); layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno = %d", errno); fd = llapi_layout_file_create(template, 0, 0640, layout); ASSERTF(fd == -1 && errno == ENOTTY, "fd = %d, errno = %d, template = %s", fd, errno, template); llapi_layout_free(layout); } #define T22FILE "t22" #define T22_DESC "llapi_layout_file_create applied mode correctly" static void test22(void) { int rc; int fd; char path[PATH_MAX]; struct stat st; mode_t mode_in = 0640; mode_t mode_out; mode_t umask_orig; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T22FILE); rc = unlink(path); ASSERTF(rc == 0 || errno == ENOENT, "errno = %d", errno); umask_orig = umask(0022); fd = llapi_layout_file_create(path, 0, mode_in, NULL); ASSERTF(fd >= 0, "errno = %d", errno); (void) umask(umask_orig); rc = fstat(fd, &st); ASSERTF(rc == 0, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", fd); mode_out = st.st_mode & ~S_IFMT; ASSERTF(mode_in == mode_out, "%o != %o", mode_in, mode_out); } #define T23_DESC "llapi_layout_get_by_path fails for non-Lustre file" static void test23(void) { struct llapi_layout *layout; char template[PATH_MAX]; int fd; int rc; snprintf(template, sizeof(template), "%s/XXXXXX", P_tmpdir); fd = mkstemp(template); ASSERTF(fd >= 0, "template = %s, errno = %d", template, errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", fd); layout = llapi_layout_get_by_path(template, 0); ASSERTF(layout == NULL && errno == ENOTTY, "errno = %d, template = %s", errno, template); rc = unlink(template); ASSERTF(rc == 0, "errno = %d", errno); } /* llapi_layout_get_by_path(path, LAYOUT_GET_EXPECTED) returns expected layout * for file with unspecified layout. */ #define T24FILE "t24" #define T24_DESC "LAYOUT_GET_EXPECTED works with existing file" static void test24(void) { int fd; int rc; struct llapi_layout *layout; uint64_t count; uint64_t size; uint64_t pattern; char path[PATH_MAX]; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T24FILE); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); fd = open(path, O_CREAT, 0640); ASSERTF(fd >= 0, "errno = %d", errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); layout = llapi_layout_get_by_path(path, LAYOUT_GET_EXPECTED); ASSERTF(layout != NULL, "errno = %d\n", errno); rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(count != LLAPI_LAYOUT_DEFAULT, "expected literal value"); rc = llapi_layout_stripe_size_get(layout, &size); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(size != LLAPI_LAYOUT_DEFAULT, "expected literal value"); rc = llapi_layout_pattern_get(layout, &pattern); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(pattern != LLAPI_LAYOUT_DEFAULT, "expected literal value"); llapi_layout_free(layout); } /* llapi_layout_get_by_path(path, LAYOUT_GET_EXPECTED) returns expected layout * for directory with unspecified layout. */ #define T25DIR "d25" #define T25_DESC "LAYOUT_GET_EXPECTED works with directory" static void test25(void) { int rc; struct llapi_layout *layout; uint64_t count; uint64_t size; uint64_t pattern; char dir[PATH_MAX]; snprintf(dir, sizeof(dir), "%s/%s", lustre_dir, T25DIR); rc = rmdir(dir); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); rc = mkdir(dir, 0750); ASSERTF(rc == 0, "errno = %d", errno); layout = llapi_layout_get_by_path(dir, LAYOUT_GET_EXPECTED); ASSERTF(layout != NULL, "errno = %d\n", errno); rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(count != LLAPI_LAYOUT_DEFAULT, "expected literal value"); rc = llapi_layout_stripe_size_get(layout, &size); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(size != LLAPI_LAYOUT_DEFAULT, "expected literal value"); rc = llapi_layout_pattern_get(layout, &pattern); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(pattern != LLAPI_LAYOUT_DEFAULT, "expected literal value"); llapi_layout_free(layout); } /* llapi_layout_get_by_path(path, LAYOUT_GET_EXPECTED) correctly combines * specified attributes of parent directory with attributes filesystem root. */ #define T26DIR "d26" #define T26_DESC "LAYOUT_GET_EXPECTED partially specified parent" #define T26_STRIPE_SIZE (1048576 * 4) static void test26(void) { int rc; struct llapi_layout *layout; const char *lfs = getenv("LFS"); uint64_t count; uint64_t size; uint64_t pattern; char dir[PATH_MAX]; char cmd[PATH_MAX + 64]; snprintf(dir, sizeof(dir), "%s/%s", lustre_dir, T26DIR); rc = rmdir(dir); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); rc = mkdir(dir, 0750); ASSERTF(rc == 0, "errno = %d", errno); if (lfs == NULL) lfs = "/usr/bin/lfs"; snprintf(cmd, sizeof(cmd), "%s setstripe -S %d %s", lfs, T26_STRIPE_SIZE, dir); rc = system(cmd); ASSERTF(rc == 0, "system(%s): exit status %d", cmd, WEXITSTATUS(rc)); layout = llapi_layout_get_by_path(dir, LAYOUT_GET_EXPECTED); ASSERTF(layout != NULL, "errno = %d\n", errno); rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(count != LLAPI_LAYOUT_DEFAULT, "expected literal value"); rc = llapi_layout_stripe_size_get(layout, &size); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(size == T26_STRIPE_SIZE, "size = %"PRIu64, size); rc = llapi_layout_pattern_get(layout, &pattern); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(pattern != LLAPI_LAYOUT_DEFAULT, "expected literal value"); llapi_layout_free(layout); } /* llapi_layout_get_by_path(path, LAYOUT_GET_EXPECTED) work with * non existing file. */ #define T27DIR "d27" #define T27_DESC "LAYOUT_GET_EXPECTED with non existing file" #define T27_STRIPE_SIZE (1048576 * 3) static void test27(void) { int rc; struct llapi_layout *layout; const char *lfs = getenv("LFS"); uint64_t count; uint64_t size; uint64_t pattern; char dirpath[PATH_MAX + 128]; char filepath[PATH_MAX * 2]; char cmd[PATH_MAX * 2]; snprintf(dirpath, sizeof(dirpath) - 1, "%s/%s", lustre_dir, T27DIR); snprintf(filepath, sizeof(filepath), "%s/nonesuch", dirpath); rc = rmdir(dirpath); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); rc = mkdir(dirpath, 0750); ASSERTF(rc == 0, "errno = %d", errno); if (lfs == NULL) lfs = "/usr/bin/lfs"; snprintf(cmd, sizeof(cmd), "%s setstripe -S %d %s", lfs, T27_STRIPE_SIZE, dirpath); rc = system(cmd); ASSERTF(rc == 0, "system(%s): exit status %d", cmd, WEXITSTATUS(rc)); layout = llapi_layout_get_by_path(filepath, LAYOUT_GET_EXPECTED); ASSERTF(layout != NULL, "errno = %d\n", errno); rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(count != LLAPI_LAYOUT_DEFAULT, "expected literal value"); rc = llapi_layout_stripe_size_get(layout, &size); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(size == T27_STRIPE_SIZE, "size = %"PRIu64, size); rc = llapi_layout_pattern_get(layout, &pattern); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(pattern != LLAPI_LAYOUT_DEFAULT, "expected literal value"); llapi_layout_free(layout); } /* llapi_layout_stripe_count_get returns LLAPI_LAYOUT_WIDE for a directory * with a stripe_count of -1. */ #define T28DIR "d28" #define T28_DESC "LLAPI_LAYOUT_WIDE returned as expected" static void test28(void) { int rc; struct llapi_layout *layout; const char *lfs = getenv("LFS"); uint64_t count; char dirpath[PATH_MAX]; char cmd[PATH_MAX + 64]; snprintf(dirpath, sizeof(dirpath), "%s/%s", lustre_dir, T28DIR); rc = rmdir(dirpath); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); rc = mkdir(dirpath, 0750); ASSERTF(rc == 0, "errno = %d", errno); if (lfs == NULL) lfs = "/usr/bin/lfs"; snprintf(cmd, sizeof(cmd), "%s setstripe -c -1 %s", lfs, dirpath); rc = system(cmd); ASSERTF(rc == 0, "system(%s): exit status %d", cmd, WEXITSTATUS(rc)); layout = llapi_layout_get_by_path(dirpath, 0); ASSERTF(layout != NULL, "errno = %d\n", errno); rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(rc == 0, "errno = %d\n", errno); ASSERTF(count == LLAPI_LAYOUT_WIDE, "count = %"PRIu64"\n", count); llapi_layout_free(layout); } #define T29FILE "f29" #define T29_DESC "set ost index to non-zero stripe number" static void test29(void) { int rc, fd, i; uint64_t ost0, ost1, nost; struct llapi_layout *layout; char path[PATH_MAX]; if (num_osts < 2) return; layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno %d", errno); snprintf(path, sizeof(path), "%s/%s", lustre_dir, T29FILE); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); /* set ost index to LLAPI_LAYOUT_IDX_MAX should fail */ rc = llapi_layout_ost_index_set(layout, 1, LLAPI_LAYOUT_IDX_MAX); ASSERTF(rc == -1 && errno == EINVAL, "rc = %d, errno = %d\n", rc, errno); /* specify ost index partially */ rc = llapi_layout_ost_index_set(layout, 1, 0); ASSERTF(rc == 0, "errno = %d", errno); /* create a partially specified layout will fail */ fd = llapi_layout_file_create(path, 0, 0660, layout); ASSERTF(fd == -1 && errno == EINVAL, "path = %s, fd = %d, errno = %d", path, fd, errno); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); /* specify all stripes */ rc = llapi_layout_ost_index_set(layout, 0, 1); ASSERTF(rc == 0, "errno = %d", errno); /* create */ fd = llapi_layout_file_create(path, 0, 0660, layout); ASSERTF(fd >= 0, "path = %s, fd = %d, errno = %d", path, fd, errno); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); llapi_layout_free(layout); /* get layout from file */ layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_ost_index_get(layout, 0, &ost0); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_ost_index_get(layout, 1, &ost1); ASSERTF(rc == 0, "errno = %d", errno); ASSERTF(ost0 == 1, "%"PRIu64" != %d", ost0, 1); ASSERTF(ost1 == 0, "%"PRIu64" != %d", ost1, 0); llapi_layout_free(layout); /* specify more ost indexes to test realloc */ nost = 0; layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno %d", errno); for (i = 0; i < LOV_MAX_STRIPE_COUNT; i++) { rc = llapi_layout_ost_index_set(layout, i, nost); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_ost_index_get(layout, i, &ost0); ASSERTF(rc == 0, "errno = %d", errno); nost++; if (nost == num_osts) nost = 0; } nost = 0; for (i = 0; i < LOV_MAX_STRIPE_COUNT; i++) { rc = llapi_layout_ost_index_get(layout, i, &ost0); ASSERTF(rc == 0, "errno = %d", errno); ASSERTF(ost0 == nost, "ost=%"PRIu64" nost=%"PRIu64"", ost0, nost); nost++; if (nost == num_osts) nost = 0; } llapi_layout_free(layout); nost = 0; layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno %d", errno); for (i = LOV_MAX_STRIPE_COUNT-1; i >= 0; i--) { rc = llapi_layout_ost_index_set(layout, i, nost); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_ost_index_get(layout, i, &ost0); ASSERTF(rc == 0, "errno = %d", errno); nost++; if (nost == num_osts) nost = 0; } nost = 0; for (i = LOV_MAX_STRIPE_COUNT-1; i <= 0; i--) { rc = llapi_layout_ost_index_get(layout, i, &ost0); ASSERTF(rc == 0, "errno = %d", errno); ASSERTF(ost0 == nost, "ost=%"PRIu64", nost=%"PRIu64"", ost0, nost); nost++; if (nost == num_osts) nost = 0; } llapi_layout_free(layout); } #define T30FILE "f30" #define T30_DESC "create composite file, traverse components" static void test30(void) { int rc, fd; uint64_t start[3], end[3]; uint64_t s, e; struct llapi_layout *layout; char path[PATH_MAX]; start[0] = 0; end[0] = 64 * 1024 * 1024; /* 64m */ start[1] = end[0]; end[1] = 1 * 1024 * 1024 * 1024; /* 1G */ start[2] = end[1]; end[2] = LUSTRE_EOF; if (num_osts < 2) return; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T30FILE); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno %d", errno); rc = llapi_layout_stripe_count_set(layout, 1); ASSERTF(rc == 0, "errno %d", errno); /* add component without adjusting previous component's extent * end will fail. */ rc = llapi_layout_comp_add(layout); ASSERTF(rc == -1 && errno == EINVAL, "rc %d, errno %d", rc, errno); rc = llapi_layout_comp_extent_set(layout, start[0], end[0]); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_add(layout); ASSERTF(rc == 0, "errno %d", errno); /* set non-contiguous extent will fail */ rc = llapi_layout_comp_extent_set(layout, start[1] * 2, end[1]); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_sanity(layout, false, false); ASSERTF(rc == 12 /*LSE_NOT_ADJACENT_PREV*/, "rc %d", rc); rc = llapi_layout_comp_extent_set(layout, start[1], end[1]); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_add(layout); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_extent_set(layout, start[2], end[2]); ASSERTF(rc == 0, "errno %d", errno); /* create composite file */ fd = llapi_layout_file_create(path, 0, 0660, layout); ASSERTF(fd >= 0, "path = %s, fd = %d, errno = %d", path, fd, errno); llapi_layout_free(layout); /* traverse & verify all components */ layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); /* current component should be the tail component */ rc = llapi_layout_comp_extent_get(layout, &s, &e); ASSERTF(rc == 0, "errno %d", errno); ASSERTF(s == start[2] && e == end[2], "s: %"PRIu64", e: %"PRIu64"", s, e); rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST); ASSERTF(rc == 0, "rc %d, errno %d", rc, errno); /* delete non-tail component will fail */ rc = llapi_layout_comp_del(layout); ASSERTF(rc == -1 && errno == EINVAL, "rc %d, errno %d", rc, errno); rc = llapi_layout_comp_extent_get(layout, &s, &e); ASSERTF(rc == 0, "errno %d", errno); ASSERTF(s == start[0] && e == end[0], "s: %"PRIu64", e: %"PRIu64"", s, e); rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT); ASSERTF(rc == 0, "rc %d, errno %d", rc, errno); rc = llapi_layout_comp_extent_get(layout, &s, &e); ASSERTF(rc == 0, "errno %d", errno); ASSERTF(s == start[1] && e == end[1], "s: %"PRIu64", e: %"PRIu64"", s, e); rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT); ASSERTF(rc == 0, "rc %d, errno %d", rc, errno); rc = llapi_layout_comp_del(layout); ASSERTF(rc == 0, "errno %d", errno); llapi_layout_free(layout); } #define T31FILE "f31" #define T31_DESC "add/delete component to/from existing file" static void test31(void) { int rc, fd, i; uint64_t start[2], end[2]; uint64_t s, e; uint32_t id[2]; struct llapi_layout *layout; char path[PATH_MAX]; start[0] = 0; end[0] = 64 * 1024 * 1024; /* 64m */ start[1] = end[0]; end[1] = LUSTRE_EOF; if (num_osts < 2) return; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T31FILE); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno %d", errno); rc = llapi_layout_stripe_count_set(layout, 1); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_extent_set(layout, start[0], end[0]); ASSERTF(rc == 0, "errno %d", errno); /* create composite file */ fd = llapi_layout_file_create(path, 0, 0660, layout); ASSERTF(fd >= 0, "path = %s, fd = %d, errno = %d", path, fd, errno); llapi_layout_free(layout); layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno %d", errno); rc = llapi_layout_stripe_count_set(layout, 2); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_extent_set(layout, start[1], end[1]); ASSERTF(rc == 0, "errno %d", errno); /* add comopnent to existing file */ rc = llapi_layout_file_comp_add(path, layout); ASSERTF(rc == 0, "errno %d", errno); llapi_layout_free(layout); /* verify the composite layout after adding */ layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST); ASSERTF(rc == 0, "rc %d, errno %d", rc, errno); i = 0; do { rc = llapi_layout_comp_extent_get(layout, &s, &e); ASSERTF(rc == 0 && i < 2, "i %d, errno %d", i, errno); ASSERTF(s == start[i] && e == end[i], "i: %d s: %"PRIu64", e: %"PRIu64"", i, s, e); rc = llapi_layout_comp_id_get(layout, &id[i]); ASSERTF(rc == 0 && id[i] != 0, "i %d, errno %d, id %d", i, errno, id[i]); rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT); ASSERTF(rc == 0 || i == 1, "i=%d rc=%d errno=%d", i, rc, errno); i++; } while (rc == 0); /* Verify reverse iteration gives the same IDs as forward iteration */ rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_LAST); ASSERTF(rc == 0, "rc %d, errno %d", rc, errno); do { __u32 comp_id; --i; rc = llapi_layout_comp_id_get(layout, &comp_id); ASSERTF(rc == 0 && comp_id == id[i], "i %d, errno %d, id[] %u/%u", i, errno, id[i], comp_id); rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_PREV); ASSERTF(rc == 0 || i == 0, "i=%d rc=%d errno=%d", i, rc, errno); } while (rc == 0); llapi_layout_free(layout); /* delete non-tail component will fail */ rc = llapi_layout_file_comp_del(path, id[0], 0); ASSERTF(rc < 0 && errno == EINVAL, "rc %d, errno %d", rc, errno); rc = llapi_layout_file_comp_del(path, id[1], 0); ASSERTF(rc == 0, "rc %d, errno %d", rc, errno); /* verify the composite layout after deleting */ layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST); ASSERTF(rc == 0, "rc %d, errno %d", rc, errno); rc = llapi_layout_comp_extent_get(layout, &s, &e); ASSERTF(rc == 0, "errno %d", errno); ASSERTF(s == start[0] && e == end[0], "s: %"PRIu64", e: %"PRIu64"", s, e); } #define T32FILE "t32" #define T32_STRIPE_COUNT (num_osts*2) #define T32_DESC "Test overstriping with layout_file_create" static void test32(void) { int rc; int fd; uint64_t count; struct llapi_layout *layout = llapi_layout_alloc(); void *lmdbuf = NULL; struct lov_user_md *lmd; char path[PATH_MAX]; ASSERTF(layout != NULL, "errno %d", errno); /* Maximum possible, to be on the safe side - num_osts could be large */ lmdbuf = malloc(XATTR_SIZE_MAX); ASSERTF(lmdbuf != NULL, "errno %d", errno); lmd = lmdbuf; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T32FILE); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); /* stripe count */ rc = llapi_layout_stripe_count_set(layout, T32_STRIPE_COUNT); ASSERTF(rc == 0, "errno = %d", errno); rc = llapi_layout_stripe_count_get(layout, &count); ASSERTF(rc == 0 && count == T32_STRIPE_COUNT, "%"PRIu64" != %d", count, T32_STRIPE_COUNT); rc = llapi_layout_pattern_set(layout, LLAPI_LAYOUT_OVERSTRIPING); ASSERTF(rc == 0, "errno = %d", errno); /* create */ fd = llapi_layout_file_create(path, 0, 0660, layout); ASSERTF(fd >= 0, "path = %s, errno = %d", path, errno); rc = ioctl(fd, LL_IOC_LOV_GETSTRIPE_NEW, lmdbuf); ASSERTF(rc == 0, "errno = %d", errno); count = lmd->lmm_stripe_count; ASSERTF(count == T32_STRIPE_COUNT, "stripe count (%"PRIu64") not equal to expected (%d)", count, T32_STRIPE_COUNT); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); llapi_layout_free(layout); free(lmdbuf); } #define T33FILE "t33" #define T33_STRIPE_COUNT (num_osts*2) #define T33_DESC "Test overstriping with llapi_file_open" static void test33(void) { int rc; int fd; uint64_t count; void *lmdbuf = NULL; struct lov_user_md *lmd; char path[PATH_MAX]; /* Maximum possible, to be on the safe side - num_osts could be large */ lmdbuf = malloc(XATTR_SIZE_MAX); ASSERTF(lmdbuf != NULL, "errno %d", errno); lmd = lmdbuf; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T33FILE); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); fd = llapi_file_open(path, O_CREAT | O_RDWR, 0660, 0, -1, num_osts*2, LOV_PATTERN_RAID0 | LOV_PATTERN_OVERSTRIPING); ASSERTF(fd >= 0, "path = %s, errno = %d", path, errno); rc = ioctl(fd, LL_IOC_LOV_GETSTRIPE_NEW, lmdbuf); ASSERTF(rc == 0, "errno = %d", errno); count = lmd->lmm_stripe_count; ASSERTF(count == T33_STRIPE_COUNT, "stripe count (%"PRIu64") not equal to expected (%d)", count, T33_STRIPE_COUNT); rc = close(fd); ASSERTF(rc == 0, "errno = %d", errno); free(lmdbuf); } #define T34FILE "f34" #define T34_DESC "create simple valid & invalid self extending layouts" static void test34(void) { int rc, fd; uint64_t start[4], end[4]; struct llapi_layout *layout; char path[PATH_MAX]; start[0] = 0; end[0] = 10 * 1024 * 1024; /* 10m */ start[1] = end[0]; end[1] = 1024 * 1024 * 1024; /* 1G */ start[2] = end[1]; end[2] = 10ull * 1024 * 1024 * 1024; /* 10G */ start[3] = end[2]; end[3] = LUSTRE_EOF; if (num_osts < 2) return; snprintf(path, sizeof(path), "%s/%s", lustre_dir, T34FILE); rc = unlink(path); ASSERTF(rc >= 0 || errno == ENOENT, "errno = %d", errno); layout = llapi_layout_alloc(); ASSERTF(layout != NULL, "errno %d", errno); rc = llapi_layout_stripe_count_set(layout, 1); ASSERTF(rc == 0, "errno %d", errno); /* add component without adjusting previous component's extent * end will fail. */ rc = llapi_layout_comp_add(layout); ASSERTF(rc == -1 && errno == EINVAL, "rc %d, errno %d", rc, errno); rc = llapi_layout_comp_extent_set(layout, start[0], end[0]); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_add(layout); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_extent_set(layout, start[1], end[1]); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_flags_set(layout, LCME_FL_EXTENSION); ASSERTF(rc == 0, "errno %d", errno); /* Invalid size, too small - < 64 MiB */ rc = llapi_layout_extension_size_set(layout, 32 << 20); ASSERTF(rc == -1, "errno %d", errno); /* too large - > 4 TiB */ rc = llapi_layout_extension_size_set(layout, 5ull << 40); ASSERTF(rc == -1, "errno %d", errno); /* Valid size, 64 MiB */ rc = llapi_layout_extension_size_set(layout, 64 << 20); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_add(layout); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_extent_set(layout, start[2], end[2]); ASSERTF(rc == 0, "errno %d", errno); /* Set extension space flag on adjacent components: * This is invalid, but can't be checked until we create the file. */ rc = llapi_layout_comp_flags_set(layout, LCME_FL_EXTENSION); ASSERTF(rc == 0, "errno %d", errno); fd = llapi_layout_file_create(path, 0, 0660, layout); ASSERTF(fd = -1, "path = %s, fd = %d, errno = %d", path, fd, errno); /* Delete incorrect component */ rc = llapi_layout_comp_del(layout); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_add(layout); ASSERTF(rc == 0, "errno %d", errno); /* Convert this comp to 0-len that can be followed by extension space */ rc = llapi_layout_comp_extent_set(layout, start[2], start[2]); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_add(layout); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_extent_set(layout, start[2], end[3]); ASSERTF(rc == 0, "errno %d", errno); rc = llapi_layout_comp_flags_set(layout, LCME_FL_EXTENSION); ASSERTF(rc == 0, "errno %d", errno); /* create composite file */ fd = llapi_layout_file_create(path, 0, 0660, layout); ASSERTF(fd >= 0, "path = %s, fd = %d, errno = %d", path, fd, errno); llapi_layout_free(layout); /* traverse & verify all components */ layout = llapi_layout_get_by_path(path, 0); ASSERTF(layout != NULL, "errno = %d", errno); rc = llapi_layout_sanity(layout, false, false); ASSERTF(rc == 0, "errno %d", errno); } static struct test_tbl_entry test_tbl[] = { 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 }; static void process_args(int argc, char *argv[]) { int c; while ((c = getopt(argc, argv, "d:p:o:s:t:")) != -1) { switch (c) { case 'd': 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_to_skip(optarg, test_tbl); break; case 't': set_tests_to_run(optarg, test_tbl); break; case '?': fprintf(stderr, "Unknown option '%c'\n", optopt); usage(argv[0]); } } } int main(int argc, char *argv[]) { process_args(argc, argv); return run_tests(lustre_dir, test_tbl); }