]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: fix prefetch queue waiting
authorEric Sandeen <sandeen@redhat.com>
Tue, 8 Apr 2014 08:56:59 +0000 (18:56 +1000)
committerDave Chinner <david@fromorbit.com>
Tue, 8 Apr 2014 08:56:59 +0000 (18:56 +1000)
97b1fcf xfs_repair: fix array overrun in do_inode_prefetch

The thread creation loop has 2 ways to exit; either via
the loop counter based on thread_count, or the break statement
if we've started enough workers to cover all AGs.

Whether or not the loop counter "i" reflects the number of
threads started depends on whether or not we exited via the
break.

The above commit prevented us from indexing off the end
of the queues[] array if we actually advanced "i" all the
way to thread_count, but in the case where we break, "i"
is one *less* than the nr of threads started, so we don't
wait for completion of all threads, and all hell breaks
loose in phase 5.

Just stop with the cleverness of re-using the loop counter -
instead, explicitly count threads that we start, and then use
that counter to wait for each worker to complete.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
repair/prefetch.c

index e47a48e398d8e9fca036d76fa0e9bd86dd6c6fad..4c32395d9f1d2f3566e43bd3eecbf7928f4b898a 100644 (file)
@@ -944,6 +944,7 @@ do_inode_prefetch(
        int                     i;
        struct work_queue       queue;
        struct work_queue       *queues;
+       int                     queues_started = 0;
 
        /*
         * If the previous phases of repair have not overflowed the buffer
@@ -987,6 +988,7 @@ do_inode_prefetch(
 
                create_work_queue(&queues[i], mp, 1);
                queue_work(&queues[i], prefetch_ag_range_work, 0, wargs);
+               queues_started++;
 
                if (wargs->end_ag >= mp->m_sb.sb_agcount)
                        break;
@@ -995,7 +997,7 @@ do_inode_prefetch(
        /*
         * wait for workers to complete
         */
-       while (i--)
+       for (i = 0; i < queues_started; i++)
                destroy_work_queue(&queues[i]);
        free(queues);
 }