>From 2b8180d6ef2be57c0c303ef422fbca40833142f3 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Thu, 12 Mar 2015 15:28:55 +0300 Subject: [PATCH] selftest: add a test case to check how locks are shown in fdinfo (v2) The main idea of this test is to check that locks are shown correctly when they can't be placed in a default seq_file buffer due to its size. V2: use the kselftest framework Cc: Andrew Morton Cc: Shuah Khan Signed-off-by: Andrey Vagin --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/fdinfo/Makefile | 11 +++ tools/testing/selftests/fdinfo/locks.c | 119 ++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 tools/testing/selftests/fdinfo/Makefile create mode 100644 tools/testing/selftests/fdinfo/locks.c diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 4e51122..061a507 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -2,6 +2,7 @@ TARGETS = breakpoints TARGETS += cpu-hotplug TARGETS += efivarfs TARGETS += exec +TARGETS += fdinfo TARGETS += firmware TARGETS += ftrace TARGETS += kcmp diff --git a/tools/testing/selftests/fdinfo/Makefile b/tools/testing/selftests/fdinfo/Makefile new file mode 100644 index 0000000..83f34ef --- /dev/null +++ b/tools/testing/selftests/fdinfo/Makefile @@ -0,0 +1,11 @@ +CFLAGS += -Wall + +all: locks + +run_tests: all + @./locks || echo "locks: [FAIL]" + +locks: locks.c + +clean: + rm -f locks diff --git a/tools/testing/selftests/fdinfo/locks.c b/tools/testing/selftests/fdinfo/locks.c new file mode 100644 index 0000000..71fc237 --- /dev/null +++ b/tools/testing/selftests/fdinfo/locks.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest.h" + +#define pr_perror(fmt, ...) fprintf(stderr, "%s:%d: " fmt ": %m\n", \ + __FILE__, __LINE__, ##__VA_ARGS__) + +#define FILE_SIZE 4096 + +int main(int argc, char **argv) +{ + int fd, fdinfo, i, ret, size, bsize = 4096; + char *buf, *p, fdinfo_path[] = "/proc/self/fdinfo/XXXXXXXXXX"; + + fd = open("test_file", O_RDWR | O_CREAT, 0666); + if (fd == -1) { + pr_perror("Unable to open test_file"); + return ksft_exit_fail(); + } + unlink("test_file"); + if (ftruncate(fd, FILE_SIZE) == -1) { + pr_perror("Unable to truncate test_file"); + return ksft_exit_fail(); + } + + /* + * Generate FILE_SIZE locks. We are going to exceed the default + * size of seq buffer + */ + for (i = 0; i < FILE_SIZE; i++) { + struct flock lock; + + if (i % 2) + lock.l_type = F_WRLCK; + else + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + lock.l_start = i; + lock.l_len = 1; + lock.l_pid = -1; + if (fcntl(fd, F_SETLK, &lock)) { + pr_perror("Unable to set lock %d\n", i); + return ksft_exit_fail(); + } + } + + snprintf(fdinfo_path, sizeof(fdinfo_path), "/proc/self/fdinfo/%d", fd); + fdinfo = open(fdinfo_path, O_RDONLY); + if (fdinfo < 0) { + pr_perror("Unable to open %s", fdinfo_path); + return ksft_exit_fail(); + } + + buf = malloc(bsize); + if (buf == NULL) { + pr_perror("Unable to allocate a buffer"); + return ksft_exit_fail(); + } + size = 0; + while (1) { + ret = read(fdinfo, buf + size, bsize - 1 - size); + if (ret == 0) + break; + if (ret == -1) { + pr_perror("Unable to read %s", fdinfo_path); + return ksft_exit_fail(); + } + size += ret; + if (bsize - size < 4096) + bsize += 4096; + buf = realloc(buf, bsize); + if (buf == NULL) { + pr_perror("Unable to allocate a buffer"); + return ksft_exit_fail(); + } + } + buf[size] = 0; + + i = 0; + for (p = buf - 1; p != NULL; p = strchr(p, '\n')) { + char fl_flag[10], fl_type[15], fl_option[10], end[32]; + int fl_id, fl_owner, maj, min; + unsigned long ino; + unsigned long long start; + + p++; + + if (strncmp(p, "lock:", 5)) + continue; + ret = sscanf(p, "lock:\t%d:%s %s %s %d %x:%x:%ld %lld %s", + &fl_id, fl_flag, fl_type, fl_option, + &fl_owner, &maj, &min, &ino, + &start, end); + if (ret != 10) { + pr_perror("Unable to parse"); + fprintf(stderr, "%s\n", buf); + return ksft_exit_fail(); + } + i++; + } + + close(fdinfo); + close(fd); + + if (i != FILE_SIZE) { + fprintf(stderr, "%s\n", buf); + return ksft_exit_fail(); + } + + free(buf); + + return ksft_exit_pass(); +} -- 2.1.0