diff options
Diffstat (limited to 'fs/erofs/zpvec.h')
-rw-r--r-- | fs/erofs/zpvec.h | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/fs/erofs/zpvec.h b/fs/erofs/zpvec.h new file mode 100644 index 000000000000..bd3cee16491c --- /dev/null +++ b/fs/erofs/zpvec.h | |||
@@ -0,0 +1,157 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0-only */ | ||
2 | /* | ||
3 | * Copyright (C) 2018 HUAWEI, Inc. | ||
4 | * http://www.huawei.com/ | ||
5 | * Created by Gao Xiang <gaoxiang25@huawei.com> | ||
6 | */ | ||
7 | #ifndef __EROFS_FS_ZPVEC_H | ||
8 | #define __EROFS_FS_ZPVEC_H | ||
9 | |||
10 | #include "tagptr.h" | ||
11 | |||
12 | /* page type in pagevec for decompress subsystem */ | ||
13 | enum z_erofs_page_type { | ||
14 | /* including Z_EROFS_VLE_PAGE_TAIL_EXCLUSIVE */ | ||
15 | Z_EROFS_PAGE_TYPE_EXCLUSIVE, | ||
16 | |||
17 | Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED, | ||
18 | |||
19 | Z_EROFS_VLE_PAGE_TYPE_HEAD, | ||
20 | Z_EROFS_VLE_PAGE_TYPE_MAX | ||
21 | }; | ||
22 | |||
23 | extern void __compiletime_error("Z_EROFS_PAGE_TYPE_EXCLUSIVE != 0") | ||
24 | __bad_page_type_exclusive(void); | ||
25 | |||
26 | /* pagevec tagged pointer */ | ||
27 | typedef tagptr2_t erofs_vtptr_t; | ||
28 | |||
29 | /* pagevec collector */ | ||
30 | struct z_erofs_pagevec_ctor { | ||
31 | struct page *curr, *next; | ||
32 | erofs_vtptr_t *pages; | ||
33 | |||
34 | unsigned int nr, index; | ||
35 | }; | ||
36 | |||
37 | static inline void z_erofs_pagevec_ctor_exit(struct z_erofs_pagevec_ctor *ctor, | ||
38 | bool atomic) | ||
39 | { | ||
40 | if (!ctor->curr) | ||
41 | return; | ||
42 | |||
43 | if (atomic) | ||
44 | kunmap_atomic(ctor->pages); | ||
45 | else | ||
46 | kunmap(ctor->curr); | ||
47 | } | ||
48 | |||
49 | static inline struct page * | ||
50 | z_erofs_pagevec_ctor_next_page(struct z_erofs_pagevec_ctor *ctor, | ||
51 | unsigned int nr) | ||
52 | { | ||
53 | unsigned int index; | ||
54 | |||
55 | /* keep away from occupied pages */ | ||
56 | if (ctor->next) | ||
57 | return ctor->next; | ||
58 | |||
59 | for (index = 0; index < nr; ++index) { | ||
60 | const erofs_vtptr_t t = ctor->pages[index]; | ||
61 | const unsigned int tags = tagptr_unfold_tags(t); | ||
62 | |||
63 | if (tags == Z_EROFS_PAGE_TYPE_EXCLUSIVE) | ||
64 | return tagptr_unfold_ptr(t); | ||
65 | } | ||
66 | DBG_BUGON(nr >= ctor->nr); | ||
67 | return NULL; | ||
68 | } | ||
69 | |||
70 | static inline void | ||
71 | z_erofs_pagevec_ctor_pagedown(struct z_erofs_pagevec_ctor *ctor, | ||
72 | bool atomic) | ||
73 | { | ||
74 | struct page *next = z_erofs_pagevec_ctor_next_page(ctor, ctor->nr); | ||
75 | |||
76 | z_erofs_pagevec_ctor_exit(ctor, atomic); | ||
77 | |||
78 | ctor->curr = next; | ||
79 | ctor->next = NULL; | ||
80 | ctor->pages = atomic ? | ||
81 | kmap_atomic(ctor->curr) : kmap(ctor->curr); | ||
82 | |||
83 | ctor->nr = PAGE_SIZE / sizeof(struct page *); | ||
84 | ctor->index = 0; | ||
85 | } | ||
86 | |||
87 | static inline void z_erofs_pagevec_ctor_init(struct z_erofs_pagevec_ctor *ctor, | ||
88 | unsigned int nr, | ||
89 | erofs_vtptr_t *pages, | ||
90 | unsigned int i) | ||
91 | { | ||
92 | ctor->nr = nr; | ||
93 | ctor->curr = ctor->next = NULL; | ||
94 | ctor->pages = pages; | ||
95 | |||
96 | if (i >= nr) { | ||
97 | i -= nr; | ||
98 | z_erofs_pagevec_ctor_pagedown(ctor, false); | ||
99 | while (i > ctor->nr) { | ||
100 | i -= ctor->nr; | ||
101 | z_erofs_pagevec_ctor_pagedown(ctor, false); | ||
102 | } | ||
103 | } | ||
104 | ctor->next = z_erofs_pagevec_ctor_next_page(ctor, i); | ||
105 | ctor->index = i; | ||
106 | } | ||
107 | |||
108 | static inline bool z_erofs_pagevec_enqueue(struct z_erofs_pagevec_ctor *ctor, | ||
109 | struct page *page, | ||
110 | enum z_erofs_page_type type, | ||
111 | bool *occupied) | ||
112 | { | ||
113 | *occupied = false; | ||
114 | if (unlikely(!ctor->next && type)) | ||
115 | if (ctor->index + 1 == ctor->nr) | ||
116 | return false; | ||
117 | |||
118 | if (unlikely(ctor->index >= ctor->nr)) | ||
119 | z_erofs_pagevec_ctor_pagedown(ctor, false); | ||
120 | |||
121 | /* exclusive page type must be 0 */ | ||
122 | if (Z_EROFS_PAGE_TYPE_EXCLUSIVE != (uintptr_t)NULL) | ||
123 | __bad_page_type_exclusive(); | ||
124 | |||
125 | /* should remind that collector->next never equal to 1, 2 */ | ||
126 | if (type == (uintptr_t)ctor->next) { | ||
127 | ctor->next = page; | ||
128 | *occupied = true; | ||
129 | } | ||
130 | ctor->pages[ctor->index++] = tagptr_fold(erofs_vtptr_t, page, type); | ||
131 | return true; | ||
132 | } | ||
133 | |||
134 | static inline struct page * | ||
135 | z_erofs_pagevec_dequeue(struct z_erofs_pagevec_ctor *ctor, | ||
136 | enum z_erofs_page_type *type) | ||
137 | { | ||
138 | erofs_vtptr_t t; | ||
139 | |||
140 | if (unlikely(ctor->index >= ctor->nr)) { | ||
141 | DBG_BUGON(!ctor->next); | ||
142 | z_erofs_pagevec_ctor_pagedown(ctor, true); | ||
143 | } | ||
144 | |||
145 | t = ctor->pages[ctor->index]; | ||
146 | |||
147 | *type = tagptr_unfold_tags(t); | ||
148 | |||
149 | /* should remind that collector->next never equal to 1, 2 */ | ||
150 | if (*type == (uintptr_t)ctor->next) | ||
151 | ctor->next = tagptr_unfold_ptr(t); | ||
152 | |||
153 | ctor->pages[ctor->index++] = tagptr_fold(erofs_vtptr_t, NULL, 0); | ||
154 | return tagptr_unfold_ptr(t); | ||
155 | } | ||
156 | #endif | ||
157 | |||