/* * 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 */ /* * Copyright 2016 Cray Inc. All rights reserved. * Authors: Patrick Farrell, Frank Zago * * A few portions are extracted from llapi_layout_test.c * * The purpose of this test is to exercise the lockahead advice of ladvise. * * The program will exit as soon as a test fails. */ #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(-1); \ } while (0) #define ASSERTF(cond, fmt, ...) \ do { \ if (!(cond)) \ DIE("assertion '%s' failed: "fmt, \ #cond, ## __VA_ARGS__); \ } while (0) #define PERFORM(testfn) \ do { \ cleanup(); \ fprintf(stderr, "Starting test " #testfn " at %lld\n", \ (unsigned long long)time(NULL)); \ rc = testfn(); \ fprintf(stderr, "Finishing test " #testfn " at %lld\n", \ (unsigned long long)time(NULL)); \ } while (0) /* Name of file/directory. Will be set once and will not change. */ static char mainpath[PATH_MAX]; static char *mainfile; static char fsmountdir[PATH_MAX]; /* Lustre mountpoint */ static char *lustre_dir; /* Test directory inside Lustre */ static int single_test; /* Number of a single test to execute*/ /* Cleanup our test file. */ static void cleanup(void) { unlink(mainpath); } /* Trivial helper for one advice */ void setup_ladvise_lockahead(struct llapi_lu_ladvise *advice, int mode, int flags, size_t start, size_t end, bool async) { advice->lla_advice = LU_LADVISE_LOCKAHEAD; advice->lla_lockahead_mode = mode; if (async) advice->lla_peradvice_flags = flags | LF_ASYNC; else advice->lla_peradvice_flags = flags; advice->lla_start = start; advice->lla_end = end; advice->lla_value3 = 0; advice->lla_value4 = 0; } /* Test valid single lock ahead request */ static int test10(void) { struct llapi_lu_ladvise advice; const int count = 1; int fd; size_t write_size = 1024 * 1024; int rc; char buf[write_size]; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); setup_ladvise_lockahead(&advice, MODE_WRITE_USER, 0, 0, write_size - 1, true); /* Manually set the result so we can verify it's being modified */ advice.lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); ASSERTF(advice.lla_lockahead_result == 0, "unexpected extent result: %d", advice.lla_lockahead_result); memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); close(fd); return 0; } /* Get lock, wait until lock is taken */ static int test11(void) { struct llapi_lu_ladvise advice; const int count = 1; int fd; size_t write_size = 1024 * 1024; int rc; char buf[write_size]; int i; int enqueue_requests = 0; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); setup_ladvise_lockahead(&advice, MODE_WRITE_USER, 0, 0, write_size - 1, true); /* Manually set the result so we can verify it's being modified */ advice.lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); ASSERTF(advice.lla_lockahead_result == 0, "unexpected extent result: %d", advice.lla_lockahead_result); enqueue_requests++; /* Ask again until we get the lock (status 1). */ for (i = 1; i < 100; i++) { usleep(100000); /* 0.1 second */ advice.lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); if (advice.lla_lockahead_result > 0) break; enqueue_requests++; } ASSERTF(advice.lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result: %d", advice.lla_lockahead_result); /* Again. This time it is always there. */ for (i = 0; i < 100; i++) { advice.lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); ASSERTF(advice.lla_lockahead_result > 0, "unexpected extent result: %d", advice.lla_lockahead_result); } memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); close(fd); return enqueue_requests; } /* Test with several times the same extent */ static int test12(void) { struct llapi_lu_ladvise *advice; const int count = 10; int fd; size_t write_size = 1024 * 1024; int rc; char buf[write_size]; int i; int expected_lock_count = 0; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); advice = malloc(sizeof(struct llapi_lu_ladvise)*count); for (i = 0; i < count; i++) { setup_ladvise_lockahead(&(advice[i]), MODE_WRITE_USER, 0, 0, write_size - 1, true); advice[i].lla_lockahead_result = 98674; } rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); for (i = 0; i < count; i++) { ASSERTF(advice[i].lla_lockahead_result >= 0, "unexpected extent result for extent %d: %d", i, advice[i].lla_lockahead_result); } /* Since all the requests are for the same extent, we should only have * one lock at the end. */ expected_lock_count = 1; /* Ask again until we get the locks. */ for (i = 1; i < 100; i++) { usleep(100000); /* 0.1 second */ advice[count-1].lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); if (advice[count-1].lla_lockahead_result > 0) break; } ASSERTF(advice[count-1].lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result: %d", advice[count-1].lla_lockahead_result); memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); free(advice); close(fd); return expected_lock_count; } /* Grow a lock forward */ static int test13(void) { struct llapi_lu_ladvise *advice = NULL; const int count = 1; int fd; size_t write_size = 1024 * 1024; int rc; char buf[write_size]; int i; int expected_lock_count = 0; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); for (i = 0; i < 100; i++) { if (advice) free(advice); advice = malloc(sizeof(struct llapi_lu_ladvise)*count); setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, i * write_size, (i+1)*write_size - 1, true); advice[0].lla_lockahead_result = 98674; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' at offset %llu: %s", mainpath, advice[0].lla_end, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result >= 0, "unexpected extent result for extent %d: %d", i, advice[0].lla_lockahead_result); expected_lock_count++; } /* Ask again until we get the lock. */ for (i = 1; i < 100; i++) { usleep(100000); /* 0.1 second */ advice[0].lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); if (advice[0].lla_lockahead_result > 0) break; } ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result: %d", advice[0].lla_lockahead_result); free(advice); memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); close(fd); return expected_lock_count; } /* Grow a lock backward */ static int test14(void) { struct llapi_lu_ladvise *advice = NULL; const int count = 1; int fd; size_t write_size = 1024 * 1024; int rc; char buf[write_size]; int i; const int num_blocks = 100; int expected_lock_count = 0; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); for (i = 0; i < num_blocks; i++) { size_t start = (num_blocks - i - 1) * write_size; size_t end = (num_blocks - i) * write_size - 1; if (advice) free(advice); advice = malloc(sizeof(struct llapi_lu_ladvise)*count); setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); advice[0].lla_lockahead_result = 98674; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' at offset %llu: %s", mainpath, advice[0].lla_end, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result >= 0, "unexpected extent result for extent %d: %d", i, advice[0].lla_lockahead_result); expected_lock_count++; } /* Ask again until we get the lock. */ for (i = 1; i < 100; i++) { usleep(100000); /* 0.1 second */ advice[0].lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); if (advice[0].lla_lockahead_result > 0) break; } ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result: %d", advice[0].lla_lockahead_result); free(advice); memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); close(fd); return expected_lock_count; } /* Request many locks at 10MiB intervals */ static int test15(void) { struct llapi_lu_ladvise *advice; const int count = 1; int fd; size_t write_size = 1024 * 1024; int rc; char buf[write_size]; int i; int expected_lock_count = 0; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); advice = malloc(sizeof(struct llapi_lu_ladvise)*count); for (i = 0; i < 500; i++) { /* The 'UL' designators are required to avoid undefined * behavior which GCC turns in to an infinite loop */ __u64 start = i * 1024UL * 1024UL * 10UL; __u64 end = start + 1; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result >= 0, "unexpected extent result for extent %d: %d", i, advice[0].lla_lockahead_result); expected_lock_count++; } /* Ask again until we get the lock. */ for (i = 1; i < 100; i++) { usleep(100000); /* 0.1 second */ advice[0].lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); if (advice[0].lla_lockahead_result > 0) break; } ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result: %d", advice[0].lla_lockahead_result); memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); /* The write should cancel the first lock (which was too small) * and create one of its own, so the net effect on lock count is 0. */ free(advice); close(fd); /* We have to map our expected return in to the range of valid return * codes, 0-255. */ expected_lock_count = expected_lock_count/100; return expected_lock_count; } /* Use lockahead to verify behavior of ladvise locknoexpand */ static int test16(void) { struct llapi_lu_ladvise *advice; struct llapi_lu_ladvise *advice_noexpand; const int count = 1; int fd; size_t write_size = 1024 * 1024; __u64 start = 0; __u64 end = write_size - 1; int rc; char buf[write_size]; int expected_lock_count = 0; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); advice = malloc(sizeof(struct llapi_lu_ladvise)*count); advice_noexpand = malloc(sizeof(struct llapi_lu_ladvise)); /* First ask for a read lock, which will conflict with the write */ setup_ladvise_lockahead(advice, MODE_READ_USER, 0, start, end, false); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result == 0, "unexpected extent result for extent: %d", advice[0].lla_lockahead_result); /* Use an async request to verify we got the read lock we asked for */ setup_ladvise_lockahead(advice, MODE_READ_USER, 0, start, end, true); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result for extent: %d", advice[0].lla_lockahead_result); /* Set noexpand */ advice_noexpand[0].lla_advice = LU_LADVISE_LOCKNOEXPAND; advice_noexpand[0].lla_peradvice_flags = 0; rc = llapi_ladvise(fd, 0, 1, advice_noexpand); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); /* This write should generate a lock on exactly "write_size" bytes */ memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); /* Write should create one LDLM lock */ expected_lock_count++; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result for extent: %d", advice[0].lla_lockahead_result); /* Now, disable locknoexpand and try writing again. */ advice_noexpand[0].lla_peradvice_flags = LF_UNSET; rc = llapi_ladvise(fd, 0, 1, advice_noexpand); /* This write should get an expanded lock */ memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); /* Write should create one LDLM lock */ expected_lock_count++; /* Verify it didn't get a lock on just the bytes it wrote.*/ usleep(100000); /* 0.1 second, plenty of time to get the lock */ start = start + write_size; end = end + write_size; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_DIFFERENT, "unexpected extent result for extent %d", advice[0].lla_lockahead_result); free(advice); close(fd); return expected_lock_count; } /* Use lockahead to verify behavior of ladvise locknoexpand, with O_NONBLOCK. * There should be no change in behavior. */ static int test17(void) { struct llapi_lu_ladvise *advice; struct llapi_lu_ladvise *advice_noexpand; const int count = 1; int fd; size_t write_size = 1024 * 1024; __u64 start = 0; __u64 end = write_size - 1; int rc; char buf[write_size]; int expected_lock_count = 0; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC | O_NONBLOCK, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); advice = malloc(sizeof(struct llapi_lu_ladvise)*count); advice_noexpand = malloc(sizeof(struct llapi_lu_ladvise)); /* First ask for a read lock, which will conflict with the write */ setup_ladvise_lockahead(advice, MODE_READ_USER, 0, start, end, false); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result == 0, "unexpected extent result for extent: %d", advice[0].lla_lockahead_result); /* Use an async request to verify we got the read lock we asked for */ setup_ladvise_lockahead(advice, MODE_READ_USER, 0, start, end, true); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result for extent: %d", advice[0].lla_lockahead_result); /* Set noexpand */ advice_noexpand[0].lla_advice = LU_LADVISE_LOCKNOEXPAND; advice_noexpand[0].lla_peradvice_flags = 0; rc = llapi_ladvise(fd, 0, 1, advice_noexpand); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); /* This write should generate a lock on exactly "write_size" bytes */ memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); /* Write should create one LDLM lock */ expected_lock_count++; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result for extent: %d", advice[0].lla_lockahead_result); /* Now, disable locknoexpand and try writing again. */ advice_noexpand[0].lla_peradvice_flags = LF_UNSET; rc = llapi_ladvise(fd, 0, 1, advice_noexpand); /* This write should get an expanded lock */ memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); /* Write should create one LDLM lock */ expected_lock_count++; /* Verify it didn't get a lock on just the bytes it wrote.*/ usleep(100000); /* 0.1 second, plenty of time to get the lock */ start = start + write_size; end = end + write_size; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_DIFFERENT, "unexpected extent result for extent %d", advice[0].lla_lockahead_result); free(advice); close(fd); return expected_lock_count; } /* Test overlapping requests */ static int test18(void) { struct llapi_lu_ladvise *advice; const int count = 1; int fd; int rc; int i; int expected_lock_count = 0; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); advice = malloc(sizeof(struct llapi_lu_ladvise)*count); /* Overlapping locks - Should only end up with 1 */ for (i = 0; i < 10; i++) { __u64 start = i; __u64 end = start + 4096; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result >= 0, "unexpected extent result for extent %d: %d", i, advice[0].lla_lockahead_result); } expected_lock_count = 1; /* Ask again until we get the lock. */ for (i = 1; i < 100; i++) { usleep(100000); /* 0.1 second */ advice[0].lla_lockahead_result = 456789; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, 0, 4096, true); rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); if (advice[0].lla_lockahead_result > 0) break; } ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result: %d", advice[0].lla_lockahead_result); free(advice); close(fd); return expected_lock_count; } /* Test that normal request blocks lock ahead requests */ static int test19(void) { struct llapi_lu_ladvise *advice; const int count = 1; int fd; size_t write_size = 1024 * 1024; int rc; char buf[write_size]; int i; int expected_lock_count = 0; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); advice = malloc(sizeof(struct llapi_lu_ladvise)*count); /* This should create a lock on the whole file, which will block lock * ahead requests. */ memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); expected_lock_count = 1; /* These should all be blocked. */ for (i = 0; i < 10; i++) { __u64 start = i * 4096; __u64 end = start + 4096; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); advice[0].lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); ASSERTF(advice[0].lla_lockahead_result == LLA_RESULT_DIFFERENT, "unexpected extent result for extent %d: %d", i, advice[0].lla_lockahead_result); } free(advice); close(fd); return expected_lock_count; } /* Test sync requests, and matching with async requests */ static int test20(void) { struct llapi_lu_ladvise advice; const int count = 1; int fd; size_t write_size = 1024 * 1024; int rc; char buf[write_size]; int i; int expected_lock_count = 1; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); /* Async request */ setup_ladvise_lockahead(&advice, MODE_WRITE_USER, 0, 0, write_size - 1, true); /* Manually set the result so we can verify it's being modified */ advice.lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); ASSERTF(advice.lla_lockahead_result == 0, "unexpected extent result: %d", advice.lla_lockahead_result); /* Ask again until we get the lock (status 1). */ for (i = 1; i < 100; i++) { usleep(100000); /* 0.1 second */ advice.lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); if (advice.lla_lockahead_result > 0) break; } ASSERTF(advice.lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result: %d", advice.lla_lockahead_result); /* Convert to a sync request on smaller range, should match and not * cancel */ setup_ladvise_lockahead(&advice, MODE_WRITE_USER, 0, 0, write_size - 1 - write_size/2, false); advice.lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); /* Sync requests cannot give detailed results */ ASSERTF(advice.lla_lockahead_result == 0, "unexpected extent result: %d", advice.lla_lockahead_result); /* Use an async request to test original lock is still present */ setup_ladvise_lockahead(&advice, MODE_WRITE_USER, 0, 0, write_size - 1, true); advice.lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); ASSERTF(advice.lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result: %d", advice.lla_lockahead_result); memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); close(fd); return expected_lock_count; } /* Test sync requests, and conflict with async requests */ static int test21(void) { struct llapi_lu_ladvise advice; const int count = 1; int fd; size_t write_size = 1024 * 1024; int rc; char buf[write_size]; int i; int expected_lock_count = 1; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); /* Async request */ setup_ladvise_lockahead(&advice, MODE_WRITE_USER, 0, 0, write_size - 1, true); /* Manually set the result so we can verify it's being modified */ advice.lla_lockahead_result = 345678; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); ASSERTF(advice.lla_lockahead_result == 0, "unexpected extent result: %d", advice.lla_lockahead_result); /* Ask again until we get the lock (status 1). */ for (i = 1; i < 100; i++) { usleep(100000); /* 0.1 second */ advice.lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); if (advice.lla_lockahead_result > 0) break; } ASSERTF(advice.lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result: %d", advice.lla_lockahead_result); /* Convert to a sync request on larger range, should cancel existing * lock */ setup_ladvise_lockahead(&advice, MODE_WRITE_USER, 0, 0, write_size*2 - 1, false); advice.lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); /* Sync requests cannot give detailed results */ ASSERTF(advice.lla_lockahead_result == 0, "unexpected extent result: %d", advice.lla_lockahead_result); /* Use an async request to test new lock is there */ setup_ladvise_lockahead(&advice, MODE_WRITE_USER, 0, 0, write_size*2 - 1, true); advice.lla_lockahead_result = 456789; rc = llapi_ladvise(fd, 0, count, &advice); ASSERTF(rc == 0, "cannot lockahead '%s': %s", mainpath, strerror(errno)); ASSERTF(advice.lla_lockahead_result == LLA_RESULT_SAME, "unexpected extent result: %d", advice.lla_lockahead_result); memset(buf, 0xaa, write_size); rc = write(fd, buf, write_size); ASSERTF(rc == sizeof(buf), "write failed for '%s': %s", mainpath, strerror(errno)); close(fd); return expected_lock_count; } /* Test various valid and invalid inputs */ static int test22(void) { struct llapi_lu_ladvise *advice; const int count = 1; int fd; int rc; size_t start = 0; size_t end = 0; fd = open(mainpath, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno)); /* A valid async request first */ advice = malloc(sizeof(struct llapi_lu_ladvise)*count); start = 0; end = 1024*1024; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); free(advice); /* Valid request sync request */ advice = malloc(sizeof(struct llapi_lu_ladvise)*count); start = 0; end = 1024*1024; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, false); rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == 0, "cannot lockahead '%s' : %s", mainpath, strerror(errno)); free(advice); /* No actual block */ advice = malloc(sizeof(struct llapi_lu_ladvise)*count); start = 0; end = 0; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == -1 && errno == EINVAL, "unexpected return for no block lock: %d %s", rc, strerror(errno)); free(advice); /* end before start */ advice = malloc(sizeof(struct llapi_lu_ladvise)*count); start = 1024 * 1024; end = 0; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0, start, end, true); rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == -1 && errno == EINVAL, "unexpected return for reversed block: %d %s", rc, strerror(errno)); free(advice); /* bogus lock mode - 0x65464 */ advice = malloc(sizeof(struct llapi_lu_ladvise)*count); start = 0; end = 1024 * 1024; setup_ladvise_lockahead(advice, 0x65464, 0, start, end, true); rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == -1 && errno == EINVAL, "unexpected return for bogus lock mode: %d %s", rc, strerror(errno)); free(advice); /* bogus flags, 0x80 */ advice = malloc(sizeof(struct llapi_lu_ladvise)*count); start = 0; end = 1024 * 1024; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0x80, start, end, true); rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == -1 && errno == EINVAL, "unexpected return for bogus flags: %u %d %s", 0x80, rc, strerror(errno)); free(advice); /* bogus flags, 0xff - CEF_MASK */ advice = malloc(sizeof(struct llapi_lu_ladvise)*count); end = 1024 * 1024; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0xff, start, end, true); rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == -1 && errno == EINVAL, "unexpected return for bogus flags: %u %d %s", 0xff, rc, strerror(errno)); free(advice); /* bogus flags, 0xffffffff */ advice = malloc(sizeof(struct llapi_lu_ladvise)*count); end = 1024 * 1024; setup_ladvise_lockahead(advice, MODE_WRITE_USER, 0xffffffff, start, end, true); rc = llapi_ladvise(fd, 0, count, advice); ASSERTF(rc == -1 && errno == EINVAL, "unexpected return for bogus flags: %u %d %s", 0xffffffff, rc, strerror(errno)); free(advice); close(fd); return 0; } static void usage(char *prog) { fprintf(stderr, "Usage: %s [-d lustre_dir], [-t single_test]\n", prog); exit(-1); } static void process_args(int argc, char *argv[]) { int c; while ((c = getopt(argc, argv, "d:f:t:")) != -1) { switch (c) { case 'f': mainfile = optarg; break; case 'd': lustre_dir = optarg; break; case 't': single_test = atoi(optarg); break; case '?': default: fprintf(stderr, "Invalid option '%c'\n", optopt); usage(argv[0]); break; } } } int main(int argc, char *argv[]) { char fsname[8]; int rc; process_args(argc, argv); if (lustre_dir == NULL) lustre_dir = "/mnt/lustre"; if (mainfile == NULL) mainfile = "lockahead_test_654"; rc = llapi_search_mounts(lustre_dir, 0, fsmountdir, fsname); if (rc != 0) { fprintf(stderr, "Error: '%s': not a Lustre filesystem\n", lustre_dir); return -1; } /* Play nice with Lustre test scripts. Non-line buffered output * stream under I/O redirection may appear incorrectly. */ setvbuf(stdout, NULL, _IOLBF, 0); /* Create a test filename and reuse it. Remove possibly old files. */ rc = snprintf(mainpath, sizeof(mainpath), "%s/%s", lustre_dir, mainfile); ASSERTF(rc > 0 && rc < sizeof(mainpath), "invalid name for mainpath"); cleanup(); switch (single_test) { case 0: PERFORM(test10); PERFORM(test11); PERFORM(test12); PERFORM(test13); PERFORM(test14); PERFORM(test15); PERFORM(test16); PERFORM(test17); PERFORM(test18); PERFORM(test19); PERFORM(test20); PERFORM(test21); PERFORM(test22); /* When running all the test cases, we can't use the return * from the last test case, as it might be non-zero to return * info, rather than for an error. Test cases assert and exit * if an error occurs. */ rc = 0; break; case 10: PERFORM(test10); break; case 11: PERFORM(test11); break; case 12: PERFORM(test12); break; case 13: PERFORM(test13); break; case 14: PERFORM(test14); break; case 15: PERFORM(test15); break; case 16: PERFORM(test16); break; case 17: PERFORM(test17); break; case 18: PERFORM(test18); break; case 19: PERFORM(test19); break; case 20: PERFORM(test20); break; case 21: PERFORM(test21); break; case 22: PERFORM(test22); break; default: fprintf(stderr, "impossible value of single_test %d\n", single_test); rc = -1; break; } return rc; }