mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-07-24 12:12:59 +02:00
util/nvmutil: partially mitigate fd offset race
our fallback pwrite/pread behaviour still does not properly replicate the safety of real pwrite/pread i intend to put this i/o code into a library for use in other programs; nvmutil is single-threaded so this change is largely redundant (but can't hurt) Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
+33
-3
@@ -1951,6 +1951,7 @@ prw(int fd, void *mem, size_t nrw,
|
|||||||
int saved_errno;
|
int saved_errno;
|
||||||
int positional_rw;
|
int positional_rw;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
off_t verified;
|
||||||
|
|
||||||
if (mem == NULL)
|
if (mem == NULL)
|
||||||
goto err_prw;
|
goto err_prw;
|
||||||
@@ -2014,11 +2015,38 @@ real_pread_pwrite:
|
|||||||
goto real_pread_pwrite;
|
goto real_pread_pwrite;
|
||||||
#else
|
#else
|
||||||
if ((off_orig = lseek_loop(fd, (off_t)0, SEEK_CUR,
|
if ((off_orig = lseek_loop(fd, (off_t)0, SEEK_CUR,
|
||||||
loop_eagain, loop_eintr)) == (off_t)-1)
|
loop_eagain, loop_eintr)) == (off_t)-1) {
|
||||||
r = -1;
|
r = -1;
|
||||||
else if (lseek_loop(fd, off, SEEK_SET,
|
} else if (lseek_loop(fd, off, SEEK_SET,
|
||||||
loop_eagain, loop_eintr) == (off_t)-1)
|
loop_eagain, loop_eintr) == (off_t)-1) {
|
||||||
r = -1;
|
r = -1;
|
||||||
|
} else {
|
||||||
|
verified = lseek_loop(fd, (off_t)0, SEEK_CUR,
|
||||||
|
loop_eagain, loop_eintr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Partial thread-safety: detect
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
if (off != verified)
|
||||||
|
goto err_prw;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (rw_type == IO_PREAD)
|
if (rw_type == IO_PREAD)
|
||||||
@@ -2027,9 +2055,11 @@ real_pread_pwrite:
|
|||||||
r = write(fd, mem, nrw);
|
r = write(fd, mem, nrw);
|
||||||
|
|
||||||
r = rw_over_nrw(r, nrw);
|
r = rw_over_nrw(r, nrw);
|
||||||
|
|
||||||
} while (r == -1 &&
|
} while (r == -1 &&
|
||||||
(errno == try_err(loop_eintr, EINTR)
|
(errno == try_err(loop_eintr, EINTR)
|
||||||
|| errno == try_err(loop_eagain, EAGAIN)));
|
|| errno == try_err(loop_eagain, EAGAIN)));
|
||||||
|
}
|
||||||
|
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
off_last = lseek_loop(fd, off_orig, SEEK_SET,
|
off_last = lseek_loop(fd, off_orig, SEEK_SET,
|
||||||
|
|||||||
Reference in New Issue
Block a user