• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * There are 2 variants defined, one with a token pointer and one without.
38  */
39 
40 #define DEFINE_BTRFS_SETGET_BITS(bits)					\
41 u##bits btrfs_get_token_##bits(const struct extent_buffer *eb,		\
42 			       const void *ptr, unsigned long off,	\
43 			       struct btrfs_map_token *token)		\
44 {									\
45 	unsigned long part_offset = (unsigned long)ptr;			\
46 	unsigned long offset = part_offset + off;			\
47 	void *p;							\
48 	int err;							\
49 	char *kaddr;							\
50 	unsigned long map_start;					\
51 	unsigned long map_len;						\
52 	int size = sizeof(u##bits);					\
53 	u##bits res;							\
54 									\
55 	ASSERT(token);							\
56 	ASSERT(token->eb == eb);					\
57 									\
58 	if (token->kaddr && token->offset <= offset &&			\
59 	   (token->offset + PAGE_SIZE >= offset + size)) {	\
60 		kaddr = token->kaddr;					\
61 		p = kaddr + part_offset - token->offset;		\
62 		res = get_unaligned_le##bits(p + off);			\
63 		return res;						\
64 	}								\
65 	err = map_private_extent_buffer(eb, offset, size,		\
66 					&kaddr, &map_start, &map_len);	\
67 	if (err) {							\
68 		__le##bits leres;					\
69 									\
70 		read_extent_buffer(eb, &leres, offset, size);		\
71 		return le##bits##_to_cpu(leres);			\
72 	}								\
73 	p = kaddr + part_offset - map_start;				\
74 	res = get_unaligned_le##bits(p + off);				\
75 	token->kaddr = kaddr;						\
76 	token->offset = map_start;					\
77 	return res;							\
78 }									\
79 u##bits btrfs_get_##bits(const struct extent_buffer *eb,		\
80 			 const void *ptr, unsigned long off)		\
81 {									\
82 	unsigned long part_offset = (unsigned long)ptr;			\
83 	unsigned long offset = part_offset + off;			\
84 	void *p;							\
85 	int err;							\
86 	char *kaddr;							\
87 	unsigned long map_start;					\
88 	unsigned long map_len;						\
89 	int size = sizeof(u##bits);					\
90 	u##bits res;							\
91 									\
92 	err = map_private_extent_buffer(eb, offset, size,		\
93 					&kaddr, &map_start, &map_len);	\
94 	if (err) {							\
95 		__le##bits leres;					\
96 									\
97 		read_extent_buffer(eb, &leres, offset, size);		\
98 		return le##bits##_to_cpu(leres);			\
99 	}								\
100 	p = kaddr + part_offset - map_start;				\
101 	res = get_unaligned_le##bits(p + off);				\
102 	return res;							\
103 }									\
104 void btrfs_set_token_##bits(struct extent_buffer *eb,			\
105 			    const void *ptr, unsigned long off,		\
106 			    u##bits val,				\
107 			    struct btrfs_map_token *token)		\
108 {									\
109 	unsigned long part_offset = (unsigned long)ptr;			\
110 	unsigned long offset = part_offset + off;			\
111 	void *p;							\
112 	int err;							\
113 	char *kaddr;							\
114 	unsigned long map_start;					\
115 	unsigned long map_len;						\
116 	int size = sizeof(u##bits);					\
117 									\
118 	ASSERT(token);							\
119 	ASSERT(token->eb == eb);					\
120 									\
121 	if (token->kaddr && token->offset <= offset &&			\
122 	   (token->offset + PAGE_SIZE >= offset + size)) {	\
123 		kaddr = token->kaddr;					\
124 		p = kaddr + part_offset - token->offset;		\
125 		put_unaligned_le##bits(val, p + off);			\
126 		return;							\
127 	}								\
128 	err = map_private_extent_buffer(eb, offset, size,		\
129 			&kaddr, &map_start, &map_len);			\
130 	if (err) {							\
131 		__le##bits val2;					\
132 									\
133 		val2 = cpu_to_le##bits(val);				\
134 		write_extent_buffer(eb, &val2, offset, size);		\
135 		return;							\
136 	}								\
137 	p = kaddr + part_offset - map_start;				\
138 	put_unaligned_le##bits(val, p + off);				\
139 	token->kaddr = kaddr;						\
140 	token->offset = map_start;					\
141 }									\
142 void btrfs_set_##bits(struct extent_buffer *eb, void *ptr,		\
143 		      unsigned long off, u##bits val)			\
144 {									\
145 	unsigned long part_offset = (unsigned long)ptr;			\
146 	unsigned long offset = part_offset + off;			\
147 	void *p;							\
148 	int err;							\
149 	char *kaddr;							\
150 	unsigned long map_start;					\
151 	unsigned long map_len;						\
152 	int size = sizeof(u##bits);					\
153 									\
154 	err = map_private_extent_buffer(eb, offset, size,		\
155 			&kaddr, &map_start, &map_len);			\
156 	if (err) {							\
157 		__le##bits val2;					\
158 									\
159 		val2 = cpu_to_le##bits(val);				\
160 		write_extent_buffer(eb, &val2, offset, size);		\
161 		return;							\
162 	}								\
163 	p = kaddr + part_offset - map_start;				\
164 	put_unaligned_le##bits(val, p + off);				\
165 }
166 
167 DEFINE_BTRFS_SETGET_BITS(8)
168 DEFINE_BTRFS_SETGET_BITS(16)
169 DEFINE_BTRFS_SETGET_BITS(32)
170 DEFINE_BTRFS_SETGET_BITS(64)
171 
btrfs_node_key(const struct extent_buffer * eb,struct btrfs_disk_key * disk_key,int nr)172 void btrfs_node_key(const struct extent_buffer *eb,
173 		    struct btrfs_disk_key *disk_key, int nr)
174 {
175 	unsigned long ptr = btrfs_node_key_ptr_offset(nr);
176 	read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
177 		       struct btrfs_key_ptr, key, disk_key);
178 }
179