systemd-journal-fstat.c 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "systemd-internals.h"
  3. // ----------------------------------------------------------------------------
  4. // fstat64 overloading to speed up libsystemd
  5. // https://github.com/systemd/systemd/pull/29261
  6. #include <dlfcn.h>
  7. #include <sys/stat.h>
  8. #define FSTAT_CACHE_MAX 1024
  9. struct fdstat64_cache_entry {
  10. bool enabled;
  11. bool updated;
  12. int err_no;
  13. struct stat64 stat;
  14. int ret;
  15. size_t cached_count;
  16. size_t session;
  17. };
  18. struct fdstat64_cache_entry fstat64_cache[FSTAT_CACHE_MAX] = {0 };
  19. __thread size_t fstat_thread_calls = 0;
  20. __thread size_t fstat_thread_cached_responses = 0;
  21. static __thread bool enable_thread_fstat = false;
  22. static __thread size_t fstat_caching_thread_session = 0;
  23. static size_t fstat_caching_global_session = 0;
  24. void fstat_cache_enable_on_thread(void) {
  25. fstat_caching_thread_session = __atomic_add_fetch(&fstat_caching_global_session, 1, __ATOMIC_ACQUIRE);
  26. enable_thread_fstat = true;
  27. }
  28. void fstat_cache_disable_on_thread(void) {
  29. fstat_caching_thread_session = __atomic_add_fetch(&fstat_caching_global_session, 1, __ATOMIC_RELEASE);
  30. enable_thread_fstat = false;
  31. }
  32. int fstat64(int fd, struct stat64 *buf) {
  33. static int (*real_fstat)(int, struct stat64 *) = NULL;
  34. if (!real_fstat)
  35. real_fstat = dlsym(RTLD_NEXT, "fstat64");
  36. fstat_thread_calls++;
  37. if(fd >= 0 && fd < FSTAT_CACHE_MAX) {
  38. if(enable_thread_fstat && fstat64_cache[fd].session != fstat_caching_thread_session) {
  39. fstat64_cache[fd].session = fstat_caching_thread_session;
  40. fstat64_cache[fd].enabled = true;
  41. fstat64_cache[fd].updated = false;
  42. }
  43. if(fstat64_cache[fd].enabled && fstat64_cache[fd].updated && fstat64_cache[fd].session == fstat_caching_thread_session) {
  44. fstat_thread_cached_responses++;
  45. errno = fstat64_cache[fd].err_no;
  46. *buf = fstat64_cache[fd].stat;
  47. fstat64_cache[fd].cached_count++;
  48. return fstat64_cache[fd].ret;
  49. }
  50. }
  51. int ret = real_fstat(fd, buf);
  52. if(fd >= 0 && fd < FSTAT_CACHE_MAX && fstat64_cache[fd].enabled && fstat64_cache[fd].session == fstat_caching_thread_session) {
  53. fstat64_cache[fd].ret = ret;
  54. fstat64_cache[fd].updated = true;
  55. fstat64_cache[fd].err_no = errno;
  56. fstat64_cache[fd].stat = *buf;
  57. }
  58. return ret;
  59. }