]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
logind: also cache LoaderEntryOneShot EFI variable 16281/head
authorLennart Poettering <lennart@poettering.net>
Thu, 25 Jun 2020 14:25:41 +0000 (16:25 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 26 Jun 2020 08:43:42 +0000 (10:43 +0200)
With this we are now caching all EFI variables that we expose as
property in logind. Thus a client invoking GetAllProperties() should
only trgger a single read of each variable, but never repeated ones.

Obsoletes: #16190
Fixes: #14828
src/login/logind-dbus.c
src/login/logind.c
src/login/logind.h
src/shared/efi-loader.c
src/shared/efi-loader.h

index d8ae0287ec326769a67f83ac3da85f489374620b..079338fbb5deeb141f8a26cb94d4cf8757c082c2 100644 (file)
@@ -2920,24 +2920,25 @@ static int property_get_reboot_to_boot_loader_entry(
                 sd_bus_error *error) {
 
         _cleanup_free_ char *v = NULL;
+        Manager *m = userdata;
+        const char *x = NULL;
         int r;
 
         assert(bus);
         assert(reply);
-        assert(userdata);
+        assert(m);
 
         r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY");
         if (r == -ENXIO) {
                 /* EFI case: let's read the LoaderEntryOneShot variable */
 
-                r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", &v);
+                r = efi_loader_update_entry_one_shot_cache(&m->efi_loader_entry_one_shot, &m->efi_loader_entry_one_shot_stat);
                 if (r < 0) {
                         if (r != -ENOENT)
-                                log_warning_errno(r, "Failed to read LoaderEntryOneShot variable: %m");
-                } else if (!efi_loader_entry_name_valid(v)) {
-                        log_warning("LoaderEntryOneShot contains invalid entry name '%s', ignoring.", v);
-                        v = mfree(v);
-                }
+                                log_warning_errno(r, "Failed to read LoaderEntryOneShot variable, ignoring: %m");
+                } else
+                        x = m->efi_loader_entry_one_shot;
+
         } else if (r < 0)
                 log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY: %m");
         else if (r > 0) {
@@ -2947,14 +2948,14 @@ static int property_get_reboot_to_boot_loader_entry(
                 r = read_one_line_file("/run/systemd/reboot-to-boot-loader-entry", &v);
                 if (r < 0) {
                         if (r != -ENOENT)
-                                log_warning_errno(r, "Failed to read /run/systemd/reboot-to-boot-loader-entry: %m");
-                } else if (!efi_loader_entry_name_valid(v)) {
+                                log_warning_errno(r, "Failed to read /run/systemd/reboot-to-boot-loader-entry, ignoring: %m");
+                } else if (!efi_loader_entry_name_valid(v))
                         log_warning("/run/systemd/reboot-to-boot-loader-entry is not valid, ignoring.");
-                        v = mfree(v);
-                }
+                else
+                        x = v;
         }
 
-        return sd_bus_message_append(reply, "s", v);
+        return sd_bus_message_append(reply, "s", x);
 }
 
 static int boot_loader_entry_exists(Manager *m, const char *id) {
index 377fba25cfab8c33d058e5d6772aefe9c74c31ee..18caae348791a8f95cf22ba009664eb2d097e899 100644 (file)
@@ -169,6 +169,7 @@ static Manager* manager_unref(Manager *m) {
         free(m->action_job);
 
         strv_free(m->efi_boot_loader_entries);
+        free(m->efi_loader_entry_one_shot);
 
         return mfree(m);
 }
index 7dbf0c28e18ad18c1734b99d15006a4a2dc656ea..e64ecce8e2810b8380465d7b2b2cb96000c0a89c 100644 (file)
@@ -126,6 +126,9 @@ struct Manager {
 
         char **efi_boot_loader_entries;
         bool efi_boot_loader_entries_set;
+
+        char *efi_loader_entry_one_shot;
+        struct stat efi_loader_entry_one_shot_stat;
 };
 
 void manager_reset_config(Manager *m);
index ce9e78b2749d5ecca0d018b6e73510298c31e7bd..00e572c423eecf08f8a11c9710e2eab6797e58b7 100644 (file)
@@ -772,3 +772,35 @@ int efi_loader_get_config_timeout_one_shot(usec_t *ret) {
         *ret = cache = sec * USEC_PER_SEC; /* return in µs */
         return 0;
 }
+
+int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat) {
+        _cleanup_free_ char *fn = NULL, *v = NULL;
+        struct stat new_stat;
+        int r;
+
+        assert(cache);
+        assert(cache_stat);
+
+        fn = efi_variable_path(EFI_VENDOR_LOADER, "LoaderEntryOneShot");
+        if (!fn)
+                return -ENOMEM;
+
+        /* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
+        if (stat(fn, &new_stat) < 0)
+                return -errno;
+
+        if (stat_inode_unmodified(&new_stat, cache_stat))
+                return 0;
+
+        r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", &v);
+        if (r < 0)
+                return r;
+
+        if (!efi_loader_entry_name_valid(v))
+                return -EINVAL;
+
+        *cache_stat = new_stat;
+        free_and_replace(*cache, v);
+
+        return 0;
+}
index 98bb57ecbd5038dd174f15e5aa34a91c940eeb30..171274a0e342edafdc7cf798c45584deab8f035d 100644 (file)
@@ -3,6 +3,8 @@
 
 #include "efivars.h"
 
+#include <sys/stat.h>
+
 #if ENABLE_EFI
 
 int efi_reboot_to_firmware_supported(void);
@@ -24,6 +26,7 @@ int efi_loader_get_entries(char ***ret);
 int efi_loader_get_features(uint64_t *ret);
 
 int efi_loader_get_config_timeout_one_shot(usec_t *ret);
+int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat);
 
 #else
 
@@ -83,6 +86,10 @@ static inline int efi_loader_get_config_timeout_one_shot(usec_t *ret) {
         return -EOPNOTSUPP;
 }
 
+static inline int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat) {
+        return -EOPNOTSUPP;
+}
+
 #endif
 
 bool efi_loader_entry_name_valid(const char *s);