file_stressor.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define _GNU_SOURCE
  3. #define __SANE_USERSPACE_TYPES__
  4. #include <fcntl.h>
  5. #include <limits.h>
  6. #include <pthread.h>
  7. #include <sched.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <sys/stat.h>
  11. #include <sys/mount.h>
  12. #include <unistd.h>
  13. #include "kselftest_harness.h"
  14. #include <linux/types.h>
  15. #include <linux/mount.h>
  16. #include <sys/syscall.h>
  17. static inline int sys_fsopen(const char *fsname, unsigned int flags)
  18. {
  19. return syscall(__NR_fsopen, fsname, flags);
  20. }
  21. static inline int sys_fsconfig(int fd, unsigned int cmd, const char *key,
  22. const char *value, int aux)
  23. {
  24. return syscall(__NR_fsconfig, fd, cmd, key, value, aux);
  25. }
  26. static inline int sys_fsmount(int fd, unsigned int flags,
  27. unsigned int attr_flags)
  28. {
  29. return syscall(__NR_fsmount, fd, flags, attr_flags);
  30. }
  31. #ifndef MOVE_MOUNT_F_EMPTY_PATH
  32. #define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */
  33. #endif
  34. static inline int sys_move_mount(int from_dfd, const char *from_pathname,
  35. int to_dfd, const char *to_pathname,
  36. unsigned int flags)
  37. {
  38. return syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd,
  39. to_pathname, flags);
  40. }
  41. FIXTURE(file_stressor) {
  42. int fd_tmpfs;
  43. int nr_procs;
  44. int max_fds;
  45. pid_t *pids_openers;
  46. pid_t *pids_getdents;
  47. int *fd_proc_pid;
  48. };
  49. FIXTURE_SETUP(file_stressor)
  50. {
  51. int fd_context;
  52. ASSERT_EQ(unshare(CLONE_NEWNS), 0);
  53. ASSERT_EQ(mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0);
  54. ASSERT_EQ(mkdir("/slab_typesafe_by_rcu", 0755), 0);
  55. fd_context = sys_fsopen("tmpfs", 0);
  56. ASSERT_GE(fd_context, 0);
  57. ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
  58. self->fd_tmpfs = sys_fsmount(fd_context, 0, 0);
  59. ASSERT_GE(self->fd_tmpfs, 0);
  60. ASSERT_EQ(close(fd_context), 0);
  61. ASSERT_EQ(sys_move_mount(self->fd_tmpfs, "", -EBADF, "/slab_typesafe_by_rcu", MOVE_MOUNT_F_EMPTY_PATH), 0);
  62. self->nr_procs = sysconf(_SC_NPROCESSORS_ONLN);
  63. self->pids_openers = malloc(sizeof(pid_t) * self->nr_procs);
  64. ASSERT_NE(self->pids_openers, NULL);
  65. self->pids_getdents = malloc(sizeof(pid_t) * self->nr_procs);
  66. ASSERT_NE(self->pids_getdents, NULL);
  67. self->fd_proc_pid = malloc(sizeof(int) * self->nr_procs);
  68. ASSERT_NE(self->fd_proc_pid, NULL);
  69. self->max_fds = 500;
  70. }
  71. FIXTURE_TEARDOWN(file_stressor)
  72. {
  73. for (int i = 0; i < self->nr_procs; i++) {
  74. int wstatus;
  75. pid_t pid;
  76. pid = waitpid(self->pids_openers[i], &wstatus, 0);
  77. ASSERT_EQ(pid, self->pids_openers[i]);
  78. ASSERT_TRUE(!WIFEXITED(wstatus) || !WIFSIGNALED(wstatus));
  79. pid = waitpid(self->pids_getdents[i], &wstatus, 0);
  80. ASSERT_EQ(pid, self->pids_getdents[i]);
  81. ASSERT_TRUE(!WIFEXITED(wstatus) || !WIFSIGNALED(wstatus));
  82. }
  83. free(self->pids_openers);
  84. free(self->pids_getdents);
  85. ASSERT_EQ(close(self->fd_tmpfs), 0);
  86. umount2("/slab_typesafe_by_rcu", 0);
  87. ASSERT_EQ(rmdir("/slab_typesafe_by_rcu"), 0);
  88. }
  89. TEST_F_TIMEOUT(file_stressor, slab_typesafe_by_rcu, 900 * 2)
  90. {
  91. for (int i = 0; i < self->nr_procs; i++) {
  92. pid_t pid_self;
  93. self->pids_openers[i] = fork();
  94. ASSERT_GE(self->pids_openers[i], 0);
  95. if (self->pids_openers[i] != 0)
  96. continue;
  97. self->pids_openers[i] = getpid();
  98. for (;;) {
  99. for (int i = 0; i < self->max_fds; i++) {
  100. char path[PATH_MAX];
  101. int fd;
  102. sprintf(path, "/slab_typesafe_by_rcu/file-%d-%d", self->pids_openers[i], i);
  103. fd = open(path, O_CREAT | O_RDONLY | O_CLOEXEC, 0644);
  104. if (fd < 0)
  105. continue;
  106. }
  107. close_range(3, ~0U, 0);
  108. }
  109. exit(0);
  110. }
  111. for (int i = 0; i < self->nr_procs; i++) {
  112. char path[PATH_MAX];
  113. sprintf(path, "/proc/%d/fd/", self->pids_openers[i]);
  114. self->fd_proc_pid[i] = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
  115. ASSERT_GE(self->fd_proc_pid[i], 0);
  116. }
  117. for (int i = 0; i < self->nr_procs; i++) {
  118. self->pids_getdents[i] = fork();
  119. ASSERT_GE(self->pids_getdents[i], 0);
  120. if (self->pids_getdents[i] != 0)
  121. continue;
  122. self->pids_getdents[i] = getpid();
  123. for (;;) {
  124. char ents[1024];
  125. ssize_t nr_read;
  126. /*
  127. * Concurrently read /proc/<pid>/fd/ which roughly does:
  128. *
  129. * f = fget_task_next(p, &fd);
  130. * if (!f)
  131. * break;
  132. * data.mode = f->f_mode;
  133. * fput(f);
  134. *
  135. * Which means that it'll try to get a reference to a
  136. * file in another task's file descriptor table.
  137. *
  138. * Under heavy file load it is increasingly likely that
  139. * the other task will manage to close @file and @file
  140. * is being recycled due to SLAB_TYPEAFE_BY_RCU
  141. * concurrently. This will trigger various warnings in
  142. * the file reference counting code.
  143. */
  144. do {
  145. nr_read = syscall(SYS_getdents64, self->fd_proc_pid[i], ents, sizeof(ents));
  146. } while (nr_read >= 0);
  147. lseek(self->fd_proc_pid[i], 0, SEEK_SET);
  148. }
  149. exit(0);
  150. }
  151. ASSERT_EQ(clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec){ .tv_sec = 900 /* 15 min */ }, NULL), 0);
  152. for (int i = 0; i < self->nr_procs; i++) {
  153. kill(self->pids_openers[i], SIGKILL);
  154. kill(self->pids_getdents[i], SIGKILL);
  155. }
  156. }
  157. TEST_HARNESS_MAIN