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:
parent
0c6513b1d1
commit
8871a0eaa9
14
ctree.h
14
ctree.h
|
@ -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) \
|
||||||
|
|
12
dir-item.c
12
dir-item.c
|
@ -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);
|
||||||
|
|
|
@ -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
11
hash.c
|
@ -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
2
hash.h
|
@ -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
|
||||||
|
|
3
hasher.c
3
hasher.c
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue