erofs-utils: mkfs: fix an indefinite wait race
authorGao Xiang <hsiangkao@linux.alibaba.com>
Wed, 21 Aug 2024 03:43:26 +0000 (11:43 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Wed, 21 Aug 2024 03:47:18 +0000 (11:47 +0800)
Coverity reports: In erofs_mkfs_flushjobs, a thread waits for
a thread-shared condition that may have already been satisfied,
causing a hang.

It might indeed happen if the dfops worker runs with the specific
timing.  Let's try to fix it and see if the report is cleared.

Coverity-id: 502330
Fixes: 37e5abcd8720 ("erofs-utils: mkfs: assign root NID in the main thread")
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20240821034326.2464146-1-hsiangkao@linux.alibaba.com
lib/inode.c

index b9dbbd609b8b56205e7f812eeccbc652a5b8ec1b..128c051712ac584da15357e3e82baefd20052a62 100644 (file)
@@ -1326,6 +1326,7 @@ struct erofs_mkfs_dfops {
        pthread_cond_t full, empty, drain;
        struct erofs_mkfs_jobitem *queue;
        unsigned int entries, head, tail;
+       bool idle;      /* initialize as false before the dfops worker runs */
 };
 
 #define EROFS_MT_QUEUE_SIZE 128
@@ -1335,7 +1336,8 @@ static void erofs_mkfs_flushjobs(struct erofs_sb_info *sbi)
        struct erofs_mkfs_dfops *q = sbi->mkfs_dfops;
 
        pthread_mutex_lock(&q->lock);
-       pthread_cond_wait(&q->drain, &q->lock);
+       if (!q->idle)
+               pthread_cond_wait(&q->drain, &q->lock);
        pthread_mutex_unlock(&q->lock);
 }
 
@@ -1345,6 +1347,8 @@ static void *erofs_mkfs_pop_jobitem(struct erofs_mkfs_dfops *q)
 
        pthread_mutex_lock(&q->lock);
        while (q->head == q->tail) {
+               /* the worker has handled everything only if sleeping here */
+               q->idle = true;
                pthread_cond_signal(&q->drain);
                pthread_cond_wait(&q->empty, &q->lock);
        }
@@ -1390,6 +1394,7 @@ static int erofs_mkfs_go(struct erofs_sb_info *sbi,
        item->type = type;
        memcpy(&item->u, elem, size);
        q->tail = (q->tail + 1) & (q->entries - 1);
+       q->idle = false;
 
        pthread_cond_signal(&q->empty);
        pthread_mutex_unlock(&q->lock);
@@ -1812,7 +1817,7 @@ static int erofs_mkfs_build_tree(struct erofs_mkfs_buildtree_ctx *ctx)
        int err, err2;
        struct erofs_sb_info *sbi = ctx->sbi ? ctx->sbi : ctx->u.root->sbi;
 
-       q = malloc(sizeof(*q));
+       q = calloc(1, sizeof(*q));
        if (!q)
                return -ENOMEM;
 
@@ -1827,8 +1832,6 @@ static int erofs_mkfs_build_tree(struct erofs_mkfs_buildtree_ctx *ctx)
        pthread_cond_init(&q->full, NULL);
        pthread_cond_init(&q->drain, NULL);
 
-       q->head = 0;
-       q->tail = 0;
        sbi->mkfs_dfops = q;
        err = pthread_create(&sbi->dfops_worker, NULL,
                             z_erofs_mt_dfops_worker, sbi);