@@ -1406,11 +1406,29 @@ struct btrfs_ioctl_defrag_range_args {
offsetof(type, member), \
sizeof(((type *)0)->member)))
-#ifndef BTRFS_SETGET_FUNCS
+#define DECLARE_BTRFS_SETGET_BITS(bits) \
+u##bits btrfs_get_u##bits(struct extent_buffer *eb, void *ptr, \
+ unsigned long off); \
+void btrfs_set_u##bits(struct extent_buffer *eb, void *ptr, \
+ unsigned long off, u##bits val)
+
+DECLARE_BTRFS_SETGET_BITS(8);
+DECLARE_BTRFS_SETGET_BITS(16);
+DECLARE_BTRFS_SETGET_BITS(32);
+DECLARE_BTRFS_SETGET_BITS(64);
+
#define BTRFS_SETGET_FUNCS(name, type, member, bits) \
-u##bits btrfs_##name(struct extent_buffer *eb, type *s); \
-void btrfs_set_##name(struct extent_buffer *eb, type *s, u##bits val);
-#endif
+static inline u##bits btrfs_##name(struct extent_buffer *eb, type *s) \
+{ \
+ BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0)->member)); \
+ return btrfs_get_u##bits(eb, s, offsetof(type, member)); \
+} \
+static inline void btrfs_set_##name(struct extent_buffer *eb, type *s, \
+ u##bits val) \
+{ \
+ BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \
+ btrfs_set_u##bits(eb, s, offsetof(type, member), val); \
+}
#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \
static inline u##bits btrfs_##name(struct extent_buffer *eb) \
@@ -17,80 +17,84 @@
*/
#include <linux/highmem.h>
+#include <asm/unaligned.h>
-/* this is some deeply nasty code. ctree.h has a different
- * definition for this BTRFS_SETGET_FUNCS macro, behind a #ifndef
- *
- * The end result is that anyone who #includes ctree.h gets a
- * declaration for the btrfs_set_foo functions and btrfs_foo functions
- *
- * This file declares the macros and then #includes ctree.h, which results
- * in cpp creating the function here based on the template below.
- *
+#include "ctree.h"
+
+/*
* These setget functions do all the extent_buffer related mapping
* required to efficiently read and write specific fields in the extent
* buffers. Every pointer to metadata items in btrfs is really just
* an unsigned long offset into the extent buffer which has been
* cast to a specific type. This gives us all the gcc type checking.
*
- * The extent buffer api is used to do all the kmapping and page
- * spanning work required to get extent buffers in highmem and have
- * a metadata blocksize different from the page size.
+ * The extent buffer api is used to do the page spanning work required
+ * to have a metadata blocksize different from the page size.
*
* The macro starts with a simple function prototype declaration so that
* sparse won't complain about it being static.
*/
-#define BTRFS_SETGET_FUNCS(name, type, member, bits) \
-u##bits btrfs_##name(struct extent_buffer *eb, type *s); \
-void btrfs_set_##name(struct extent_buffer *eb, type *s, u##bits val); \
-u##bits btrfs_##name(struct extent_buffer *eb, \
- type *s) \
+#define DEFINE_BTRFS_SETGET_BITS(bits) \
+u##bits btrfs_get_u##bits(struct extent_buffer *eb, void *ptr, \
+ unsigned long off); \
+void btrfs_set_u##bits(struct extent_buffer *eb, void *ptr, \
+ unsigned long off, u##bits val); \
+u##bits btrfs_get_u##bits(struct extent_buffer *eb, void *ptr, \
+ unsigned long off) \
{ \
- unsigned long part_offset = (unsigned long)s; \
- unsigned long offset = part_offset + offsetof(type, member); \
- type *p; \
- int err; \
- char *kaddr; \
- unsigned long map_start; \
- unsigned long map_len; \
- u##bits res; \
- err = map_private_extent_buffer(eb, offset, \
- sizeof(((type *)0)->member), \
- &kaddr, &map_start, &map_len); \
- if (err) { \
- __le##bits leres; \
- read_eb_member(eb, s, type, member, &leres); \
- return le##bits##_to_cpu(leres); \
- } \
- p = (type *)(kaddr + part_offset - map_start); \
- res = le##bits##_to_cpu(p->member); \
- return res; \
+ unsigned long part_offset = (unsigned long)ptr; \
+ unsigned long offset = part_offset + off; \
+ void *p; \
+ int err; \
+ char *kaddr; \
+ unsigned long map_start; \
+ unsigned long map_len; \
+ u##bits res; \
+ int size = sizeof(u##bits); \
+ \
+ err = map_private_extent_buffer(eb, offset, size, \
+ &kaddr, &map_start, &map_len); \
+ if (err) { \
+ __le##bits leres; \
+ \
+ read_extent_buffer(eb, &leres, offset, size); \
+ return le##bits##_to_cpu(leres); \
+ } \
+ \
+ p = kaddr + part_offset - map_start; \
+ res = get_unaligned((u##bits *)(p + off)); \
+ return res; \
} \
-void btrfs_set_##name(struct extent_buffer *eb, \
- type *s, u##bits val) \
+void btrfs_set_u##bits(struct extent_buffer *eb, void *ptr, \
+ unsigned long off, u##bits val) \
{ \
- unsigned long part_offset = (unsigned long)s; \
- unsigned long offset = part_offset + offsetof(type, member); \
- type *p; \
- int err; \
- char *kaddr; \
- unsigned long map_start; \
- unsigned long map_len; \
- err = map_private_extent_buffer(eb, offset, \
- sizeof(((type *)0)->member), \
- &kaddr, &map_start, &map_len); \
- if (err) { \
- __le##bits val2; \
- val2 = cpu_to_le##bits(val); \
- write_eb_member(eb, s, type, member, &val2); \
- return; \
- } \
- p = (type *)(kaddr + part_offset - map_start); \
- p->member = cpu_to_le##bits(val); \
+ unsigned long part_offset = (unsigned long)ptr; \
+ unsigned long offset = part_offset + off; \
+ void *p; \
+ int err; \
+ char *kaddr; \
+ unsigned long map_start; \
+ unsigned long map_len; \
+ int size = sizeof(u##bits); \
+ \
+ err = map_private_extent_buffer(eb, offset, size, \
+ &kaddr, &map_start, &map_len); \
+ if (err) { \
+ __le##bits val2; \
+ \
+ val2 = cpu_to_le##bits(val); \
+ write_extent_buffer(eb, &val2, offset, size); \
+ } else { \
+ p = kaddr + part_offset - map_start; \
+ put_unaligned(val, (u##bits *)(p + off)); \
+ } \
}
-#include "ctree.h"
+DEFINE_BTRFS_SETGET_BITS(8);
+DEFINE_BTRFS_SETGET_BITS(16);
+DEFINE_BTRFS_SETGET_BITS(32);
+DEFINE_BTRFS_SETGET_BITS(64);
void btrfs_node_key(struct extent_buffer *eb,
struct btrfs_disk_key *disk_key, int nr)
BTRFS_SETGET_FUNCS macro is used to generate btrfs_set_foo() and btrfs_foo() functions, which read and write specific fields in the extent buffer. The total number of set/get functions is ~200, but in fact we only need 8 functions: 2 for u8 field, 2 for u16, 2 for u32 and 2 for u64. It results in redunction of ~22K bytes. text data bss dec hex filename 528069 4328 1060 533457 823d1 fs/btrfs/btrfs.o.orig 505997 4328 1060 511385 7cd99 fs/btrfs/btrfs.o Compared btrfs_set_bits() with btrfs_set_foo(), the extra runtime overhead is we have to pass one more argument. Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> --- fs/btrfs/ctree.h | 26 +++++++++-- fs/btrfs/struct-funcs.c | 118 ++++++++++++++++++++++++----------------------- 2 files changed, 83 insertions(+), 61 deletions(-)