[PATCH] erofs-utils: lib/diskbuf: fix MT data race in erofs_diskbuf_reserve()
Utkal Singh
singhutkal015 at gmail.com
Thu Apr 2 16:04:24 AEDT 2026
Two threads calling erofs_diskbuf_reserve() concurrently can both
observe strm->locked == false and both advance tailoffset, silently
producing an incorrect offset in the output image. Add a
pthread_mutex_t to serialize access.
The commit path also gains the missing strm->locked = false reset;
without it, locked was set once and never cleared, making the flag
a latch rather than a guard.
libpthread is already a build requirement (-lpthread in
lib/Makefile.am) and pthread_mutex_t is used identically in
lib/workqueue.c and lib/compress.c, so no build system changes
are required.
Fixes: 13f7268 ("erofs-utils: lib: introduce multi-threaded I/O framework")
Signed-off-by: Utkal Singh <singhutkal015 at gmail.com>
---
lib/diskbuf.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/lib/diskbuf.c b/lib/diskbuf.c
index 0bf42da..ccfeaa4 100644
--- a/lib/diskbuf.c
+++ b/lib/diskbuf.c
@@ -2,6 +2,7 @@
#include "erofs/diskbuf.h"
#include "erofs/internal.h"
#include "erofs/print.h"
+#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
@@ -15,6 +16,7 @@ static struct erofs_diskbufstrm {
int fd;
unsigned int alignsize;
bool locked;
+ pthread_mutex_t lock;
} *dbufstrm;
int erofs_diskbuf_getfd(struct erofs_diskbuf *db, u64 *fpos)
@@ -34,15 +36,20 @@ int erofs_diskbuf_reserve(struct erofs_diskbuf *db, int sid, u64 *off)
{
struct erofs_diskbufstrm *strm = dbufstrm + sid;
- if (strm->tailoffset & (strm->alignsize - 1)) {
- strm->tailoffset = round_up(strm->tailoffset, strm->alignsize);
+ pthread_mutex_lock(&strm->lock);
+ if (strm->locked) {
+ pthread_mutex_unlock(&strm->lock);
+ return -EBUSY;
}
+ if (strm->tailoffset & (strm->alignsize - 1))
+ strm->tailoffset = round_up(strm->tailoffset, strm->alignsize);
db->offset = strm->tailoffset;
if (off)
*off = db->offset + strm->devpos;
db->sp = strm;
(void)erofs_atomic_inc_return(&strm->count);
- strm->locked = true; /* TODO: need a real lock for MT */
+ strm->locked = true;
+ pthread_mutex_unlock(&strm->lock);
return strm->fd;
}
@@ -51,9 +58,12 @@ void erofs_diskbuf_commit(struct erofs_diskbuf *db, u64 len)
struct erofs_diskbufstrm *strm = db->sp;
DBG_BUGON(!strm);
+ pthread_mutex_lock(&strm->lock);
DBG_BUGON(!strm->locked);
DBG_BUGON(strm->tailoffset != db->offset);
strm->tailoffset += len;
+ strm->locked = false;
+ pthread_mutex_unlock(&strm->lock);
}
void erofs_diskbuf_close(struct erofs_diskbuf *db)
@@ -115,6 +125,7 @@ int erofs_diskbuf_init(unsigned int nstrms)
setupone:
strm->tailoffset = 0;
erofs_atomic_set(&strm->count, 1);
+ pthread_mutex_init(&strm->lock, NULL);
if (fstat(strm->fd, &st))
return -errno;
strm->alignsize = max_t(u32, st.st_blksize, getpagesize());
@@ -132,6 +143,7 @@ void erofs_diskbuf_exit(void)
for (strm = dbufstrm; strm->fd >= 0; ++strm) {
DBG_BUGON(erofs_atomic_read(&strm->count) != 1);
+ pthread_mutex_destroy(&strm->lock);
close(strm->fd);
strm->fd = -1;
}
--
2.43.0
More information about the Linux-erofs
mailing list