Miguel Figueiredo Mascarenhas Sousa Filipe
2008-Mar-24 05:45 UTC
[Btrfs-devel] [PATCH] Endianess bug fix for v0.13 with kernels older than 2.6.23.
Fix for a endianess BUG when using btrfs v0.13 with kernels older than 2.6.23 Problem: Has of v0.13, btrfs-progs is using crc32c.c equivalent to the one found on linux-2.6.23/lib/libcrc32c.c Since crc32c_le() changed in linux-2.6.23, when running btrfs v0.13 with older kernels we have a missmatch between the versions of crc32c_le() from btrfs-progs and libcrc32c in the kernel. This missmatch causes a bug when using btrfs on big endian machines. Solution: btrfs_crc32c() macro that when compiling for kernels older than 2.6.23, does endianess conversion to parameters and return value of crc32c(). This endianess conversion nullifies the differences in implementation of crc32c_le(). If kernel 2.6.23 or better, it calls crc32c(). Signed-off-by: Miguel Sousa Filipe <miguel.filipe@gmail.com> --- diff -r 5c0d66b6195b -r e8daa3967ff4 crc32c.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc32c.h Mon Mar 24 12:31:37 2008 +0000 @@ -0,0 +1,17 @@ +#include <asm/byteorder.h> +#include <linux/crc32c.h> +#include <linux/version.h> + +/** + * implementation of crc32c_le() changed in linux-2.6.23, + * has of v0.13 btrfs-progs is using the latest version. + * We must workaround older implementations of crc32c_le() + * found on older kernel versions. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) +#define btrfs_crc32c(seed, data, length) \ + __cpu_to_le32( crc32c( __le32_to_cpu(seed), (unsigned char const *)data, length) ) +#else +#define btrfs_crc32c(seed, data, length) \ + crc32c(seed, (unsigned char const *)data, length) +#endif diff -r 5c0d66b6195b -r e8daa3967ff4 disk-io.c --- a/disk-io.c Mon Mar 24 01:03:20 2008 +0000 +++ b/disk-io.c Mon Mar 24 12:31:37 2008 +0000 @@ -18,12 +18,12 @@ #include <linux/fs.h> #include <linux/blkdev.h> -#include <linux/crc32c.h> #include <linux/scatterlist.h> #include <linux/swap.h> #include <linux/radix-tree.h> #include <linux/writeback.h> #include <linux/buffer_head.h> // for block_sync_page +#include "crc32c.h" #include "ctree.h" #include "disk-io.h" #include "transaction.h" @@ -108,7 +108,7 @@ out: u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len) { - return crc32c(seed, data, len); + return btrfs_crc32c(seed, data, len); } void btrfs_csum_final(u32 crc, char *result) diff -r 5c0d66b6195b -r e8daa3967ff4 extent-tree.c --- a/extent-tree.c Mon Mar 24 01:03:20 2008 +0000 +++ b/extent-tree.c Mon Mar 24 12:31:37 2008 +0000 @@ -17,9 +17,9 @@ */ #include <linux/sched.h> -#include <linux/crc32c.h> #include <linux/pagemap.h> #include "hash.h" +#include "crc32c.h" #include "ctree.h" #include "disk-io.h" #include "print-tree.h" @@ -402,14 +402,14 @@ static u64 hash_extent_ref(u64 root_obje __le64 lenum; lenum = cpu_to_le64(root_objectid); - high_crc = crc32c(high_crc, &lenum, sizeof(lenum)); + high_crc = btrfs_crc32c(high_crc, &lenum, sizeof(lenum)); lenum = cpu_to_le64(ref_generation); - low_crc = crc32c(low_crc, &lenum, sizeof(lenum)); + low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum)); if (owner >= BTRFS_FIRST_FREE_OBJECTID) { lenum = cpu_to_le64(owner); - low_crc = crc32c(low_crc, &lenum, sizeof(lenum)); + low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum)); lenum = cpu_to_le64(owner_offset); - low_crc = crc32c(low_crc, &lenum, sizeof(lenum)); + low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum)); } return ((u64)high_crc << 32) | (u64)low_crc; } -- Miguel Sousa Filipe