]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fd-util: optimize fd_get_path() a bit 10523/head
authorLennart Poettering <lennart@poettering.net>
Thu, 25 Oct 2018 19:27:00 +0000 (21:27 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 25 Oct 2018 19:37:14 +0000 (21:37 +0200)
journald calls fd_get_path() a lot (it probably shouldn't, there's some
room for improvement there, but I'll leave that for another time), hence
it's worth optimizing the call a bit, in particular as it's easy.

Previously we'd open the dir /proc/self/fd/ first, before reading the
symlink inside it. This means the whole function requires three system
calls: open(), readlinkat(), close(). The reason for doing it this way
is to distinguish the case when we see ENOENT because /proc is not
mounted and the case when the fd doesn't exist.

With this change we'll directly go for the readlink(), and only if that
fails do an access() to see if /proc is mounted at all.

This optimizes the common case (where the fd is valid and /proc
mounted), in favour of the uncommon case (where the fd doesn#t exist or
/proc is not mounted).

src/basic/fd-util.c

index b97bd191ab2db928f207d370f7f7c48117698d29..5775a13e3e8067298195143d9ba8b88ae35eb98c 100644 (file)
@@ -353,22 +353,22 @@ bool fdname_is_valid(const char *s) {
 }
 
 int fd_get_path(int fd, char **ret) {
-        _cleanup_close_ int dir = -1;
-        char fdname[DECIMAL_STR_MAX(int)];
+        char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
         int r;
 
-        dir = open("/proc/self/fd/", O_CLOEXEC | O_DIRECTORY | O_PATH);
-        if (dir < 0)
-                /* /proc is not available or not set up properly, we're most likely
-                 * in some chroot environment. */
-                return errno == ENOENT ? -EOPNOTSUPP : -errno;
+        xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+        r = readlink_malloc(procfs_path, ret);
+        if (r == -ENOENT) {
+                /* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make
+                 * things debuggable and distuingish the two. */
 
-        xsprintf(fdname, "%i", fd);
+                if (access("/proc/self/fd/", F_OK) < 0)
+                        /* /proc is not available or not set up properly, we're most likely in some chroot
+                         * environment. */
+                        return errno == ENOENT ? -EOPNOTSUPP : -errno;
 
-        r = readlinkat_malloc(dir, fdname, ret);
-        if (r == -ENOENT)
-                /* If the file doesn't exist the fd is invalid */
-                return -EBADF;
+                return -EBADF; /* The directory exists, hence it's the fd that doesn't. */
+        }
 
         return r;
 }