summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--util/nvmutil/nvmutil.c204
1 files changed, 155 insertions, 49 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index 0292a4cb..35ea6757 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -332,6 +332,8 @@ static void check_bin(size_t a, const char *a_name);
*/
static void rw_gbe_file_part(size_t p, int rw_type,
const char *rw_type_str);
+static void check_written_part(size_t p);
+static void report_io_err_rw(void);
static u8 *gbe_mem_offset(size_t part, const char *f_op);
static off_t gbe_file_offset(size_t part, const char *f_op);
static off_t gbe_x_offset(size_t part, const char *f_op,
@@ -353,8 +355,8 @@ static int try_err(int loop_err, int errval);
/*
* Error handling and cleanup
*/
+static int close_files(void);
static void err(int nvm_errval, const char *msg, ...);
-static void close_files(void);
static const char *getnvmprogname(void);
static void usage(int usage_exit);
@@ -407,8 +409,9 @@ static const char *rname = NULL;
*
* The code will handle this properly.
*/
-static u8 buf[GBE_FILE_SIZE];
-static u8 pad[GBE_PART_SIZE]; /* the file that wouldn't die */
+static u8 real_buf[GBE_FILE_SIZE];
+static u8 pad[GBE_FILE_SIZE]; /* the file that wouldn't die */
+static u8 *buf = real_buf;
static ushort mac_buf[3];
static off_t gbe_file_size;
@@ -603,6 +606,13 @@ typedef char bool_part_invert[(PART_INVERT==1)?1:-1];
static int use_prng = 0;
+static int io_err_gbe = 0;
+static int rw_check_err_read[] = {0, 0};
+static int rw_check_partial_read[] = {0, 0};
+static int rw_check_bad_part[] = {0, 0};
+
+static int post_rw_checksum[] = {0, 0};
+
int
main(int argc, char *argv[])
{
@@ -674,10 +684,29 @@ main(int argc, char *argv[])
run_cmd(cmd_index);
- if (command[cmd_index].flags == O_RDWR)
+ if (command[cmd_index].flags == O_RDWR) {
+
write_gbe_file();
- close_files();
+ /*
+ * We may otherwise read from
+ * cache, so we must sync.
+ */
+ if (fsync(gbe_fd) == -1)
+ err(errno, "%s: fsync (pre-verification)",
+ fname);
+
+ check_written_part(0);
+ check_written_part(1);
+
+ report_io_err_rw();
+
+ if (io_err_gbe)
+ err(EIO, "%s: bad write", fname);
+ }
+
+ if (close_files() == -1)
+ err(EIO, "%s: close", fname);
return EXIT_SUCCESS;
}
@@ -1520,38 +1549,104 @@ rw_gbe_file_part(size_t p, int rw_type,
if ((size_t)r != gbe_rw_size)
err(EIO, "%s: partial %s: part %lu",
fname, rw_type_str, (ulong)p);
+}
- /*
- * Next, we read back what was written,
- * to ensure that it was done correctly.
- * NOTE: using "pad" (only cat uses it)
- */
+static void
+check_written_part(size_t p)
+{
+ ssize_t r;
+ size_t gbe_rw_size;
+ u8 *mem_offset;
+ off_t file_offset;
+ u8 *buf_restore;
- if (rw_type != IO_PWRITE)
- return; /* skip for reads */
+ if (!part_modified[p])
+ return;
- /*
- * We may otherwise read from
- * cache, so we must sync.
- */
- if (fsync(gbe_fd) == -1)
- err(errno, "%s: fsync: part %lu (post-verification)",
- fname, (ulong)p);
+ gbe_rw_size = command[cmd_index].rw_size;
+
+ /* invert not needed for pwrite */
+ mem_offset = gbe_mem_offset(p, "pwrite");
+ file_offset = (off_t)gbe_file_offset(p, "pwrite");
+
+ memset(pad, 0xff, sizeof(pad));
r = rw_gbe_file_exact(gbe_fd, pad,
gbe_rw_size, file_offset, IO_PREAD);
if (r == -1)
- err(errno, "%s: pread: part %lu (post-verification)",
- fname, (ulong)p);
+ rw_check_err_read[p] = io_err_gbe = 1;
+ else if ((size_t)r != gbe_rw_size)
+ rw_check_partial_read[p] = io_err_gbe = 1;
+ else if (memcmp(mem_offset, pad, gbe_rw_size) != 0)
+ rw_check_bad_part[p] = io_err_gbe = 1;
+
+ if (rw_check_err_read[p] ||
+ rw_check_partial_read[p])
+ return;
- if ((size_t)r != gbe_rw_size)
- err(EIO, "%s: partial pread: part %lu (post-verification)",
- fname, (ulong)p);
+ /*
+ * We only load one part on-file, into memory but
+ * always at offset zero, for post-write checks.
+ * That's why we hardcode good_checksum(0).
+ */
+ buf_restore = buf;
+ buf = pad;
+ post_rw_checksum[p] = good_checksum(0);
+ buf = buf_restore;
+}
+
+static void
+report_io_err_rw(void)
+{
+ size_t p;
+
+ if (!io_err_gbe)
+ return;
- if (memcmp(mem_offset, pad, gbe_rw_size) != 0)
- err(errno, "%s: pwrite: corrupt write on part %lu",
- fname, (ulong)p);
+ for (p = 0; p < 2; p++) {
+ if (!part_modified[p])
+ continue;
+
+ if (rw_check_err_read[p])
+ fprintf(stderr,
+ "%s: pread: p%lu (post-verification)\n",
+ fname, (ulong)p);
+ if (rw_check_partial_read[p])
+ fprintf(stderr,
+ "%s: partial pread: p%lu (post-verification)\n",
+ fname, (ulong)p);
+ if (rw_check_bad_part[p])
+ fprintf(stderr,
+ "%s: pwrite: corrupt write on p%lu\n",
+ fname, (ulong)p);
+
+ if (rw_check_err_read[p] ||
+ rw_check_partial_read[p]) {
+ fprintf(stderr,
+ "%s: p%lu: skipped checksum verification "
+ "(because read failed)\n",
+ fname, (ulong)p);
+
+ continue;
+ }
+
+ fprintf(stderr, "%s: ", fname);
+
+ if (post_rw_checksum[p])
+ fprintf(stderr, "GOOD");
+ else
+ fprintf(stderr, "BAD");
+
+ fprintf(stderr, " checksum in p%lu on-disk.\n",
+ (ulong)p);
+
+ if (post_rw_checksum[p]) {
+ fprintf(stderr,
+ " This does NOT mean it's safe. it may be\n"
+ " salvageable if you use the cat feature.\n");
+ }
+ }
}
/*
@@ -1826,8 +1921,7 @@ try_rw_again:
saved_errno = errno;
if (lseek_loop(fd, off_orig, SEEK_SET,
loop_eagain, loop_eintr) == (off_t)-1) {
- if (r < 0)
- errno = saved_errno;
+ errno = saved_errno;
return -1;
}
errno = saved_errno;
@@ -1908,17 +2002,45 @@ try_err(int loop_err, int errval)
return -1;
}
+static int
+close_files(void)
+{
+ int close_err_gbe = 0;
+ int close_err_rand = 0;
+ int saved_errno = errno;
+
+ if (gbe_fd > -1) {
+ if (close(gbe_fd) == -1)
+ close_err_gbe = errno;
+ gbe_fd = -1;
+ }
+
+ if (urandom_fd > -1) {
+ if (close(urandom_fd) == -1)
+ close_err_rand = errno;
+ urandom_fd = -1;
+ }
+
+ if (saved_errno)
+ errno = saved_errno;
+
+ if (close_err_gbe || close_err_rand)
+ return -1;
+
+ return 0;
+}
+
static void
err(int nvm_errval, const char *msg, ...)
{
va_list args;
- if (nvm_errval >= 0) {
- close_files();
- errno = nvm_errval;
- }
if (errno <= 0)
errno = ECANCELED;
+ if (!errno)
+ errno = nvm_errval;
+
+ (void)close_files();
fprintf(stderr, "%s: ", getnvmprogname());
@@ -1932,22 +2054,6 @@ err(int nvm_errval, const char *msg, ...)
exit(EXIT_FAILURE);
}
-static void
-close_files(void)
-{
- if (gbe_fd > -1) {
- if (close(gbe_fd) == -1)
- err(-1, "%s: close failed", fname);
- gbe_fd = -1;
- }
-
- if (urandom_fd > -1) {
- if (close(urandom_fd) == -1)
- err(-1, "%s: close failed", rname);
- urandom_fd = -1;
- }
-}
-
static const char *
getnvmprogname(void)
{