zfsonlinux/zfs — pull request #2010 by dweeezil (2013-12-29 17:52:15+00:00)
Title: Work around GCC 4.8 aggressive loop optimization.

GCC >+ 4.8's aggressive loop optimization breaks some of the iterators
over the dn_blkptr[] pseudo-array in dnode_phys. Since dn_blkptr[] is
defined as a single-element array, GCC believes an iterator can only
access index 0 and will unroll the loop into a single iteration.

This commit works around the optimization by casting the array to a
pointer and is definitely a hack. It fixes all obvious iterators that
might break, however, the only loop where it was known to cause problems
was this loop in dmu_objset_write_ready():

for (i = 0; i < dnp->dn_nblkptr; i++)
bp->blk_fill += dnp->dn_blkptr[i].blk_fill;

In the common case where dn_nblkptr is 3, the loop is only executed a
single time and "i" is equal to 1 following the loop.

The specific breakage cause by this problem is that the blk_fill of
root block pointers wouldn't be set properly when more than one blkptr
is in use (when no indrect blocks are needed).

The simple reproducing sequence is:

zpool create tank /tank.img
zdb -ddddd tank 0

and notice that "fill=31", however, there are two L0 indirect blocks with
"F=31" and "F=5". The fill count should be 36 rather than 35. This problem
causes an assert to be hit in a simple "zdb tank" when built with --enable-debug.