[3/8] elf: Avoid redundant ld.so.cache reload after first load
Checks
| Context |
Check |
Description |
| redhat-pt-bot/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
Commit Message
_dl_check_ldsocache_needs_loading only stored the stat fields it
compares (mtime, ino, size, dev) on the path where a cache was already
loaded. On the very first call CACHE is NULL and the function returned
"needs loading" without recording those fields, leaving
new_cache_file_time zero. The next call then copied that zero value
into cache_file_time and compared it against the freshly stat'd values,
which always differed, forcing a second, unnecessary load (munmap +
mmap + re-parse) of an unchanged cache at every startup.
It can be shown with repro:
$ cat << EOF > repro.c
#include <dlfcn.h>
int main (void) { dlopen ("does-not-exist-xyz.so.99", RTLD_NOW); return 0; }
EOF
$ gcc repro.c -o repro
$ strace -f -e trace=openat elf/ld.so --library-path . ./repro 2>&1 | grep -c "/etc/ld.so.cache"
The result should be 1, instead of 2.
Record the stat fields as soon as the stat succeeds, before the
CACHE == NULL early return, so the following call has an accurate
baseline and does not spuriously reload.
---
elf/dl-cache.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
Comments
Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
> - /* Any file is better than no file (likely the first time
> - through). */
> - if (cache == NULL)
> - return true;
> -
> - /* Store the fields we check, in order they're likely to differ. */
> + /* Store the fields we check, in order they're likely to differ. We
> + must do this even for the first load (CACHE == NULL below), so that
> + the next call copies an accurate NEW_CACHE_FILE_TIME into
> + CACHE_FILE_TIME and does not spuriously reload the unchanged cache. */
> new_cache_file_time.mtime = new_cache_file_stat.st_mtime;
> new_cache_file_time.ino = new_cache_file_stat.st_ino;
> new_cache_file_time.size = new_cache_file_stat.st_size;
> new_cache_file_time.dev = new_cache_file_stat.st_dev;
>
> + /* Any file is better than no file (likely the first time
> + through). */
> + if (cache == NULL)
> + return true;
> +
> /* At this point, NEW_CACHE_FILE_TIME is valid as well as
> CACHE_FILE_TIME, so we compare them. */
> return (memcmp (&new_cache_file_time, &cache_file_time,
LGTM
Reviewed-by: DJ Delorie <dj@redhat.com>
@@ -433,17 +433,20 @@ _dl_check_ldsocache_needs_loading (void)
if (rv < 0)
return false;
- /* Any file is better than no file (likely the first time
- through). */
- if (cache == NULL)
- return true;
-
- /* Store the fields we check, in order they're likely to differ. */
+ /* Store the fields we check, in order they're likely to differ. We
+ must do this even for the first load (CACHE == NULL below), so that
+ the next call copies an accurate NEW_CACHE_FILE_TIME into
+ CACHE_FILE_TIME and does not spuriously reload the unchanged cache. */
new_cache_file_time.mtime = new_cache_file_stat.st_mtime;
new_cache_file_time.ino = new_cache_file_stat.st_ino;
new_cache_file_time.size = new_cache_file_stat.st_size;
new_cache_file_time.dev = new_cache_file_stat.st_dev;
+ /* Any file is better than no file (likely the first time
+ through). */
+ if (cache == NULL)
+ return true;
+
/* At this point, NEW_CACHE_FILE_TIME is valid as well as
CACHE_FILE_TIME, so we compare them. */
return (memcmp (&new_cache_file_time, &cache_file_time,