Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/fs/btrfs/accessors.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2007 Oracle. All rights reserved.
4
*/
5
6
#include <linux/unaligned.h>
7
#include "messages.h"
8
#include "extent_io.h"
9
#include "fs.h"
10
#include "accessors.h"
11
12
static void __cold report_setget_bounds(const struct extent_buffer *eb,
13
const void *ptr, unsigned off, int size)
14
{
15
unsigned long member_offset = (unsigned long)ptr + off;
16
17
btrfs_warn(eb->fs_info,
18
"bad eb member %s: ptr 0x%lx start %llu member offset %lu size %d",
19
(member_offset > eb->len ? "start" : "end"),
20
(unsigned long)ptr, eb->start, member_offset, size);
21
}
22
23
/* Copy bytes from @src1 and @src2 to @dest. */
24
static __always_inline void memcpy_split_src(char *dest, const char *src1,
25
const char *src2, const size_t len1,
26
const size_t total)
27
{
28
memcpy(dest, src1, len1);
29
memcpy(dest + len1, src2, total - len1);
30
}
31
32
/*
33
* Macro templates that define helpers to read/write extent buffer data of a
34
* given size, that are also used via ctree.h for access to item members by
35
* specialized helpers.
36
*
37
* Generic helpers:
38
* - btrfs_set_8 (for 8/16/32/64)
39
* - btrfs_get_8 (for 8/16/32/64)
40
*
41
* The set/get functions handle data spanning two pages transparently, in case
42
* metadata block size is larger than page. Every pointer to metadata items is
43
* an offset into the extent buffer page array, cast to a specific type. This
44
* gives us all the type checking.
45
*
46
* The extent buffer pages stored in the array folios may not form a contiguous
47
* phyusical range, but the API functions assume the linear offset to the range
48
* from 0 to metadata node size.
49
*/
50
51
#define DEFINE_BTRFS_SETGET_BITS(bits) \
52
u##bits btrfs_get_##bits(const struct extent_buffer *eb, \
53
const void *ptr, unsigned long off) \
54
{ \
55
const unsigned long member_offset = (unsigned long)ptr + off; \
56
const unsigned long idx = get_eb_folio_index(eb, member_offset);\
57
const unsigned long oif = get_eb_offset_in_folio(eb, \
58
member_offset);\
59
char *kaddr = folio_address(eb->folios[idx]) + oif; \
60
const int part = eb->folio_size - oif; \
61
u8 lebytes[sizeof(u##bits)]; \
62
\
63
if (unlikely(member_offset + sizeof(u##bits) > eb->len)) { \
64
report_setget_bounds(eb, ptr, off, sizeof(u##bits)); \
65
return 0; \
66
} \
67
if (INLINE_EXTENT_BUFFER_PAGES == 1 || sizeof(u##bits) == 1 || \
68
likely(sizeof(u##bits) <= part)) \
69
return get_unaligned_le##bits(kaddr); \
70
\
71
if (sizeof(u##bits) == 2) { \
72
lebytes[0] = *kaddr; \
73
kaddr = folio_address(eb->folios[idx + 1]); \
74
lebytes[1] = *kaddr; \
75
} else { \
76
memcpy_split_src(lebytes, kaddr, \
77
folio_address(eb->folios[idx + 1]), \
78
part, sizeof(u##bits)); \
79
} \
80
return get_unaligned_le##bits(lebytes); \
81
} \
82
void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr, \
83
unsigned long off, u##bits val) \
84
{ \
85
const unsigned long member_offset = (unsigned long)ptr + off; \
86
const unsigned long idx = get_eb_folio_index(eb, member_offset);\
87
const unsigned long oif = get_eb_offset_in_folio(eb, \
88
member_offset);\
89
char *kaddr = folio_address(eb->folios[idx]) + oif; \
90
const int part = eb->folio_size - oif; \
91
u8 lebytes[sizeof(u##bits)]; \
92
\
93
if (unlikely(member_offset + sizeof(u##bits) > eb->len)) { \
94
report_setget_bounds(eb, ptr, off, sizeof(u##bits)); \
95
return; \
96
} \
97
if (INLINE_EXTENT_BUFFER_PAGES == 1 || sizeof(u##bits) == 1 || \
98
likely(sizeof(u##bits) <= part)) { \
99
put_unaligned_le##bits(val, kaddr); \
100
return; \
101
} \
102
put_unaligned_le##bits(val, lebytes); \
103
if (sizeof(u##bits) == 2) { \
104
*kaddr = lebytes[0]; \
105
kaddr = folio_address(eb->folios[idx + 1]); \
106
*kaddr = lebytes[1]; \
107
} else { \
108
memcpy(kaddr, lebytes, part); \
109
kaddr = folio_address(eb->folios[idx + 1]); \
110
memcpy(kaddr, lebytes + part, sizeof(u##bits) - part); \
111
} \
112
}
113
114
DEFINE_BTRFS_SETGET_BITS(8)
115
DEFINE_BTRFS_SETGET_BITS(16)
116
DEFINE_BTRFS_SETGET_BITS(32)
117
DEFINE_BTRFS_SETGET_BITS(64)
118
119
void btrfs_node_key(const struct extent_buffer *eb,
120
struct btrfs_disk_key *disk_key, int nr)
121
{
122
unsigned long ptr = btrfs_node_key_ptr_offset(eb, nr);
123
read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
124
struct btrfs_key_ptr, key, disk_key);
125
}
126
127