master
c 93 lines 2.72 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "systemd-internals.h"
4
5 #if !defined(HAVE_RUST_PROVIDER)
6
7 // ----------------------------------------------------------------------------
8 // fstat64 overloading to speed up libsystemd
9 // https://github.com/systemd/systemd/pull/29261
10
11 #include <dlfcn.h>
12 #include <sys/stat.h>
13
14 #define FSTAT_CACHE_MAX 1024
15 struct fdstat64_cache_entry {
16 bool enabled;
17 bool updated;
18 int err_no;
19 struct stat64 stat;
20 int ret;
21 size_t cached_count;
22 size_t session;
23 };
24
25 struct fdstat64_cache_entry fstat64_cache[FSTAT_CACHE_MAX] = {0};
26 __thread size_t fstat_thread_calls = 0;
27 __thread size_t fstat_thread_cached_responses = 0;
28 static __thread bool enable_thread_fstat = false;
29 static __thread size_t fstat_caching_thread_session = 0;
30 static size_t fstat_caching_global_session = 0;
31
32 void fstat_cache_enable_on_thread(void)
33 {
34 fstat_caching_thread_session = __atomic_add_fetch(&fstat_caching_global_session, 1, __ATOMIC_ACQUIRE);
35 enable_thread_fstat = true;
36 }
37
38 void fstat_cache_disable_on_thread(void)
39 {
40 fstat_caching_thread_session = __atomic_add_fetch(&fstat_caching_global_session, 1, __ATOMIC_RELEASE);
41 enable_thread_fstat = false;
42 }
43
44 int fstat64(int fd, struct stat64 *buf)
45 {
46 static int (*real_fstat)(int, struct stat64 *) = NULL;
47 if (!real_fstat)
48 real_fstat = dlsym(RTLD_NEXT, "fstat64");
49
50 fstat_thread_calls++;
51
52 if (fd >= 0 && fd < FSTAT_CACHE_MAX) {
53 if (enable_thread_fstat && fstat64_cache[fd].session != fstat_caching_thread_session) {
54 fstat64_cache[fd].session = fstat_caching_thread_session;
55 fstat64_cache[fd].enabled = true;
56 fstat64_cache[fd].updated = false;
57 }
58
59 if (fstat64_cache[fd].enabled && fstat64_cache[fd].updated &&
60 fstat64_cache[fd].session == fstat_caching_thread_session) {
61 fstat_thread_cached_responses++;
62 errno = fstat64_cache[fd].err_no;
63 *buf = fstat64_cache[fd].stat;
64 fstat64_cache[fd].cached_count++;
65 return fstat64_cache[fd].ret;
66 }
67 }
68
69 int ret = real_fstat(fd, buf);
70
71 if (fd >= 0 && fd < FSTAT_CACHE_MAX && fstat64_cache[fd].enabled &&
72 fstat64_cache[fd].session == fstat_caching_thread_session) {
73 fstat64_cache[fd].ret = ret;
74 fstat64_cache[fd].updated = true;
75 fstat64_cache[fd].err_no = errno;
76 fstat64_cache[fd].stat = *buf;
77 }
78
79 return ret;
80 }
81
82 #else // HAVE_RUST_PROVIDER
83
84 // When using Rust provider, disable fstat caching entirely since
85 // we will not rely on libsystemd.
86
87 __thread size_t fstat_thread_calls = 0;
88 __thread size_t fstat_thread_cached_responses = 0;
89
90 void fstat_cache_enable_on_thread(void) { }
91 void fstat_cache_disable_on_thread(void) { }
92
93 #endif