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