Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[sfrench/cifs-2.6.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
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
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 }