From: Lennart Poettering Date: Thu, 25 Jun 2020 14:25:41 +0000 (+0200) Subject: logind: also cache LoaderEntryOneShot EFI variable X-Git-Tag: v246-rc1~79^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F16281%2Fhead;p=thirdparty%2Fsystemd.git logind: also cache LoaderEntryOneShot EFI variable 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 --- diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index d8ae0287ec3..079338fbb5d 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -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) { diff --git a/src/login/logind.c b/src/login/logind.c index 377fba25cfa..18caae34879 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -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); } diff --git a/src/login/logind.h b/src/login/logind.h index 7dbf0c28e18..e64ecce8e28 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -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); diff --git a/src/shared/efi-loader.c b/src/shared/efi-loader.c index ce9e78b2749..00e572c423e 100644 --- a/src/shared/efi-loader.c +++ b/src/shared/efi-loader.c @@ -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; +} diff --git a/src/shared/efi-loader.h b/src/shared/efi-loader.h index 98bb57ecbd5..171274a0e34 100644 --- a/src/shared/efi-loader.h +++ b/src/shared/efi-loader.h @@ -3,6 +3,8 @@ #include "efivars.h" +#include + #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);