Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
9888c340 DS |
2 | |
3 | #ifndef BTRFS_EXTENT_MAP_H | |
4 | #define BTRFS_EXTENT_MAP_H | |
a52d9a80 | 5 | |
602035d7 | 6 | #include <linux/compiler_types.h> |
c27b1dbb | 7 | #include <linux/spinlock_types.h> |
a52d9a80 | 8 | #include <linux/rbtree.h> |
602035d7 | 9 | #include <linux/list.h> |
490b54d6 | 10 | #include <linux/refcount.h> |
22b46bdc | 11 | #include "misc.h" |
f86f7a75 | 12 | #include "compression.h" |
a52d9a80 | 13 | |
602035d7 DS |
14 | struct btrfs_inode; |
15 | struct btrfs_fs_info; | |
16 | ||
e248e04e DG |
17 | #define EXTENT_MAP_LAST_BYTE ((u64)-4) |
18 | #define EXTENT_MAP_HOLE ((u64)-3) | |
19 | #define EXTENT_MAP_INLINE ((u64)-2) | |
a52d9a80 | 20 | |
50b5b602 DS |
21 | /* bits for the extent_map::flags field */ |
22 | enum { | |
23 | /* this entry not yet on disk, don't free it */ | |
f86f7a75 FM |
24 | ENUM_BIT(EXTENT_FLAG_PINNED), |
25 | ENUM_BIT(EXTENT_FLAG_COMPRESS_ZLIB), | |
26 | ENUM_BIT(EXTENT_FLAG_COMPRESS_LZO), | |
27 | ENUM_BIT(EXTENT_FLAG_COMPRESS_ZSTD), | |
50b5b602 | 28 | /* pre-allocated extent */ |
f86f7a75 | 29 | ENUM_BIT(EXTENT_FLAG_PREALLOC), |
50b5b602 | 30 | /* Logging this extent */ |
f86f7a75 | 31 | ENUM_BIT(EXTENT_FLAG_LOGGING), |
199257a7 | 32 | /* This em is merged from two or more physically adjacent ems */ |
f86f7a75 | 33 | ENUM_BIT(EXTENT_FLAG_MERGED), |
50b5b602 | 34 | }; |
7f3c74fb | 35 | |
f86f7a75 | 36 | /* |
319d91ee QW |
37 | * This structure represents file extents and holes. |
38 | * | |
39 | * Unlike on-disk file extent items, extent maps can be merged to save memory. | |
40 | * This means members only match file extent items before any merging. | |
41 | * | |
f86f7a75 FM |
42 | * Keep this structure as compact as possible, as we can have really large |
43 | * amounts of allocated extent maps at any time. | |
44 | */ | |
a52d9a80 | 45 | struct extent_map { |
a52d9a80 | 46 | struct rb_node rb_node; |
d1310b2e | 47 | |
319d91ee QW |
48 | /* All of these are in bytes. */ |
49 | ||
50 | /* File offset matching the offset of a BTRFS_EXTENT_ITEM_KEY key. */ | |
d1310b2e | 51 | u64 start; |
319d91ee QW |
52 | |
53 | /* | |
54 | * Length of the file extent. | |
55 | * | |
56 | * For non-inlined file extents it's btrfs_file_extent_item::num_bytes. | |
57 | * For inline extents it's sectorsize, since inline data starts at | |
58 | * offsetof(struct btrfs_file_extent_item, disk_bytenr) thus | |
59 | * btrfs_file_extent_item::num_bytes is not valid. | |
60 | */ | |
d1310b2e | 61 | u64 len; |
319d91ee | 62 | |
3d2ac992 QW |
63 | /* |
64 | * The bytenr of the full on-disk extent. | |
65 | * | |
66 | * For regular extents it's btrfs_file_extent_item::disk_bytenr. | |
67 | * For holes it's EXTENT_MAP_HOLE and for inline extents it's | |
68 | * EXTENT_MAP_INLINE. | |
69 | */ | |
70 | u64 disk_bytenr; | |
71 | ||
319d91ee QW |
72 | /* |
73 | * The full on-disk extent length, matching | |
74 | * btrfs_file_extent_item::disk_num_bytes. | |
75 | */ | |
e8fe524d | 76 | u64 disk_num_bytes; |
319d91ee | 77 | |
3d2ac992 QW |
78 | /* |
79 | * Offset inside the decompressed extent. | |
80 | * | |
81 | * For regular extents it's btrfs_file_extent_item::offset. | |
82 | * For holes and inline extents it's 0. | |
83 | */ | |
84 | u64 offset; | |
85 | ||
319d91ee QW |
86 | /* |
87 | * The decompressed size of the whole on-disk extent, matching | |
88 | * btrfs_file_extent_item::ram_bytes. | |
89 | */ | |
cc95bef6 | 90 | u64 ram_bytes; |
319d91ee | 91 | |
199257a7 QW |
92 | /* |
93 | * Generation of the extent map, for merged em it's the highest | |
94 | * generation of all merged ems. | |
95 | * For non-merged extents, it's from btrfs_file_extent_item::generation. | |
96 | */ | |
5dc562c5 | 97 | u64 generation; |
f86f7a75 | 98 | u32 flags; |
490b54d6 | 99 | refcount_t refs; |
5dc562c5 | 100 | struct list_head list; |
a52d9a80 CM |
101 | }; |
102 | ||
d1310b2e | 103 | struct extent_map_tree { |
4e660ca3 | 104 | struct rb_root root; |
5dc562c5 | 105 | struct list_head modified_extents; |
890871be | 106 | rwlock_t lock; |
a52d9a80 CM |
107 | }; |
108 | ||
4c0c8cfc FM |
109 | struct btrfs_inode; |
110 | ||
f86f7a75 FM |
111 | static inline void extent_map_set_compression(struct extent_map *em, |
112 | enum btrfs_compression_type type) | |
113 | { | |
114 | if (type == BTRFS_COMPRESS_ZLIB) | |
115 | em->flags |= EXTENT_FLAG_COMPRESS_ZLIB; | |
116 | else if (type == BTRFS_COMPRESS_LZO) | |
117 | em->flags |= EXTENT_FLAG_COMPRESS_LZO; | |
118 | else if (type == BTRFS_COMPRESS_ZSTD) | |
119 | em->flags |= EXTENT_FLAG_COMPRESS_ZSTD; | |
120 | } | |
121 | ||
122 | static inline enum btrfs_compression_type extent_map_compression(const struct extent_map *em) | |
123 | { | |
124 | if (em->flags & EXTENT_FLAG_COMPRESS_ZLIB) | |
125 | return BTRFS_COMPRESS_ZLIB; | |
126 | ||
127 | if (em->flags & EXTENT_FLAG_COMPRESS_LZO) | |
128 | return BTRFS_COMPRESS_LZO; | |
129 | ||
130 | if (em->flags & EXTENT_FLAG_COMPRESS_ZSTD) | |
131 | return BTRFS_COMPRESS_ZSTD; | |
132 | ||
133 | return BTRFS_COMPRESS_NONE; | |
134 | } | |
135 | ||
136 | /* | |
137 | * More efficient way to determine if extent is compressed, instead of using | |
138 | * 'extent_map_compression() != BTRFS_COMPRESS_NONE'. | |
139 | */ | |
140 | static inline bool extent_map_is_compressed(const struct extent_map *em) | |
141 | { | |
142 | return (em->flags & (EXTENT_FLAG_COMPRESS_ZLIB | | |
143 | EXTENT_FLAG_COMPRESS_LZO | | |
144 | EXTENT_FLAG_COMPRESS_ZSTD)) != 0; | |
145 | } | |
146 | ||
cbc0e928 FM |
147 | static inline int extent_map_in_tree(const struct extent_map *em) |
148 | { | |
149 | return !RB_EMPTY_NODE(&em->rb_node); | |
150 | } | |
151 | ||
c77a8c61 QW |
152 | static inline u64 extent_map_block_start(const struct extent_map *em) |
153 | { | |
154 | if (em->disk_bytenr < EXTENT_MAP_LAST_BYTE) { | |
155 | if (extent_map_is_compressed(em)) | |
156 | return em->disk_bytenr; | |
157 | return em->disk_bytenr + em->offset; | |
158 | } | |
159 | return em->disk_bytenr; | |
160 | } | |
161 | ||
b144cc04 | 162 | static inline u64 extent_map_end(const struct extent_map *em) |
d1310b2e CM |
163 | { |
164 | if (em->start + em->len < em->start) | |
165 | return (u64)-1; | |
166 | return em->start + em->len; | |
167 | } | |
168 | ||
a8067e02 | 169 | void extent_map_tree_init(struct extent_map_tree *tree); |
a52d9a80 | 170 | struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, |
d1310b2e | 171 | u64 start, u64 len); |
c2fbd812 | 172 | void remove_extent_mapping(struct btrfs_inode *inode, struct extent_map *em); |
f000bc6f CH |
173 | int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre, |
174 | u64 new_logical); | |
d1310b2e | 175 | |
172ddd60 | 176 | struct extent_map *alloc_extent_map(void); |
a52d9a80 | 177 | void free_extent_map(struct extent_map *em); |
2f4cbe64 | 178 | int __init extent_map_init(void); |
e67c718b | 179 | void __cold extent_map_exit(void); |
00deaf04 | 180 | int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen); |
002f3a2c | 181 | void clear_em_logging(struct btrfs_inode *inode, struct extent_map *em); |
b917b7c3 CM |
182 | struct extent_map *search_extent_mapping(struct extent_map_tree *tree, |
183 | u64 start, u64 len); | |
0a308f80 | 184 | int btrfs_add_extent_mapping(struct btrfs_inode *inode, |
c04e61b5 | 185 | struct extent_map **em_in, u64 start, u64 len); |
4c0c8cfc FM |
186 | void btrfs_drop_extent_map_range(struct btrfs_inode *inode, |
187 | u64 start, u64 end, | |
188 | bool skip_pinned); | |
a1ba4c08 FM |
189 | int btrfs_replace_extent_map_range(struct btrfs_inode *inode, |
190 | struct extent_map *new_em, | |
191 | bool modified); | |
956a17d9 | 192 | long btrfs_free_extent_maps(struct btrfs_fs_info *fs_info, long nr_to_scan); |
9888c340 | 193 | |
a52d9a80 | 194 | #endif |