mm/huge_memory.c: use head to emphasize the purpose of page
[linux-2.6-microblaze.git] / fs / btrfs / struct-funcs.c
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
10 static inline u8 get_unaligned_le8(const void *p)
11 {
12        return *(u8 *)p;
13 }
14
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
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 }