Commit | Line | Data |
---|---|---|
cac06d84 QW |
1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | ||
3 | #ifndef BTRFS_SUBPAGE_H | |
4 | #define BTRFS_SUBPAGE_H | |
5 | ||
6 | #include <linux/spinlock.h> | |
7 | ||
8481dd80 QW |
8 | /* |
9 | * Extra info for subpapge bitmap. | |
10 | * | |
11 | * For subpage we pack all uptodate/error/dirty/writeback/ordered bitmaps into | |
12 | * one larger bitmap. | |
13 | * | |
14 | * This structure records how they are organized in the bitmap: | |
15 | * | |
16 | * /- uptodate_offset /- error_offset /- dirty_offset | |
17 | * | | | | |
18 | * v v v | |
19 | * |u|u|u|u|........|u|u|e|e|.......|e|e| ... |o|o| | |
20 | * |<- bitmap_nr_bits ->| | |
21 | * |<--------------- total_nr_bits ---------------->| | |
22 | */ | |
23 | struct btrfs_subpage_info { | |
24 | /* Number of bits for each bitmap */ | |
25 | unsigned int bitmap_nr_bits; | |
26 | ||
27 | /* Total number of bits for the whole bitmap */ | |
28 | unsigned int total_nr_bits; | |
29 | ||
30 | /* | |
31 | * *_start indicates where the bitmap starts, the length is always | |
32 | * @bitmap_size, which is calculated from PAGE_SIZE / sectorsize. | |
33 | */ | |
34 | unsigned int uptodate_offset; | |
35 | unsigned int error_offset; | |
36 | unsigned int dirty_offset; | |
37 | unsigned int writeback_offset; | |
38 | unsigned int ordered_offset; | |
e4f94347 | 39 | unsigned int checked_offset; |
8481dd80 QW |
40 | }; |
41 | ||
cac06d84 QW |
42 | /* |
43 | * Structure to trace status of each sector inside a page, attached to | |
44 | * page::private for both data and metadata inodes. | |
45 | */ | |
46 | struct btrfs_subpage { | |
47 | /* Common members for both data and metadata pages */ | |
48 | spinlock_t lock; | |
3d078efa QW |
49 | /* |
50 | * Both data and metadata needs to track how many readers are for the | |
51 | * page. | |
52 | * Data relies on @readers to unlock the page when last reader finished. | |
53 | * While metadata doesn't need page unlock, it needs to prevent | |
54 | * page::private get cleared before the last end_page_read(). | |
55 | */ | |
56 | atomic_t readers; | |
760f991f | 57 | union { |
8ff8466d QW |
58 | /* |
59 | * Structures only used by metadata | |
60 | * | |
61 | * @eb_refs should only be operated under private_lock, as it | |
62 | * manages whether the subpage can be detached. | |
63 | */ | |
64 | atomic_t eb_refs; | |
6f17400b | 65 | |
72a69cd0 QW |
66 | /* Structures only used by data */ |
67 | atomic_t writers; | |
760f991f | 68 | }; |
72a69cd0 | 69 | unsigned long bitmaps[]; |
cac06d84 QW |
70 | }; |
71 | ||
72 | enum btrfs_subpage_type { | |
73 | BTRFS_SUBPAGE_METADATA, | |
74 | BTRFS_SUBPAGE_DATA, | |
75 | }; | |
76 | ||
fbca46eb QW |
77 | bool btrfs_is_subpage(const struct btrfs_fs_info *fs_info, struct page *page); |
78 | ||
8481dd80 | 79 | void btrfs_init_subpage_info(struct btrfs_subpage_info *subpage_info, u32 sectorsize); |
cac06d84 QW |
80 | int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info, |
81 | struct page *page, enum btrfs_subpage_type type); | |
82 | void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, | |
83 | struct page *page); | |
84 | ||
760f991f | 85 | /* Allocate additional data where page represents more than one sector */ |
651fb419 QW |
86 | struct btrfs_subpage *btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info, |
87 | enum btrfs_subpage_type type); | |
760f991f QW |
88 | void btrfs_free_subpage(struct btrfs_subpage *subpage); |
89 | ||
8ff8466d QW |
90 | void btrfs_page_inc_eb_refs(const struct btrfs_fs_info *fs_info, |
91 | struct page *page); | |
92 | void btrfs_page_dec_eb_refs(const struct btrfs_fs_info *fs_info, | |
93 | struct page *page); | |
94 | ||
92082d40 QW |
95 | void btrfs_subpage_start_reader(const struct btrfs_fs_info *fs_info, |
96 | struct page *page, u64 start, u32 len); | |
97 | void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info, | |
98 | struct page *page, u64 start, u32 len); | |
99 | ||
1e1de387 QW |
100 | void btrfs_subpage_start_writer(const struct btrfs_fs_info *fs_info, |
101 | struct page *page, u64 start, u32 len); | |
102 | bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info, | |
103 | struct page *page, u64 start, u32 len); | |
104 | int btrfs_page_start_writer_lock(const struct btrfs_fs_info *fs_info, | |
105 | struct page *page, u64 start, u32 len); | |
106 | void btrfs_page_end_writer_lock(const struct btrfs_fs_info *fs_info, | |
107 | struct page *page, u64 start, u32 len); | |
108 | ||
a1d767c1 QW |
109 | /* |
110 | * Template for subpage related operations. | |
111 | * | |
112 | * btrfs_subpage_*() are for call sites where the page has subpage attached and | |
113 | * the range is ensured to be inside the page. | |
114 | * | |
115 | * btrfs_page_*() are for call sites where the page can either be subpage | |
116 | * specific or regular page. The function will handle both cases. | |
117 | * But the range still needs to be inside the page. | |
60e2d255 QW |
118 | * |
119 | * btrfs_page_clamp_*() are similar to btrfs_page_*(), except the range doesn't | |
120 | * need to be inside the page. Those functions will truncate the range | |
121 | * automatically. | |
a1d767c1 QW |
122 | */ |
123 | #define DECLARE_BTRFS_SUBPAGE_OPS(name) \ | |
124 | void btrfs_subpage_set_##name(const struct btrfs_fs_info *fs_info, \ | |
125 | struct page *page, u64 start, u32 len); \ | |
126 | void btrfs_subpage_clear_##name(const struct btrfs_fs_info *fs_info, \ | |
127 | struct page *page, u64 start, u32 len); \ | |
128 | bool btrfs_subpage_test_##name(const struct btrfs_fs_info *fs_info, \ | |
129 | struct page *page, u64 start, u32 len); \ | |
130 | void btrfs_page_set_##name(const struct btrfs_fs_info *fs_info, \ | |
131 | struct page *page, u64 start, u32 len); \ | |
132 | void btrfs_page_clear_##name(const struct btrfs_fs_info *fs_info, \ | |
133 | struct page *page, u64 start, u32 len); \ | |
134 | bool btrfs_page_test_##name(const struct btrfs_fs_info *fs_info, \ | |
60e2d255 QW |
135 | struct page *page, u64 start, u32 len); \ |
136 | void btrfs_page_clamp_set_##name(const struct btrfs_fs_info *fs_info, \ | |
137 | struct page *page, u64 start, u32 len); \ | |
138 | void btrfs_page_clamp_clear_##name(const struct btrfs_fs_info *fs_info, \ | |
139 | struct page *page, u64 start, u32 len); \ | |
140 | bool btrfs_page_clamp_test_##name(const struct btrfs_fs_info *fs_info, \ | |
a1d767c1 QW |
141 | struct page *page, u64 start, u32 len); |
142 | ||
143 | DECLARE_BTRFS_SUBPAGE_OPS(uptodate); | |
03a816b3 | 144 | DECLARE_BTRFS_SUBPAGE_OPS(error); |
d8a5713e | 145 | DECLARE_BTRFS_SUBPAGE_OPS(dirty); |
3470da3b | 146 | DECLARE_BTRFS_SUBPAGE_OPS(writeback); |
6f17400b | 147 | DECLARE_BTRFS_SUBPAGE_OPS(ordered); |
e4f94347 | 148 | DECLARE_BTRFS_SUBPAGE_OPS(checked); |
d8a5713e QW |
149 | |
150 | bool btrfs_subpage_clear_and_test_dirty(const struct btrfs_fs_info *fs_info, | |
151 | struct page *page, u64 start, u32 len); | |
a1d767c1 | 152 | |
cc1d0d93 QW |
153 | void btrfs_page_assert_not_dirty(const struct btrfs_fs_info *fs_info, |
154 | struct page *page); | |
e55a0de1 QW |
155 | void btrfs_page_unlock_writer(struct btrfs_fs_info *fs_info, struct page *page, |
156 | u64 start, u32 len); | |
cc1d0d93 | 157 | |
cac06d84 | 158 | #endif |