summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/nvmutil/nvmutil.c107
1 files changed, 66 insertions, 41 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index bea8ea2c..fe8364f7 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -745,7 +745,10 @@ main(int argc, char *argv[])
#endif
#endif
+#if !defined(HAVE_ARC4RANDOM_BUF) || \
+ (HAVE_ARC4RANDOM_BUF) < 1
srand((uint)(time(NULL) ^ getpid()));
+#endif
open_gbe_file();
lock_gbe_file();
@@ -944,11 +947,17 @@ xstrxcmp(const char *a, const char *b, size_t maxlen)
err(EINVAL, "Empty string in xstrxcmp");
for (i = 0; i < maxlen; i++) {
- if (a[i] != b[i])
- return (u8)a[i] - (u8)b[i];
+ u8 ac = (u8)a[i];
+ u8 bc = (u8)b[i];
- if (a[i] == '\0')
- return 0;
+ if (ac == '\0' || bc == '\0') {
+ if (ac == bc)
+ return 0;
+ return ac - bc;
+ }
+
+ if (ac != bc)
+ return ac - bc;
}
/*
@@ -1814,9 +1823,10 @@ rw_gbe_file_exact(int fd, u8 *mem, size_t nrw,
{
size_t mem_addr;
size_t buf_addr;
+ ssize_t r;
- if (mem == NULL)
- goto err_rw_gbe_file_exact;
+ if (io_args(fd, mem, nrw, off, rw_type) == -1)
+ return -1;
mem_addr = (size_t)(void *)mem;
buf_addr = (size_t)(void *)buf;
@@ -1835,13 +1845,15 @@ rw_gbe_file_exact(int fd, u8 *mem, size_t nrw,
if (nrw > (size_t)(gbe_file_size - off))
goto err_rw_gbe_file_exact;
- if (nrw > GBE_PART_SIZE)
+ if (nrw > (size_t)GBE_PART_SIZE)
goto err_rw_gbe_file_exact;
- return rw_file_exact(fd, mem, nrw, off, rw_type,
+ r = rw_file_exact(fd, mem, nrw, off, rw_type,
NO_LOOP_EAGAIN, LOOP_EINTR, MAX_ZERO_RW_RETRY,
OFF_ERR);
+ return rw_over_nrw(r, nrw);
+
err_rw_gbe_file_exact:
errno = EIO;
return -1;
@@ -1896,7 +1908,7 @@ rw_file_exact(int fd, u8 *mem, size_t nrw,
while (1) {
/* Prevent theoretical overflow */
- if ((size_t)rv > (nrw - rc))
+ if (rv >= 0 && (size_t)rv > (nrw - rc))
goto err_rw_file_exact;
rc += rv;
@@ -1905,6 +1917,8 @@ rw_file_exact(int fd, u8 *mem, size_t nrw,
mem_cur = (void *)(mem + (size_t)rc);
nrw_cur = (size_t)(nrw - (size_t)rc);
+ if (off < 0)
+ goto err_rw_file_exact;
off_cur = (off_t)((size_t)off + (size_t)rc);
rv = prw(fd, mem_cur, nrw_cur, off_cur,
@@ -2061,42 +2075,49 @@ real_pread_pwrite:
* if the offset changed to what
* we previously got. If it did,
* then another thread may have
- * changed it.
- *
- * This is no substitute for real
- * pread/pwrite, which would be
- * fully atomic at kernel-level
- * and do not use file offsets.
+ * changed it. Enabled if
+ * off_reset is OFF_RESET.
*
- * TODO: Add a toggle to make it
- * recover instead, reset
- * to known offset, and
- * carry on operations.
- *
- * Failure is the better option
- * here, since recovery would
- * mask hidden bugs in code.
- * We cannot guarantee thread
- * safety, except in the event
- * that violations cause exit;
- * you would then debug it.
+ * We do this *once*, on the theory
+ * that nothing is touching it now.
*/
- if (off != verified) {
- if (!off_reset)
- goto err_prw;
-
- if (lseek_loop(fd, off, SEEK_SET,
- loop_eagain, loop_eintr) == (off_t)-1)
- return -1;
- }
+ if (off_reset && off != verified)
+ lseek_loop(fd, off, SEEK_SET,
+ loop_eagain, loop_eintr);
do {
+ /*
+ * Verify again before I/O
+ * (even with OFF_ERR)
+ *
+ * This implements the first check
+ * even with OFF_ERR, but without
+ * the recovery. On ERR_RESET, if
+ * the check fails again, then we
+ * know something else is touching
+ * the file, so it's best that we
+ * probably leave it alone and err.
+ *
+ * In other words, ERR_RESET only
+ * tolerates one change. Any more
+ * will cause an exit, including
+ * per EINTR/EAGAIN re-spin.
+ */
+ verified = lseek_loop(fd, (off_t)0, SEEK_CUR,
+ loop_eagain, loop_eintr);
+
+ if (off != verified)
+ goto err_prw;
+
if (rw_type == IO_PREAD)
r = read(fd, mem, nrw);
else if (rw_type == IO_PWRITE)
r = write(fd, mem, nrw);
- r = rw_over_nrw(r, nrw);
+ if (rw_over_nrw(r, nrw) == -1) {
+ errno = EIO;
+ break;
+ }
} while (r == -1 &&
(errno == try_err(loop_eintr, EINTR)
@@ -2104,14 +2125,15 @@ real_pread_pwrite:
}
saved_errno = errno;
+
off_last = lseek_loop(fd, off_orig, SEEK_SET,
loop_eagain, loop_eintr);
- if (off_last == (off_t)-1) {
+
+ if (off_last != off_orig) {
errno = saved_errno;
- return -1;
- }
- if (off_last != off_orig)
goto err_prw;
+ }
+
errno = saved_errno;
return rw_over_nrw(r, nrw);
@@ -2134,7 +2156,7 @@ io_args(int fd, void *mem, size_t nrw,
if (fd < 0)
goto err_io_args;
- /* prevent underflow */
+ /* negative offset */
if (off < 0)
goto err_io_args;
@@ -2150,6 +2172,9 @@ io_args(int fd, void *mem, size_t nrw,
if (((size_t)off + nrw) < (size_t)off)
goto err_io_args;
+ if (rw_type > IO_PWRITE)
+ goto err_io_args;
+
return 0;
err_io_args: