summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2026-03-10 02:32:13 +0000
committerLeah Rowe <leah@libreboot.org>2026-03-10 02:48:34 +0000
commit41314025898ea65038eafe1292180ab0a2c21658 (patch)
treeab1f908cb2cc65a65613f9c38c68a1a58a657612
parent0c23474322218ec64c73c647efdc6679f6119955 (diff)
util/nvmutil: safer read_gbe_file_exact
it now retries infinitely on EINTR, except when the return of pread is precisely zero, at which point it errs. this is better than having an arbitrary maximum like before, and increases robustness on unreliable file systems, e.g. NFS shares. Signed-off-by: Leah Rowe <leah@libreboot.org>
-rw-r--r--util/nvmutil/nvmutil.c50
1 files changed, 19 insertions, 31 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index b6570d42..c6c7b5f2 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -96,7 +96,7 @@ static void open_gbe_file(void);
static void xopen(int *fd, const char *path, int flags, struct stat *st);
static void read_gbe_file(void);
static void read_gbe_file_part(size_t part);
-static ssize_t read_gbe_file_exact(int fd, void *buf, size_t len,
+static void read_gbe_file_exact(int fd, uint8_t *buf, size_t len,
off_t off);
static void read_checksums(void);
static int good_checksum(size_t partnum);
@@ -132,7 +132,7 @@ static void check_nvm_bound(size_t pos16, size_t part);
static void check_bin(size_t a, const char *a_name);
static void write_gbe_file_part(size_t part);
static off_t gbe_file_offset(size_t part, const char *f_op);
-static void *gbe_mem_offset(size_t part, const char *f_op);
+static uint8_t *gbe_mem_offset(size_t part, const char *f_op);
static off_t gbe_x_offset(size_t part, const char *f_op,
const char *d_type, off_t nsize, off_t ncmp);
static void err(int nvm_errval, const char *msg, ...);
@@ -698,48 +698,36 @@ read_gbe_file(void)
static void
read_gbe_file_part(size_t p)
{
- ssize_t rc;
-
size_t gbe_rw_size = command[cmd_index].rw_size;
- void *mem_offset =
+ uint8_t *mem_offset =
gbe_mem_offset(p ^ command[cmd_index].invert, "pread");
- rc = read_gbe_file_exact(gbe_fd, mem_offset,
+ read_gbe_file_exact(gbe_fd, mem_offset,
gbe_rw_size, gbe_file_offset(p, "pread"));
-
- if (rc != (ssize_t)gbe_rw_size)
- err(ECANCELED, "%s: Partial read from p%zu", fname, p);
}
-static ssize_t
+static void
read_gbe_file_exact(int fd,
- void *buf, size_t len, off_t off)
+ uint8_t *buf, size_t len, off_t off)
{
- int retry;
- ssize_t rval;
+ ssize_t rval = -1;
+ ssize_t rc = 0;
if (fd == -1)
err(ECANCELED, "Trying to open bad fd: %s", fname);
- for (retry = 0; retry < MAX_RETRY_RW; retry++) {
- rval = pread(fd, buf, len, off);
-
- if (rval == (ssize_t)len) {
- errno = 0;
- return rval;
- } else if (rval != -1) {
- err(ECANCELED,
- "%s: Short pread of %zd bytes",
- fname, rval);
- } else if (errno != EINTR) {
- err(ECANCELED,
- "%s: Could not pread", fname);
+ for (rc = 0; rc != (ssize_t)len; rc += rval) {
+ if ((rval = pread(fd, buf + rc, len - rc, off + rc)) > -1) {
+ if (!rval) /* prevent infinite loop */
+ err(EIO, "%s: pread of 0 bytes", fname);
+ continue;
}
- }
- err(EINTR, "%s: pread: max retries exceeded", fname);
+ if (errno != EINTR || rval < -1)
+ err(EIO, "%s", fname);
- return -1;
+ errno = 0;
+ }
}
static void
@@ -1323,13 +1311,13 @@ gbe_file_offset(size_t p, const char *f_op)
* but used to check Gbe bounds in memory,
* and it is *also* used during file I/O.
*/
-static void *
+static uint8_t *
gbe_mem_offset(size_t p, const char *f_op)
{
off_t gbe_off = gbe_x_offset(p, f_op, "mem",
GBE_PART_SIZE, GBE_FILE_SIZE);
- return (void *)(buf + gbe_off);
+ return (uint8_t *)(buf + gbe_off);
}
static off_t