![Arnd Bergmann](/assets/img/avatar_default.png)
This is another attempt to avoid a regression in wwn_to_u64() after that started using get_unaligned_be64(), which in turn ran into a bug on gcc-4.9 through 6.1. The regression got introduced due to the combination of two separate workarounds (commitse3bde9568d
: "include/linux/unaligned: force inlining of byteswap operations" andef3fb2422f
: "scsi: fc: use get/put_unaligned64 for wwn access") that each try to sidestep distinct problems with gcc behavior (code growth and increased stack usage). Unfortunately after both have been applied, a more serious gcc bug has been uncovered, leading to incorrect object code that discards part of a function and causes undefined behavior. As part of this problem is how __builtin_constant_p gets evaluated on an argument passed by reference into an inline function, this avoids the use of __builtin_constant_p() for all architectures that set CONFIG_ARCH_USE_BUILTIN_BSWAP. Most architectures do not set ARCH_SUPPORTS_OPTIMIZED_INLINING, which means they probably do not suffer from the problem in the qla2xxx driver, but they might still run into it elsewhere. Both of the original workarounds were only merged in the 4.6 kernel, and the bug that is fixed by this patch should only appear if both are there, so we probably don't need to backport the fix. On the other hand, it works by simplifying the code path and should not have any negative effects. [arnd@arndb.de: fix older gcc warnings] (http://lkml.kernel.org/r/12243652.bxSxEgjgfk@wuerfel) Link: https://lkml.org/lkml/headers/2016/4/12/1103 Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66122 Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70232 Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646 Fixes:e3bde9568d
("include/linux/unaligned: force inlining of byteswap operations") Fixes:ef3fb2422f
("scsi: fc: use get/put_unaligned64 for wwn access") Link: http://lkml.kernel.org/r/1780465.XdtPJpi8Tt@wuerfel Signed-off-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com> Tested-by: Josh Poimboeuf <jpoimboe@redhat.com> # on gcc-5.3 Tested-by: Quinn Tran <quinn.tran@qlogic.com> Cc: Martin Jambor <mjambor@suse.cz> Cc: "Martin K. Petersen" <martin.petersen@oracle.com> Cc: James Bottomley <James.Bottomley@hansenpartnership.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: Thomas Graf <tgraf@suug.ch> Cc: Peter Zijlstra <peterz@infradead.org> Cc: David Rientjes <rientjes@google.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Himanshu Madhani <himanshu.madhani@qlogic.com> Cc: Jan Hubicka <hubicka@ucw.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
295 lines
6.6 KiB
C
295 lines
6.6 KiB
C
#ifndef _UAPI_LINUX_SWAB_H
|
|
#define _UAPI_LINUX_SWAB_H
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/compiler.h>
|
|
#include <asm/swab.h>
|
|
|
|
/*
|
|
* casts are necessary for constants, because we never know how for sure
|
|
* how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way.
|
|
*/
|
|
#define ___constant_swab16(x) ((__u16)( \
|
|
(((__u16)(x) & (__u16)0x00ffU) << 8) | \
|
|
(((__u16)(x) & (__u16)0xff00U) >> 8)))
|
|
|
|
#define ___constant_swab32(x) ((__u32)( \
|
|
(((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
|
|
(((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \
|
|
(((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \
|
|
(((__u32)(x) & (__u32)0xff000000UL) >> 24)))
|
|
|
|
#define ___constant_swab64(x) ((__u64)( \
|
|
(((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) | \
|
|
(((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) | \
|
|
(((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) | \
|
|
(((__u64)(x) & (__u64)0x00000000ff000000ULL) << 8) | \
|
|
(((__u64)(x) & (__u64)0x000000ff00000000ULL) >> 8) | \
|
|
(((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
|
|
(((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) | \
|
|
(((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56)))
|
|
|
|
#define ___constant_swahw32(x) ((__u32)( \
|
|
(((__u32)(x) & (__u32)0x0000ffffUL) << 16) | \
|
|
(((__u32)(x) & (__u32)0xffff0000UL) >> 16)))
|
|
|
|
#define ___constant_swahb32(x) ((__u32)( \
|
|
(((__u32)(x) & (__u32)0x00ff00ffUL) << 8) | \
|
|
(((__u32)(x) & (__u32)0xff00ff00UL) >> 8)))
|
|
|
|
/*
|
|
* Implement the following as inlines, but define the interface using
|
|
* macros to allow constant folding when possible:
|
|
* ___swab16, ___swab32, ___swab64, ___swahw32, ___swahb32
|
|
*/
|
|
|
|
static inline __attribute_const__ __u16 __fswab16(__u16 val)
|
|
{
|
|
#if defined (__arch_swab16)
|
|
return __arch_swab16(val);
|
|
#else
|
|
return ___constant_swab16(val);
|
|
#endif
|
|
}
|
|
|
|
static inline __attribute_const__ __u32 __fswab32(__u32 val)
|
|
{
|
|
#if defined(__arch_swab32)
|
|
return __arch_swab32(val);
|
|
#else
|
|
return ___constant_swab32(val);
|
|
#endif
|
|
}
|
|
|
|
static inline __attribute_const__ __u64 __fswab64(__u64 val)
|
|
{
|
|
#if defined (__arch_swab64)
|
|
return __arch_swab64(val);
|
|
#elif defined(__SWAB_64_THRU_32__)
|
|
__u32 h = val >> 32;
|
|
__u32 l = val & ((1ULL << 32) - 1);
|
|
return (((__u64)__fswab32(l)) << 32) | ((__u64)(__fswab32(h)));
|
|
#else
|
|
return ___constant_swab64(val);
|
|
#endif
|
|
}
|
|
|
|
static inline __attribute_const__ __u32 __fswahw32(__u32 val)
|
|
{
|
|
#ifdef __arch_swahw32
|
|
return __arch_swahw32(val);
|
|
#else
|
|
return ___constant_swahw32(val);
|
|
#endif
|
|
}
|
|
|
|
static inline __attribute_const__ __u32 __fswahb32(__u32 val)
|
|
{
|
|
#ifdef __arch_swahb32
|
|
return __arch_swahb32(val);
|
|
#else
|
|
return ___constant_swahb32(val);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* __swab16 - return a byteswapped 16-bit value
|
|
* @x: value to byteswap
|
|
*/
|
|
#ifdef __HAVE_BUILTIN_BSWAP16__
|
|
#define __swab16(x) (__u16)__builtin_bswap16((__u16)(x))
|
|
#else
|
|
#define __swab16(x) \
|
|
(__builtin_constant_p((__u16)(x)) ? \
|
|
___constant_swab16(x) : \
|
|
__fswab16(x))
|
|
#endif
|
|
|
|
/**
|
|
* __swab32 - return a byteswapped 32-bit value
|
|
* @x: value to byteswap
|
|
*/
|
|
#ifdef __HAVE_BUILTIN_BSWAP32__
|
|
#define __swab32(x) (__u32)__builtin_bswap32((__u32)(x))
|
|
#else
|
|
#define __swab32(x) \
|
|
(__builtin_constant_p((__u32)(x)) ? \
|
|
___constant_swab32(x) : \
|
|
__fswab32(x))
|
|
#endif
|
|
|
|
/**
|
|
* __swab64 - return a byteswapped 64-bit value
|
|
* @x: value to byteswap
|
|
*/
|
|
#ifdef __HAVE_BUILTIN_BSWAP64__
|
|
#define __swab64(x) (__u64)__builtin_bswap64((__u64)(x))
|
|
#else
|
|
#define __swab64(x) \
|
|
(__builtin_constant_p((__u64)(x)) ? \
|
|
___constant_swab64(x) : \
|
|
__fswab64(x))
|
|
#endif
|
|
|
|
/**
|
|
* __swahw32 - return a word-swapped 32-bit value
|
|
* @x: value to wordswap
|
|
*
|
|
* __swahw32(0x12340000) is 0x00001234
|
|
*/
|
|
#define __swahw32(x) \
|
|
(__builtin_constant_p((__u32)(x)) ? \
|
|
___constant_swahw32(x) : \
|
|
__fswahw32(x))
|
|
|
|
/**
|
|
* __swahb32 - return a high and low byte-swapped 32-bit value
|
|
* @x: value to byteswap
|
|
*
|
|
* __swahb32(0x12345678) is 0x34127856
|
|
*/
|
|
#define __swahb32(x) \
|
|
(__builtin_constant_p((__u32)(x)) ? \
|
|
___constant_swahb32(x) : \
|
|
__fswahb32(x))
|
|
|
|
/**
|
|
* __swab16p - return a byteswapped 16-bit value from a pointer
|
|
* @p: pointer to a naturally-aligned 16-bit value
|
|
*/
|
|
static __always_inline __u16 __swab16p(const __u16 *p)
|
|
{
|
|
#ifdef __arch_swab16p
|
|
return __arch_swab16p(p);
|
|
#else
|
|
return __swab16(*p);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* __swab32p - return a byteswapped 32-bit value from a pointer
|
|
* @p: pointer to a naturally-aligned 32-bit value
|
|
*/
|
|
static __always_inline __u32 __swab32p(const __u32 *p)
|
|
{
|
|
#ifdef __arch_swab32p
|
|
return __arch_swab32p(p);
|
|
#else
|
|
return __swab32(*p);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* __swab64p - return a byteswapped 64-bit value from a pointer
|
|
* @p: pointer to a naturally-aligned 64-bit value
|
|
*/
|
|
static __always_inline __u64 __swab64p(const __u64 *p)
|
|
{
|
|
#ifdef __arch_swab64p
|
|
return __arch_swab64p(p);
|
|
#else
|
|
return __swab64(*p);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* __swahw32p - return a wordswapped 32-bit value from a pointer
|
|
* @p: pointer to a naturally-aligned 32-bit value
|
|
*
|
|
* See __swahw32() for details of wordswapping.
|
|
*/
|
|
static inline __u32 __swahw32p(const __u32 *p)
|
|
{
|
|
#ifdef __arch_swahw32p
|
|
return __arch_swahw32p(p);
|
|
#else
|
|
return __swahw32(*p);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* __swahb32p - return a high and low byteswapped 32-bit value from a pointer
|
|
* @p: pointer to a naturally-aligned 32-bit value
|
|
*
|
|
* See __swahb32() for details of high/low byteswapping.
|
|
*/
|
|
static inline __u32 __swahb32p(const __u32 *p)
|
|
{
|
|
#ifdef __arch_swahb32p
|
|
return __arch_swahb32p(p);
|
|
#else
|
|
return __swahb32(*p);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* __swab16s - byteswap a 16-bit value in-place
|
|
* @p: pointer to a naturally-aligned 16-bit value
|
|
*/
|
|
static inline void __swab16s(__u16 *p)
|
|
{
|
|
#ifdef __arch_swab16s
|
|
__arch_swab16s(p);
|
|
#else
|
|
*p = __swab16p(p);
|
|
#endif
|
|
}
|
|
/**
|
|
* __swab32s - byteswap a 32-bit value in-place
|
|
* @p: pointer to a naturally-aligned 32-bit value
|
|
*/
|
|
static __always_inline void __swab32s(__u32 *p)
|
|
{
|
|
#ifdef __arch_swab32s
|
|
__arch_swab32s(p);
|
|
#else
|
|
*p = __swab32p(p);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* __swab64s - byteswap a 64-bit value in-place
|
|
* @p: pointer to a naturally-aligned 64-bit value
|
|
*/
|
|
static __always_inline void __swab64s(__u64 *p)
|
|
{
|
|
#ifdef __arch_swab64s
|
|
__arch_swab64s(p);
|
|
#else
|
|
*p = __swab64p(p);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* __swahw32s - wordswap a 32-bit value in-place
|
|
* @p: pointer to a naturally-aligned 32-bit value
|
|
*
|
|
* See __swahw32() for details of wordswapping
|
|
*/
|
|
static inline void __swahw32s(__u32 *p)
|
|
{
|
|
#ifdef __arch_swahw32s
|
|
__arch_swahw32s(p);
|
|
#else
|
|
*p = __swahw32p(p);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* __swahb32s - high and low byteswap a 32-bit value in-place
|
|
* @p: pointer to a naturally-aligned 32-bit value
|
|
*
|
|
* See __swahb32() for details of high and low byte swapping
|
|
*/
|
|
static inline void __swahb32s(__u32 *p)
|
|
{
|
|
#ifdef __arch_swahb32s
|
|
__arch_swahb32s(p);
|
|
#else
|
|
*p = __swahb32p(p);
|
|
#endif
|
|
}
|
|
|
|
|
|
#endif /* _UAPI_LINUX_SWAB_H */
|