From: Christoph Hellwig Date: Fri, 28 Aug 2009 18:18:06 +0000 (-0300) Subject: xfsprogs: fix unaligned access in libxfs X-Git-Tag: v3.0.3~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=91eba724e3957a8fd1ef3c79614a3e453d151a8a;p=thirdparty%2Fxfsprogs-dev.git xfsprogs: fix unaligned access in libxfs The get/put unaligned handlers we use to access the extent descriptor are not good enough for architectures like Sparc that do not tolerate dereferencing unaligned pointers. Replace the implementation with the one the kernel uses on these architectures. It might be a tad slower on architectures like x86, but I don't want to have multiple implementations around to not let the testing matrix explode. Also remove the unaligned.h header which includes another implementation for unaligned access we don't actually use anymore. Note that the little change to xfs_inode.c needs to go into the kernel aswell, I will send a patch for that shortly. Signed-off-by: Christoph Hellwig Reviewed-by: Eric Sandeen Reported-by: Gabriel Vlasiu Tested-by: Gabriel Vlasiu --- diff --git a/include/Makefile b/include/Makefile index a7cd5c140..1ca507129 100644 --- a/include/Makefile +++ b/include/Makefile @@ -37,7 +37,7 @@ PHFILES = darwin.h freebsd.h irix.h linux.h DKHFILES = volume.h fstyp.h dvh.h LSRCFILES = $(shell echo $(PHFILES) | sed -e "s/$(PKG_PLATFORM).h//g") LSRCFILES += platform_defs.h.in builddefs.in buildmacros buildrules install-sh -LSRCFILES += $(DKHFILES) command.h input.h path.h project.h unaligned.h +LSRCFILES += $(DKHFILES) command.h input.h path.h project.h LDIRT = xfs disk default install: xfs disk diff --git a/include/unaligned.h b/include/unaligned.h deleted file mode 100644 index 7f75981ff..000000000 --- a/include/unaligned.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef _UNALIGNED_H_ -#define _UNALIGNED_H_ - -/* - * For the benefit of those who are trying to port Linux to another - * architecture, here are some C-language equivalents. - * - * This is based almost entirely upon Richard Henderson's - * asm-alpha/unaligned.h implementation. Some comments were - * taken from David Mosberger's asm-ia64/unaligned.h header. - */ - -/* - * The main single-value unaligned transfer routines. - */ -#define get_unaligned(ptr) \ - __get_unaligned((ptr), sizeof(*(ptr))) -#define put_unaligned(x,ptr) \ - __put_unaligned((__u64)(x), (ptr), sizeof(*(ptr))) - -/* - * This function doesn't actually exist. The idea is that when - * someone uses the macros below with an unsupported size (datatype), - * the linker will alert us to the problem via an unresolved reference - * error. - */ -extern void bad_unaligned_access_length(void) __attribute__((noreturn)); - -struct __una_u64 { __u64 x __attribute__((packed)); }; -struct __una_u32 { __u32 x __attribute__((packed)); }; -struct __una_u16 { __u16 x __attribute__((packed)); }; - -/* - * Elemental unaligned loads - */ - -static inline __u64 __uldq(const __u64 *addr) -{ - const struct __una_u64 *ptr = (const struct __una_u64 *) addr; - return ptr->x; -} - -static inline __u32 __uldl(const __u32 *addr) -{ - const struct __una_u32 *ptr = (const struct __una_u32 *) addr; - return ptr->x; -} - -static inline __u16 __uldw(const __u16 *addr) -{ - const struct __una_u16 *ptr = (const struct __una_u16 *) addr; - return ptr->x; -} - -/* - * Elemental unaligned stores - */ - -static inline void __ustq(__u64 val, __u64 *addr) -{ - struct __una_u64 *ptr = (struct __una_u64 *) addr; - ptr->x = val; -} - -static inline void __ustl(__u32 val, __u32 *addr) -{ - struct __una_u32 *ptr = (struct __una_u32 *) addr; - ptr->x = val; -} - -static inline void __ustw(__u16 val, __u16 *addr) -{ - struct __una_u16 *ptr = (struct __una_u16 *) addr; - ptr->x = val; -} - -#define __get_unaligned(ptr, size) ({ \ - const void *__gu_p = ptr; \ - __u64 val; \ - switch (size) { \ - case 1: \ - val = *(const __u8 *)__gu_p; \ - break; \ - case 2: \ - val = __uldw(__gu_p); \ - break; \ - case 4: \ - val = __uldl(__gu_p); \ - break; \ - case 8: \ - val = __uldq(__gu_p); \ - break; \ - default: \ - bad_unaligned_access_length(); \ - }; \ - (__typeof__(*(ptr)))val; \ -}) - -#define __put_unaligned(val, ptr, size) \ -do { \ - void *__gu_p = ptr; \ - switch (size) { \ - case 1: \ - *(__u8 *)__gu_p = val; \ - break; \ - case 2: \ - __ustw(val, __gu_p); \ - break; \ - case 4: \ - __ustl(val, __gu_p); \ - break; \ - case 8: \ - __ustq(val, __gu_p); \ - break; \ - default: \ - bad_unaligned_access_length(); \ - }; \ -} while(0) - -#endif /* _UNALIGNED_H */ diff --git a/libxfs/xfs.h b/libxfs/xfs.h index b99e569d6..8e94dad71 100644 --- a/libxfs/xfs.h +++ b/libxfs/xfs.h @@ -127,19 +127,37 @@ static inline int __do_div(unsigned long long *n, unsigned base) #define max_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) -/* only 64 bit accesses used in xfs kernel code */ -static inline __u64 get_unaligned_be64(void *ptr) + +static inline __uint32_t __get_unaligned_be32(const __uint8_t *p) +{ + return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + +static inline __uint64_t get_unaligned_be64(void *p) { - __be64 __tmp; - memmove(&__tmp, ptr, 8); - return be64_to_cpu(__tmp); + return (__uint64_t)__get_unaligned_be32(p) << 32 | + __get_unaligned_be32(p + 4); } -static inline void put_unaligned(__be64 val, void *ptr) +static inline void __put_unaligned_be16(__uint16_t val, __uint8_t *p) { - memmove(ptr, &val, 8); + *p++ = val >> 8; + *p++ = val; } +static inline void __put_unaligned_be32(__uint32_t val, __uint8_t *p) +{ + __put_unaligned_be16(val >> 16, p); + __put_unaligned_be16(val, p + 2); +} + +static inline void put_unaligned_be64(__uint64_t val, void *p) +{ + __put_unaligned_be32(val >> 32, p); + __put_unaligned_be32(val, p + 4); +} + + static inline __attribute__((const)) int is_power_of_2(unsigned long n) { diff --git a/libxfs/xfs_inode.c b/libxfs/xfs_inode.c index 97c0f09d5..b0adabc48 100644 --- a/libxfs/xfs_inode.c +++ b/libxfs/xfs_inode.c @@ -1056,8 +1056,8 @@ xfs_iextents_copy( } /* Translate to on disk format */ - put_unaligned(cpu_to_be64(ep->l0), &dp->l0); - put_unaligned(cpu_to_be64(ep->l1), &dp->l1); + put_unaligned_be64(ep->l0, &dp->l0); + put_unaligned_be64(ep->l1, &dp->l1); dp++; copied++; }