1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | |
3 | #ifndef BTRFS_EXTENT_MAP_H |
4 | #define BTRFS_EXTENT_MAP_H |
5 | |
6 | #include <linux/compiler_types.h> |
7 | #include <linux/rwlock_types.h> |
8 | #include <linux/rbtree.h> |
9 | #include <linux/list.h> |
10 | #include <linux/refcount.h> |
11 | #include "misc.h" |
12 | #include "extent_map.h" |
13 | #include "compression.h" |
14 | |
15 | struct btrfs_inode; |
16 | struct btrfs_fs_info; |
17 | |
18 | #define EXTENT_MAP_LAST_BYTE ((u64)-4) |
19 | #define EXTENT_MAP_HOLE ((u64)-3) |
20 | #define EXTENT_MAP_INLINE ((u64)-2) |
21 | |
22 | /* bits for the extent_map::flags field */ |
23 | enum { |
24 | /* this entry not yet on disk, don't free it */ |
25 | ENUM_BIT(EXTENT_FLAG_PINNED), |
26 | ENUM_BIT(EXTENT_FLAG_COMPRESS_ZLIB), |
27 | ENUM_BIT(EXTENT_FLAG_COMPRESS_LZO), |
28 | ENUM_BIT(EXTENT_FLAG_COMPRESS_ZSTD), |
29 | /* pre-allocated extent */ |
30 | ENUM_BIT(EXTENT_FLAG_PREALLOC), |
31 | /* Logging this extent */ |
32 | ENUM_BIT(EXTENT_FLAG_LOGGING), |
33 | /* Filling in a preallocated extent */ |
34 | ENUM_BIT(EXTENT_FLAG_FILLING), |
35 | /* This em is merged from two or more physically adjacent ems */ |
36 | ENUM_BIT(EXTENT_FLAG_MERGED), |
37 | }; |
38 | |
39 | /* |
40 | * Keep this structure as compact as possible, as we can have really large |
41 | * amounts of allocated extent maps at any time. |
42 | */ |
43 | struct extent_map { |
44 | struct rb_node rb_node; |
45 | |
46 | /* all of these are in bytes */ |
47 | u64 start; |
48 | u64 len; |
49 | u64 mod_start; |
50 | u64 mod_len; |
51 | u64 orig_start; |
52 | u64 orig_block_len; |
53 | u64 ram_bytes; |
54 | u64 block_start; |
55 | u64 block_len; |
56 | |
57 | /* |
58 | * Generation of the extent map, for merged em it's the highest |
59 | * generation of all merged ems. |
60 | * For non-merged extents, it's from btrfs_file_extent_item::generation. |
61 | */ |
62 | u64 generation; |
63 | u32 flags; |
64 | refcount_t refs; |
65 | struct list_head list; |
66 | }; |
67 | |
68 | struct extent_map_tree { |
69 | struct rb_root_cached map; |
70 | struct list_head modified_extents; |
71 | rwlock_t lock; |
72 | }; |
73 | |
74 | struct btrfs_inode; |
75 | |
76 | static inline void extent_map_set_compression(struct extent_map *em, |
77 | enum btrfs_compression_type type) |
78 | { |
79 | if (type == BTRFS_COMPRESS_ZLIB) |
80 | em->flags |= EXTENT_FLAG_COMPRESS_ZLIB; |
81 | else if (type == BTRFS_COMPRESS_LZO) |
82 | em->flags |= EXTENT_FLAG_COMPRESS_LZO; |
83 | else if (type == BTRFS_COMPRESS_ZSTD) |
84 | em->flags |= EXTENT_FLAG_COMPRESS_ZSTD; |
85 | } |
86 | |
87 | static inline enum btrfs_compression_type extent_map_compression(const struct extent_map *em) |
88 | { |
89 | if (em->flags & EXTENT_FLAG_COMPRESS_ZLIB) |
90 | return BTRFS_COMPRESS_ZLIB; |
91 | |
92 | if (em->flags & EXTENT_FLAG_COMPRESS_LZO) |
93 | return BTRFS_COMPRESS_LZO; |
94 | |
95 | if (em->flags & EXTENT_FLAG_COMPRESS_ZSTD) |
96 | return BTRFS_COMPRESS_ZSTD; |
97 | |
98 | return BTRFS_COMPRESS_NONE; |
99 | } |
100 | |
101 | /* |
102 | * More efficient way to determine if extent is compressed, instead of using |
103 | * 'extent_map_compression() != BTRFS_COMPRESS_NONE'. |
104 | */ |
105 | static inline bool extent_map_is_compressed(const struct extent_map *em) |
106 | { |
107 | return (em->flags & (EXTENT_FLAG_COMPRESS_ZLIB | |
108 | EXTENT_FLAG_COMPRESS_LZO | |
109 | EXTENT_FLAG_COMPRESS_ZSTD)) != 0; |
110 | } |
111 | |
112 | static inline int extent_map_in_tree(const struct extent_map *em) |
113 | { |
114 | return !RB_EMPTY_NODE(&em->rb_node); |
115 | } |
116 | |
117 | static inline u64 extent_map_end(const struct extent_map *em) |
118 | { |
119 | if (em->start + em->len < em->start) |
120 | return (u64)-1; |
121 | return em->start + em->len; |
122 | } |
123 | |
124 | void extent_map_tree_init(struct extent_map_tree *tree); |
125 | struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, |
126 | u64 start, u64 len); |
127 | void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em); |
128 | int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre, |
129 | u64 new_logical); |
130 | |
131 | struct extent_map *alloc_extent_map(void); |
132 | void free_extent_map(struct extent_map *em); |
133 | int __init extent_map_init(void); |
134 | void __cold extent_map_exit(void); |
135 | int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen); |
136 | void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em); |
137 | struct extent_map *search_extent_mapping(struct extent_map_tree *tree, |
138 | u64 start, u64 len); |
139 | int btrfs_add_extent_mapping(struct btrfs_fs_info *fs_info, |
140 | struct extent_map_tree *em_tree, |
141 | struct extent_map **em_in, u64 start, u64 len); |
142 | void btrfs_drop_extent_map_range(struct btrfs_inode *inode, |
143 | u64 start, u64 end, |
144 | bool skip_pinned); |
145 | int btrfs_replace_extent_map_range(struct btrfs_inode *inode, |
146 | struct extent_map *new_em, |
147 | bool modified); |
148 | |
149 | #endif |
150 | |