]> granicus.if.org Git - zfs/commitdiff
Disable GCCs aggressive loop optimization
authorBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 14 Jan 2014 17:39:13 +0000 (09:39 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 14 Jan 2014 21:55:58 +0000 (13:55 -0800)
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.

One way to resolve the issue would be to cast the array to a pointer
and fix all the iterators that might break.  The only loop where it
is known to cause a problem is 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 caused 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

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 31. This
problem causes an assert to be hit in a simple "zdb tank" when built
with --enable-debug.

However, this approach was not taken because we need to be absolutely
sure we catch all instances of this unwanted optimization.  Therefore,
the build system has been updated to detect if GCC supports the
aggressive loop optimization.  If it does the optimization will be
explicitly disabled using the -fno-aggressive-loop-optimization option.

Original-fix-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Tim Chase <tim@chase2k.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #2010
Closes #2051

config/Rules.am
config/always-no-aggressive-loop-optimizations.m4 [new file with mode: 0644]
config/kernel.m4
config/zfs-build.m4

index e3fa5b5a409381e0cdfe2109b7e4741a76eabbb3..24f94264ba864cfde901f204ea877d65446b1566 100644 (file)
@@ -1,8 +1,10 @@
 DEFAULT_INCLUDES = -include ${top_builddir}/zfs_config.h
 
 AM_LIBTOOLFLAGS = --silent
-AM_CFLAGS  = -Wall -Wstrict-prototypes
-AM_CFLAGS += -fno-strict-aliasing ${NO_UNUSED_BUT_SET_VARIABLE} ${DEBUG_CFLAGS}
+AM_CFLAGS  = ${DEBUG_CFLAGS} -Wall -Wstrict-prototypes
+AM_CFLAGS += ${NO_UNUSED_BUT_SET_VARIABLE}
+AM_CFLAGS += ${NO_AGGRESSIVE_LOOP_OPTIMIZATIONS}
+AM_CFLAGS += -fno-strict-aliasing
 AM_CPPFLAGS  = -D_GNU_SOURCE -D__EXTENSIONS__ -D_REENTRANT
 AM_CPPFLAGS += -D_POSIX_PTHREAD_SEMANTICS -D_FILE_OFFSET_BITS=64
 AM_CPPFLAGS += -D_LARGEFILE64_SOURCE -DTEXT_DOMAIN=\"zfs-linux-user\"
diff --git a/config/always-no-aggressive-loop-optimizations.m4 b/config/always-no-aggressive-loop-optimizations.m4
new file mode 100644 (file)
index 0000000..8f2115a
--- /dev/null
@@ -0,0 +1,20 @@
+dnl #
+dnl # Check if gcc supports -fno-aggressive-loop-optimizations
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_NO_AGGRESSIVE_LOOP_OPTIMIZATIONS], [
+       AC_MSG_CHECKING([for -fno-aggressive-loop-optimizations support])
+
+       saved_flags="$CFLAGS"
+       CFLAGS="$CFLAGS -fno-aggressive-loop-optimizations"
+
+       AC_RUN_IFELSE([AC_LANG_PROGRAM([], [])], [
+               NO_AGGRESSIVE_LOOP_OPTIMIZATIONS=-fno-aggressive-loop-optimizations
+               AC_MSG_RESULT([yes])
+       ], [
+               NO_AGGRESSIVE_LOOP_OPTIMIZATIONS=
+               AC_MSG_RESULT([no])
+       ])
+
+       CFLAGS="$saved_flags"
+       AC_SUBST([NO_AGGRESSIVE_LOOP_OPTIMIZATIONS])
+])
index cbf0ca3d69d638e36c565fca69bead35cda2da1e..62a9b4299ef41d1d2c24171a27eddd919f9fbc6a 100644 (file)
@@ -104,6 +104,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
        dnl # -Wall -fno-strict-aliasing -Wstrict-prototypes and other
        dnl # compiler options are added by the kernel build system.
        KERNELCPPFLAGS="$KERNELCPPFLAGS $NO_UNUSED_BUT_SET_VARIABLE"
+       KERNELCPPFLAGS="$KERNELCPPFLAGS $NO_AGGRESSIVE_LOOP_OPTIMIZATIONS"
        KERNELCPPFLAGS="$KERNELCPPFLAGS -DHAVE_SPL -D_KERNEL"
        KERNELCPPFLAGS="$KERNELCPPFLAGS -DTEXT_DOMAIN=\\\"zfs-linux-kernel\\\""
 
index 005185b038115484c426faf80a3871909ac793fd..477b916786b878bd955469afe724f0b4a6bdf138 100644 (file)
@@ -62,6 +62,7 @@ AC_DEFUN([ZFS_AC_DEBUG_DMU_TX], [
 
 AC_DEFUN([ZFS_AC_CONFIG_ALWAYS], [
        ZFS_AC_CONFIG_ALWAYS_NO_UNUSED_BUT_SET_VARIABLE
+       ZFS_AC_CONFIG_ALWAYS_NO_AGGRESSIVE_LOOP_OPTIMIZATIONS
 ])
 
 AC_DEFUN([ZFS_AC_CONFIG], [