1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2007 Oracle.  All rights reserved.
4  */
5 
6 #include <asm/unaligned.h>
7 
8 #include "ctree.h"
9 
get_unaligned_le8(const void * p)10 static inline u8 get_unaligned_le8(const void *p)
11 {
12        return *(u8 *)p;
13 }
14 
put_unaligned_le8(u8 val,void * p)15 static inline void put_unaligned_le8(u8 val, void *p)
16 {
17        *(u8 *)p = val;
18 }
19 
20 /*
21  * this is some deeply nasty code.
22  *
23  * The end result is that anyone who #includes ctree.h gets a
24  * declaration for the btrfs_set_foo functions and btrfs_foo functions,
25  * which are wrappers of btrfs_set_token_#bits functions and
26  * btrfs_get_token_#bits functions, which are defined in this file.
27  *
28  * These setget functions do all the extent_buffer related mapping
29  * required to efficiently read and write specific fields in the extent
30  * buffers.  Every pointer to metadata items in btrfs is really just
31  * an unsigned long offset into the extent buffer which has been
32  * cast to a specific type.  This gives us all the gcc type checking.
33  *
34  * The extent buffer api is used to do the page spanning work required to
35  * have a metadata blocksize different from the page size.
36  */
37 
38 #define DEFINE_BTRFS_SETGET_BITS(bits)					\
39 u##bits btrfs_get_token_##bits(const struct extent_buffer *eb,		\
40 			       const void *ptr, unsigned long off,	\
41 			       struct btrfs_map_token *token)		\
42 {									\
43 	unsigned long part_offset = (unsigned long)ptr;			\
44 	unsigned long offset = part_offset + off;			\
45 	void *p;							\
46 	int err;							\
47 	char *kaddr;							\
48 	unsigned long map_start;					\
49 	unsigned long map_len;						\
50 	int size = sizeof(u##bits);					\
51 	u##bits res;							\
52 									\
53 	if (token && token->kaddr && token->offset <= offset &&		\
54 	    token->eb == eb &&						\
55 	   (token->offset + PAGE_SIZE >= offset + size)) {	\
56 		kaddr = token->kaddr;					\
57 		p = kaddr + part_offset - token->offset;		\
58 		res = get_unaligned_le##bits(p + off);			\
59 		return res;						\
60 	}								\
61 	err = map_private_extent_buffer(eb, offset, size,		\
62 					&kaddr, &map_start, &map_len);	\
63 	if (err) {							\
64 		__le##bits leres;					\
65 									\
66 		read_extent_buffer(eb, &leres, offset, size);		\
67 		return le##bits##_to_cpu(leres);			\
68 	}								\
69 	p = kaddr + part_offset - map_start;				\
70 	res = get_unaligned_le##bits(p + off);				\
71 	if (token) {							\
72 		token->kaddr = kaddr;					\
73 		token->offset = map_start;				\
74 		token->eb = eb;						\
75 	}								\
76 	return res;							\
77 }									\
78 void btrfs_set_token_##bits(struct extent_buffer *eb,			\
79 			    const void *ptr, unsigned long off,		\
80 			    u##bits val,				\
81 			    struct btrfs_map_token *token)		\
82 {									\
83 	unsigned long part_offset = (unsigned long)ptr;			\
84 	unsigned long offset = part_offset + off;			\
85 	void *p;							\
86 	int err;							\
87 	char *kaddr;							\
88 	unsigned long map_start;					\
89 	unsigned long map_len;						\
90 	int size = sizeof(u##bits);					\
91 									\
92 	if (token && token->kaddr && token->offset <= offset &&		\
93 	    token->eb == eb &&						\
94 	   (token->offset + PAGE_SIZE >= offset + size)) {	\
95 		kaddr = token->kaddr;					\
96 		p = kaddr + part_offset - token->offset;		\
97 		put_unaligned_le##bits(val, p + off);			\
98 		return;							\
99 	}								\
100 	err = map_private_extent_buffer(eb, offset, size,		\
101 			&kaddr, &map_start, &map_len);			\
102 	if (err) {							\
103 		__le##bits val2;					\
104 									\
105 		val2 = cpu_to_le##bits(val);				\
106 		write_extent_buffer(eb, &val2, offset, size);		\
107 		return;							\
108 	}								\
109 	p = kaddr + part_offset - map_start;				\
110 	put_unaligned_le##bits(val, p + off);				\
111 	if (token) {							\
112 		token->kaddr = kaddr;					\
113 		token->offset = map_start;				\
114 		token->eb = eb;						\
115 	}								\
116 }
117 
118 DEFINE_BTRFS_SETGET_BITS(8)
119 DEFINE_BTRFS_SETGET_BITS(16)
120 DEFINE_BTRFS_SETGET_BITS(32)
121 DEFINE_BTRFS_SETGET_BITS(64)
122 
btrfs_node_key(const struct extent_buffer * eb,struct btrfs_disk_key * disk_key,int nr)123 void btrfs_node_key(const struct extent_buffer *eb,
124 		    struct btrfs_disk_key *disk_key, int nr)
125 {
126 	unsigned long ptr = btrfs_node_key_ptr_offset(nr);
127 	read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
128 		       struct btrfs_key_ptr, key, disk_key);
129 }
130