diff options
author | David Miller <davem@davemloft.net> | 2008-02-15 10:40:52 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:00 -0400 |
commit | df68b8a7ad4a18c9e63f1c12015a59c3b7031adb (patch) | |
tree | f2e6569b5f4843a01f23068fdfd3b450c8258459 | |
parent | 39b5637f6f195852259004bb27b58e2dcf9fb378 (diff) |
Btrfs: unaligned access fixes
Btrfs set/get macros lose type information needed to avoid
unaligned accesses on sparc64.
ere is a patch for the kernel bits which fixes most of the
unaligned accesses on sparc64.
btrfs_name_hash is modified to return the hash value instead
of getting a return location via a (potentially unaligned)
pointer.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.h | 17 | ||||
-rw-r--r-- | fs/btrfs/dir-item.c | 12 | ||||
-rw-r--r-- | fs/btrfs/hash.c | 17 | ||||
-rw-r--r-- | fs/btrfs/hash.h | 2 | ||||
-rw-r--r-- | fs/btrfs/struct-funcs.c | 30 |
5 files changed, 33 insertions, 45 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 52144b04f1af..086cb0525cd1 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -495,22 +495,17 @@ void btrfs_set_##name(struct extent_buffer *eb, type *s, u##bits val); | |||
495 | #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \ | 495 | #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \ |
496 | static inline u##bits btrfs_##name(struct extent_buffer *eb) \ | 496 | static inline u##bits btrfs_##name(struct extent_buffer *eb) \ |
497 | { \ | 497 | { \ |
498 | char *kaddr = kmap_atomic(eb->first_page, KM_USER0); \ | 498 | type *p = kmap_atomic(eb->first_page, KM_USER0); \ |
499 | unsigned long offset = offsetof(type, member); \ | 499 | u##bits res = le##bits##_to_cpu(p->member); \ |
500 | u##bits res; \ | 500 | kunmap_atomic(p, KM_USER0); \ |
501 | __le##bits *tmp = (__le##bits *)(kaddr + offset); \ | ||
502 | res = le##bits##_to_cpu(*tmp); \ | ||
503 | kunmap_atomic(kaddr, KM_USER0); \ | ||
504 | return res; \ | 501 | return res; \ |
505 | } \ | 502 | } \ |
506 | static inline void btrfs_set_##name(struct extent_buffer *eb, \ | 503 | static inline void btrfs_set_##name(struct extent_buffer *eb, \ |
507 | u##bits val) \ | 504 | u##bits val) \ |
508 | { \ | 505 | { \ |
509 | char *kaddr = kmap_atomic(eb->first_page, KM_USER0); \ | 506 | type *p = kmap_atomic(eb->first_page, KM_USER0); \ |
510 | unsigned long offset = offsetof(type, member); \ | 507 | p->member = cpu_to_le##bits(val); \ |
511 | __le##bits *tmp = (__le##bits *)(kaddr + offset); \ | 508 | kunmap_atomic(p, KM_USER0); \ |
512 | *tmp = cpu_to_le##bits(val); \ | ||
513 | kunmap_atomic(kaddr, KM_USER0); \ | ||
514 | } | 509 | } |
515 | 510 | ||
516 | #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \ | 511 | #define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \ |
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c index 5247a9a41f08..7a73dc59dc4d 100644 --- a/fs/btrfs/dir-item.c +++ b/fs/btrfs/dir-item.c | |||
@@ -71,8 +71,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, | |||
71 | 71 | ||
72 | key.objectid = dir; | 72 | key.objectid = dir; |
73 | btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); | 73 | btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); |
74 | ret = btrfs_name_hash(name, name_len, &key.offset); | 74 | key.offset = btrfs_name_hash(name, name_len); |
75 | BUG_ON(ret); | ||
76 | path = btrfs_alloc_path(); | 75 | path = btrfs_alloc_path(); |
77 | if (!path) | 76 | if (!path) |
78 | return -ENOMEM; | 77 | return -ENOMEM; |
@@ -125,8 +124,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root | |||
125 | 124 | ||
126 | key.objectid = dir; | 125 | key.objectid = dir; |
127 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); | 126 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); |
128 | ret = btrfs_name_hash(name, name_len, &key.offset); | 127 | key.offset = btrfs_name_hash(name, name_len); |
129 | BUG_ON(ret); | ||
130 | path = btrfs_alloc_path(); | 128 | path = btrfs_alloc_path(); |
131 | data_size = sizeof(*dir_item) + name_len; | 129 | data_size = sizeof(*dir_item) + name_len; |
132 | dir_item = insert_with_overflow(trans, root, path, &key, data_size, | 130 | dir_item = insert_with_overflow(trans, root, path, &key, data_size, |
@@ -199,8 +197,7 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, | |||
199 | key.objectid = dir; | 197 | key.objectid = dir; |
200 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); | 198 | btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY); |
201 | 199 | ||
202 | ret = btrfs_name_hash(name, name_len, &key.offset); | 200 | key.offset = btrfs_name_hash(name, name_len); |
203 | BUG_ON(ret); | ||
204 | 201 | ||
205 | ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); | 202 | ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); |
206 | if (ret < 0) | 203 | if (ret < 0) |
@@ -261,8 +258,7 @@ struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, | |||
261 | 258 | ||
262 | key.objectid = dir; | 259 | key.objectid = dir; |
263 | btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); | 260 | btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY); |
264 | ret = btrfs_name_hash(name, name_len, &key.offset); | 261 | key.offset = btrfs_name_hash(name, name_len); |
265 | BUG_ON(ret); | ||
266 | ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); | 262 | ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); |
267 | if (ret < 0) | 263 | if (ret < 0) |
268 | return ERR_PTR(ret); | 264 | return ERR_PTR(ret); |
diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c index e5c76903d722..d5252f5c9d01 100644 --- a/fs/btrfs/hash.c +++ b/fs/btrfs/hash.c | |||
@@ -76,19 +76,18 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) | |||
76 | *buf++ = pad; | 76 | *buf++ = pad; |
77 | } | 77 | } |
78 | 78 | ||
79 | int btrfs_name_hash(const char *name, int len, u64 *hash_result) | 79 | u64 btrfs_name_hash(const char *name, int len) |
80 | { | 80 | { |
81 | __u32 hash; | 81 | __u32 hash; |
82 | __u32 minor_hash = 0; | 82 | __u32 minor_hash = 0; |
83 | const char *p; | 83 | const char *p; |
84 | __u32 in[8], buf[2]; | 84 | __u32 in[8], buf[2]; |
85 | u64 hash_result; | ||
85 | 86 | ||
86 | if (len == 1 && *name == '.') { | 87 | if (len == 1 && *name == '.') { |
87 | *hash_result = 1; | 88 | return 1; |
88 | return 0; | ||
89 | } else if (len == 2 && name[0] == '.' && name[1] == '.') { | 89 | } else if (len == 2 && name[0] == '.' && name[1] == '.') { |
90 | *hash_result = 2; | 90 | return 2; |
91 | return 0; | ||
92 | } | 91 | } |
93 | 92 | ||
94 | /* Initialize the default seed for the hash checksum functions */ | 93 | /* Initialize the default seed for the hash checksum functions */ |
@@ -106,8 +105,8 @@ int btrfs_name_hash(const char *name, int len, u64 *hash_result) | |||
106 | } | 105 | } |
107 | hash = buf[0]; | 106 | hash = buf[0]; |
108 | minor_hash = buf[1]; | 107 | minor_hash = buf[1]; |
109 | *hash_result = buf[0]; | 108 | hash_result = buf[0]; |
110 | *hash_result <<= 32; | 109 | hash_result <<= 32; |
111 | *hash_result |= buf[1]; | 110 | hash_result |= buf[1]; |
112 | return 0; | 111 | return hash_result; |
113 | } | 112 | } |
diff --git a/fs/btrfs/hash.h b/fs/btrfs/hash.h index d3be02670585..868ee17ca77a 100644 --- a/fs/btrfs/hash.h +++ b/fs/btrfs/hash.h | |||
@@ -18,5 +18,5 @@ | |||
18 | 18 | ||
19 | #ifndef __HASH__ | 19 | #ifndef __HASH__ |
20 | #define __HASH__ | 20 | #define __HASH__ |
21 | int btrfs_name_hash(const char *name, int len, u64 *hash_result); | 21 | u64 btrfs_name_hash(const char *name, int len); |
22 | #endif | 22 | #endif |
diff --git a/fs/btrfs/struct-funcs.c b/fs/btrfs/struct-funcs.c index c5715a60554c..ad03a32d1116 100644 --- a/fs/btrfs/struct-funcs.c +++ b/fs/btrfs/struct-funcs.c | |||
@@ -21,16 +21,15 @@ | |||
21 | u##bits btrfs_##name(struct extent_buffer *eb, \ | 21 | u##bits btrfs_##name(struct extent_buffer *eb, \ |
22 | type *s) \ | 22 | type *s) \ |
23 | { \ | 23 | { \ |
24 | unsigned long offset = (unsigned long)s + \ | 24 | unsigned long part_offset = (unsigned long)s; \ |
25 | offsetof(type, member); \ | 25 | unsigned long offset = part_offset + offsetof(type, member); \ |
26 | __le##bits *tmp; \ | 26 | type *p; \ |
27 | /* ugly, but we want the fast path here */ \ | 27 | /* ugly, but we want the fast path here */ \ |
28 | if (eb->map_token && offset >= eb->map_start && \ | 28 | if (eb->map_token && offset >= eb->map_start && \ |
29 | offset + sizeof(((type *)0)->member) <= eb->map_start + \ | 29 | offset + sizeof(((type *)0)->member) <= eb->map_start + \ |
30 | eb->map_len) { \ | 30 | eb->map_len) { \ |
31 | tmp = (__le##bits *)(eb->kaddr + offset - \ | 31 | p = (type *)(eb->kaddr + part_offset - eb->map_start); \ |
32 | eb->map_start); \ | 32 | return le##bits##_to_cpu(p->member); \ |
33 | return le##bits##_to_cpu(*tmp); \ | ||
34 | } \ | 33 | } \ |
35 | { \ | 34 | { \ |
36 | int err; \ | 35 | int err; \ |
@@ -48,8 +47,8 @@ u##bits btrfs_##name(struct extent_buffer *eb, \ | |||
48 | read_eb_member(eb, s, type, member, &res); \ | 47 | read_eb_member(eb, s, type, member, &res); \ |
49 | return le##bits##_to_cpu(res); \ | 48 | return le##bits##_to_cpu(res); \ |
50 | } \ | 49 | } \ |
51 | tmp = (__le##bits *)(kaddr + offset - map_start); \ | 50 | p = (type *)(kaddr + part_offset - map_start); \ |
52 | res = le##bits##_to_cpu(*tmp); \ | 51 | res = le##bits##_to_cpu(p->member); \ |
53 | if (unmap_on_exit) \ | 52 | if (unmap_on_exit) \ |
54 | unmap_extent_buffer(eb, map_token, KM_USER1); \ | 53 | unmap_extent_buffer(eb, map_token, KM_USER1); \ |
55 | return res; \ | 54 | return res; \ |
@@ -58,16 +57,15 @@ u##bits btrfs_##name(struct extent_buffer *eb, \ | |||
58 | void btrfs_set_##name(struct extent_buffer *eb, \ | 57 | void btrfs_set_##name(struct extent_buffer *eb, \ |
59 | type *s, u##bits val) \ | 58 | type *s, u##bits val) \ |
60 | { \ | 59 | { \ |
61 | unsigned long offset = (unsigned long)s + \ | 60 | unsigned long part_offset = (unsigned long)s; \ |
62 | offsetof(type, member); \ | 61 | unsigned long offset = part_offset + offsetof(type, member); \ |
63 | __le##bits *tmp; \ | 62 | type *p; \ |
64 | /* ugly, but we want the fast path here */ \ | 63 | /* ugly, but we want the fast path here */ \ |
65 | if (eb->map_token && offset >= eb->map_start && \ | 64 | if (eb->map_token && offset >= eb->map_start && \ |
66 | offset + sizeof(((type *)0)->member) <= eb->map_start + \ | 65 | offset + sizeof(((type *)0)->member) <= eb->map_start + \ |
67 | eb->map_len) { \ | 66 | eb->map_len) { \ |
68 | tmp = (__le##bits *)(eb->kaddr + offset - \ | 67 | p = (type *)(eb->kaddr + part_offset - eb->map_start); \ |
69 | eb->map_start); \ | 68 | p->member = cpu_to_le##bits(val); \ |
70 | *tmp = cpu_to_le##bits(val); \ | ||
71 | return; \ | 69 | return; \ |
72 | } \ | 70 | } \ |
73 | { \ | 71 | { \ |
@@ -86,8 +84,8 @@ void btrfs_set_##name(struct extent_buffer *eb, \ | |||
86 | write_eb_member(eb, s, type, member, &val); \ | 84 | write_eb_member(eb, s, type, member, &val); \ |
87 | return; \ | 85 | return; \ |
88 | } \ | 86 | } \ |
89 | tmp = (__le##bits *)(kaddr + offset - map_start); \ | 87 | p = (type *)(kaddr + part_offset - map_start); \ |
90 | *tmp = cpu_to_le##bits(val); \ | 88 | p->member = cpu_to_le##bits(val); \ |
91 | if (unmap_on_exit) \ | 89 | if (unmap_on_exit) \ |
92 | unmap_extent_buffer(eb, map_token, KM_USER1); \ | 90 | unmap_extent_buffer(eb, map_token, KM_USER1); \ |
93 | } \ | 91 | } \ |