Unaligned access fixes

The first problem is that these SETGET macros lose typing information,
and therefore can't see the 'packed' attribute and therefore take
unaligned access SIGBUS signals on sparc64 when trying to derefernce
the member.

The next problem is a similar issue in btrfs_name_hash().  This gets
passed things like &key.offset which is a member of a packed
structure, losing this packed'ness information btrfs_name_hash()
performs a potentially unaligned memory access, again resulting in a
SIGBUS.
This commit is contained in:
David Miller 2008-02-15 11:19:58 -05:00 committed by David Woodhouse
parent 0c6513b1d1
commit 8871a0eaa9
6 changed files with 20 additions and 26 deletions

14
ctree.h
View File

@ -451,18 +451,16 @@ static inline void btrfs_set_##name(struct extent_buffer *eb, \
static inline u##bits btrfs_##name(struct extent_buffer *eb, \ static inline u##bits btrfs_##name(struct extent_buffer *eb, \
type *s) \ type *s) \
{ \ { \
unsigned long offset = (unsigned long)s + \ unsigned long offset = (unsigned long)s; \
offsetof(type, member); \ type *p = (type *) (eb->data + offset); \
__le##bits *tmp = (__le##bits *)(eb->data + offset); \ return le##bits##_to_cpu(p->member); \
return le##bits##_to_cpu(*tmp); \
} \ } \
static inline void btrfs_set_##name(struct extent_buffer *eb, \ static inline void btrfs_set_##name(struct extent_buffer *eb, \
type *s, u##bits val) \ type *s, u##bits val) \
{ \ { \
unsigned long offset = (unsigned long)s + \ unsigned long offset = (unsigned long)s; \
offsetof(type, member); \ type *p = (type *) (eb->data + offset); \
__le##bits *tmp = (__le##bits *)(eb->data + offset); \ p->member = cpu_to_le##bits(val); \
*tmp = cpu_to_le##bits(val); \
} }
#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \ #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \

View File

@ -71,8 +71,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
key.objectid = dir; key.objectid = dir;
btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
ret = btrfs_name_hash(name, name_len, &key.offset); key.offset = btrfs_name_hash(name, name_len);
BUG_ON(ret);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
@ -122,8 +121,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root
key.objectid = dir; key.objectid = dir;
btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
ret = btrfs_name_hash(name, name_len, &key.offset); key.offset = btrfs_name_hash(name, name_len);
BUG_ON(ret);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
data_size = sizeof(*dir_item) + name_len; data_size = sizeof(*dir_item) + name_len;
dir_item = insert_with_overflow(trans, root, path, &key, data_size, dir_item = insert_with_overflow(trans, root, path, &key, data_size,
@ -196,8 +194,7 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
key.objectid = dir; key.objectid = dir;
btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
ret = btrfs_name_hash(name, name_len, &key.offset); key.offset = btrfs_name_hash(name, name_len);
BUG_ON(ret);
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
if (ret < 0) if (ret < 0)
@ -258,8 +255,7 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans,
key.objectid = dir; key.objectid = dir;
btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
ret = btrfs_name_hash(name, name_len, &key.offset); key.offset = btrfs_name_hash(name, name_len);
BUG_ON(ret);
ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
if (ret < 0) if (ret < 0)
return ERR_PTR(ret); return ERR_PTR(ret);

View File

@ -129,8 +129,8 @@ error:
struct btrfs_dir_item); struct btrfs_dir_item);
found = (char *)(di + 1); found = (char *)(di + 1);
found_len = btrfs_dir_name_len(di); found_len = btrfs_dir_name_len(di);
btrfs_name_hash(buf, strlen(buf), &myhash); myhash = btrfs_name_hash(buf, strlen(buf));
btrfs_name_hash(found, found_len, &foundhash); foundhash = btrfs_name_hash(found, found_len);
if (myhash != foundhash) if (myhash != foundhash)
goto fatal_release; goto fatal_release;
btrfs_release_path(root, &path); btrfs_release_path(root, &path);

11
hash.c
View File

@ -75,12 +75,13 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
*buf++ = pad; *buf++ = pad;
} }
int btrfs_name_hash(const char *name, int len, u64 *hash_result) u64 btrfs_name_hash(const char *name, int len)
{ {
__u32 hash; __u32 hash;
__u32 minor_hash = 0; __u32 minor_hash = 0;
const char *p; const char *p;
__u32 in[8], buf[2]; __u32 in[8], buf[2];
u64 hash_result;
/* Initialize the default seed for the hash checksum functions */ /* Initialize the default seed for the hash checksum functions */
buf[0] = 0x67452301; buf[0] = 0x67452301;
@ -97,8 +98,8 @@ int btrfs_name_hash(const char *name, int len, u64 *hash_result)
} }
hash = buf[0]; hash = buf[0];
minor_hash = buf[1]; minor_hash = buf[1];
*hash_result = buf[0]; hash_result = buf[0];
*hash_result <<= 32; hash_result <<= 32;
*hash_result |= buf[1]; hash_result |= buf[1];
return 0; return hash_result;
} }

2
hash.h
View File

@ -18,5 +18,5 @@
#ifndef __HASH__ #ifndef __HASH__
#define __HASH__ #define __HASH__
int btrfs_name_hash(const char *name, int len, u64 *hash_result); u64 btrfs_name_hash(const char *name, int len);
#endif #endif

View File

@ -35,8 +35,7 @@ int main() {
continue; continue;
if (line[strlen(line)-1] == '\n') if (line[strlen(line)-1] == '\n')
line[strlen(line)-1] = '\0'; line[strlen(line)-1] = '\0';
ret = btrfs_name_hash(line, strlen(line), &result); result = btrfs_name_hash(line, strlen(line));
BUG_ON(ret);
printf("hash returns %llu\n", (unsigned long long)result); printf("hash returns %llu\n", (unsigned long long)result);
} }
return 0; return 0;