util/nvmutil: extra race-condition check in prw

even with OFF_RESET, we still want some error checking.
if the check fails again immediately after, then it
suggests that another program really is modifying the
file, so we should stop.

the first check is done on the theory that another
program *was* working on it, but now isn't.

once again, this isn't perfect. use read pread/pwrite
if you need thread safety (and even then, you still
need to actually check your code)

Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
Leah Rowe
2026-03-15 00:49:57 +00:00
parent 8c0946e9ba
commit b09f52547f
+20 -19
View File
@@ -2073,25 +2073,8 @@ real_pread_pwrite:
* if the offset changed to what * if the offset changed to what
* we previously got. If it did, * we previously got. If it did,
* then another thread may have * then another thread may have
* changed it. * changed it. Enabled if
* * off_reset is OFF_RESET.
* This is no substitute for real
* pread/pwrite, which would be
* fully atomic at kernel-level
* and do not use file offsets.
*
* 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.
*/ */
if (off != verified) { if (off != verified) {
if (!off_reset) if (!off_reset)
@@ -2112,6 +2095,24 @@ real_pread_pwrite:
return -1; return -1;
} }
verified = lseek_loop(fd, (off_t)0, SEEK_CUR,
loop_eagain, loop_eintr);
/*
* 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.
*/
if (verified != off)
goto err_prw;
do { do {
if (rw_type == IO_PREAD) if (rw_type == IO_PREAD)
r = read(fd, mem, nrw); r = read(fd, mem, nrw);