diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 2309196d8df3..b86969dc6e81 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -582,9 +582,18 @@ static char *dso__get_filename(struct dso *dso, const char *root_dir, goto out; if (!is_regular_file(name)) { + struct stat st; char *new_name; - if (errno != ENOENT || dso__nsinfo(dso) == NULL) + /* + * errno only reflects the failure reason when stat() itself + * failed: a successful stat() on a non-regular file (e.g. a + * directory) leaves a stale errno, which a previous failed + * iteration of the try_to_open_dso() fallback loop may have + * set to ENOENT. + */ + if (stat(name, &st) == 0 || errno != ENOENT || + dso__nsinfo(dso) == NULL) goto out; new_name = dso__filename_with_chroot(dso, name); @@ -640,10 +649,13 @@ static int __open_dso(struct dso *dso, struct machine *machine) mutex_lock(dso__lock(dso)); name = dso__get_filename(dso, machine ? machine->root_dir : "", &decomp); - if (name) + if (name) { fd = do_open(name); - else + } else { + if (errno == 0) + errno = ENOENT; fd = -errno; + } if (decomp) unlink(name);