Update to efivar 34, and include a patch to avoid upstream rate limiting.

Signed-off-by: Peter Jones <pjones@redhat.com>
This commit is contained in:
Peter Jones 2018-02-27 13:15:38 -05:00
parent c5680d4539
commit 1cf335fff3
3 changed files with 127 additions and 4 deletions

View File

@ -0,0 +1,117 @@
From 5ea8c3400693b30c2b65a887899dc2a8e36a9688 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Fri, 23 Feb 2018 15:49:02 -0500
Subject: [PATCH] efivarfs / vars: usleep() before reading from efivarfs if
euid != 0
There's a kernel rate limiter on efi variable reads now for
non-root users, and we'd rather just not hit it than have to dig out
from having hit it. So this adds a 10ms sleep before each read call.
If you do have 50 variables, efibootmgr will do 100 reads, which would
trigger the rate limit. In that case, this patch adds 1 second (plus
lossage due to calling, etc.), so it should stay just below the
triggering threshold. That will definitely be /smoother/ than hitting
it, and almost certainly faster as well, because the extra calls will
re-enforce the limit.
Signed-off-by: Peter Jones <pjones@redhat.com>
---
src/efivarfs.c | 12 ++++++++++++
src/vars.c | 11 +++++++++++
src/util.h | 7 +++++++
3 files changed, 30 insertions(+)
diff --git a/src/efivarfs.c b/src/efivarfs.c
index d1458a24d1e..38e4074e977 100644
--- a/src/efivarfs.c
+++ b/src/efivarfs.c
@@ -220,6 +220,16 @@ efivarfs_get_variable(efi_guid_t guid, const char *name, uint8_t **data,
int fd = -1;
char *path = NULL;
int rc;
+ int ratelimit;
+
+ /*
+ * The kernel rate limiter hits us if we go faster than 100 efi
+ * variable reads per second as non-root. So if we're not root, just
+ * delay this long after each read. The user is not going to notice.
+ *
+ * 1s / 100 = 10000us.
+ */
+ ratelimit = geteuid() == 0 ? 0 : 10000;
rc = make_efivarfs_path(&path, guid, name);
if (rc < 0) {
@@ -233,12 +243,14 @@ efivarfs_get_variable(efi_guid_t guid, const char *name, uint8_t **data,
goto err;
}
+ usleep(ratelimit);
rc = read(fd, &ret_attributes, sizeof (ret_attributes));
if (rc < 0) {
efi_error("read failed");
goto err;
}
+ usleep(ratelimit);
rc = read_file(fd, &ret_data, &size);
if (rc < 0) {
efi_error("read_file failed");
diff --git a/src/vars.c b/src/vars.c
index a7b5e2387f9..8522725a51f 100644
--- a/src/vars.c
+++ b/src/vars.c
@@ -305,6 +305,16 @@ vars_get_variable(efi_guid_t guid, const char *name, uint8_t **data,
char *path = NULL;
int rc;
int fd = -1;
+ int ratelimit;
+
+ /*
+ * The kernel rate limiter hits us if we go faster than 100 efi
+ * variable reads per second as non-root. So if we're not root, just
+ * delay this long after each read. The user is not going to notice.
+ *
+ * 1s / 100 = 10000us.
+ */
+ ratelimit = geteuid() == 0 ? 0 : 10000;
rc = asprintf(&path, "%s%s-" GUID_FORMAT "/raw_var",
get_vars_path(),
@@ -322,6 +332,7 @@ vars_get_variable(efi_guid_t guid, const char *name, uint8_t **data,
goto err;
}
+ usleep(ratelimit);
rc = read_file(fd, &buf, &bufsize);
if (rc < 0) {
efi_error("read_file(%s) failed", path);
diff --git a/src/util.h b/src/util.h
index deef7e71bc4..69042d3cf9a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -25,6 +25,7 @@
#include <endian.h>
#include <errno.h>
#include <limits.h>
+#include <sched.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
@@ -137,6 +138,12 @@ read_file(int fd, uint8_t **buf, size_t *bufsize)
* before doing so. */
s = read(fd, p, size - filesize);
if (s < 0 && errno == EAGAIN) {
+ /*
+ * if we got EAGAIN, there's a good chance we've hit
+ * the kernel rate limiter. Doing more reads is just
+ * going to make it worse, so instead, give it a rest.
+ */
+ sched_yield();
continue;
} else if (s < 0) {
int saved_errno = errno;
--
2.15.0

View File

@ -1,6 +1,6 @@
Name: efivar
Version: 33
Release: 3%{?dist}
Version: 34
Release: 1%{?dist}
Summary: Tools to manage UEFI variables
License: LGPLv2.1
URL: https://github.com/rhboot/efivar
@ -8,7 +8,10 @@ Requires: %{name}-libs = %{version}-%{release}
ExclusiveArch: %{ix86} x86_64 aarch64 %{arm}
BuildRequires: popt-devel git glibc-static libabigail
Source0: https://github.com/rhboot/efivar/archive/%{version}.tar.bz2
# please don't fix this to reflect github's incomprehensible url that goes
# to a different tarball.
Source0: https://github.com/rhboot/efivar/archive/efivar-%{version}.tar.bz2
Patch0001: 0001-efivarfs-vars-usleep-before-reading-from-efivarfs-if.patch
%description
efivar provides a simple command line interface to the UEFI variable facility.
@ -70,6 +73,9 @@ make libdir=%{_libdir} bindir=%{_bindir} CFLAGS="$RPM_OPT_FLAGS -flto" LDFLAGS="
%{_libdir}/*.so.*
%changelog
* Tue Feb 27 2018 Peter Jones <pjones@redhat.com> - 34-1
- Update to efivar 34, and include a patch to avoid upstream rate limiting.
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 33-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild

View File

@ -1 +1 @@
SHA512 (33.tar.bz2) = 76c053b38b6293e79eff2dcaaaed35c87e875fb7ab67163f91190085c2733c105b351d062b6f95786f95597396be5137284ab7537ba8b9968da4b648247862f3
SHA512 (efivar-34.tar.bz2) = 6baa02e1ad919f84d129a032a4631126d6f43dfc247f63c247624cc2af697fb627fd76fe0ffed069b42b835d862582877644fb19843361ef9ced62aa7cd518c4