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