f8daadb19e37f2c9ed0800a7f57f943150d2e714
[linux-block.git] / fs / erofs / zdata.h
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (C) 2018 HUAWEI, Inc.
4  *             https://www.huawei.com/
5  */
6 #ifndef __EROFS_FS_ZDATA_H
7 #define __EROFS_FS_ZDATA_H
8
9 #include "internal.h"
10 #include "zpvec.h"
11
12 #define Z_EROFS_PCLUSTER_MAX_PAGES      (Z_EROFS_PCLUSTER_MAX_SIZE / PAGE_SIZE)
13 #define Z_EROFS_NR_INLINE_PAGEVECS      3
14
15 #define Z_EROFS_PCLUSTER_FULL_LENGTH    0x00000001
16 #define Z_EROFS_PCLUSTER_LENGTH_BIT     1
17
18 /*
19  * let's leave a type here in case of introducing
20  * another tagged pointer later.
21  */
22 typedef void *z_erofs_next_pcluster_t;
23
24 struct z_erofs_bvec {
25         struct page *page;
26         int offset;
27         unsigned int end;
28 };
29
30 #define __Z_EROFS_BVSET(name, total) \
31 struct name { \
32         /* point to the next page which contains the following bvecs */ \
33         struct page *nextpage; \
34         struct z_erofs_bvec bvec[total]; \
35 }
36 __Z_EROFS_BVSET(z_erofs_bvset,);
37 __Z_EROFS_BVSET(z_erofs_bvset_inline, Z_EROFS_NR_INLINE_PAGEVECS);
38
39 /*
40  * Structure fields follow one of the following exclusion rules.
41  *
42  * I: Modifiable by initialization/destruction paths and read-only
43  *    for everyone else;
44  *
45  * L: Field should be protected by the pcluster lock;
46  *
47  * A: Field should be accessed / updated in atomic for parallelized code.
48  */
49 struct z_erofs_pcluster {
50         struct erofs_workgroup obj;
51         struct mutex lock;
52
53         /* A: point to next chained pcluster or TAILs */
54         z_erofs_next_pcluster_t next;
55
56         /* A: lower limit of decompressed length and if full length or not */
57         unsigned int length;
58
59         /* L: total number of bvecs */
60         unsigned int vcnt;
61
62         /* I: page offset of start position of decompression */
63         unsigned short pageofs_out;
64
65         /* I: page offset of inline compressed data */
66         unsigned short pageofs_in;
67
68         /* L: maximum relative page index in bvecs */
69         unsigned short nr_pages;
70
71         union {
72                 /* L: inline a certain number of pagevecs for bootstrap */
73                 erofs_vtptr_t pagevec[Z_EROFS_NR_INLINE_PAGEVECS];
74
75                 /* L: inline a certain number of bvec for bootstrap */
76                 struct z_erofs_bvset_inline bvset;
77
78                 /* I: can be used to free the pcluster by RCU. */
79                 struct rcu_head rcu;
80         };
81
82         union {
83                 /* I: physical cluster size in pages */
84                 unsigned short pclusterpages;
85
86                 /* I: tailpacking inline compressed size */
87                 unsigned short tailpacking_size;
88         };
89
90         /* I: compression algorithm format */
91         unsigned char algorithmformat;
92
93         /* A: compressed pages (can be cached or inplaced pages) */
94         struct page *compressed_pages[];
95 };
96
97 /* let's avoid the valid 32-bit kernel addresses */
98
99 /* the chained workgroup has't submitted io (still open) */
100 #define Z_EROFS_PCLUSTER_TAIL           ((void *)0x5F0ECAFE)
101 /* the chained workgroup has already submitted io */
102 #define Z_EROFS_PCLUSTER_TAIL_CLOSED    ((void *)0x5F0EDEAD)
103
104 #define Z_EROFS_PCLUSTER_NIL            (NULL)
105
106 struct z_erofs_decompressqueue {
107         struct super_block *sb;
108         atomic_t pending_bios;
109         z_erofs_next_pcluster_t head;
110
111         union {
112                 struct completion done;
113                 struct work_struct work;
114         } u;
115 };
116
117 static inline bool z_erofs_is_inline_pcluster(struct z_erofs_pcluster *pcl)
118 {
119         return !pcl->obj.index;
120 }
121
122 static inline unsigned int z_erofs_pclusterpages(struct z_erofs_pcluster *pcl)
123 {
124         if (z_erofs_is_inline_pcluster(pcl))
125                 return 1;
126         return pcl->pclusterpages;
127 }
128
129 #define Z_EROFS_ONLINEPAGE_COUNT_BITS   2
130 #define Z_EROFS_ONLINEPAGE_COUNT_MASK   ((1 << Z_EROFS_ONLINEPAGE_COUNT_BITS) - 1)
131 #define Z_EROFS_ONLINEPAGE_INDEX_SHIFT  (Z_EROFS_ONLINEPAGE_COUNT_BITS)
132
133 /*
134  * waiters (aka. ongoing_packs): # to unlock the page
135  * sub-index: 0 - for partial page, >= 1 full page sub-index
136  */
137 typedef atomic_t z_erofs_onlinepage_t;
138
139 /* type punning */
140 union z_erofs_onlinepage_converter {
141         z_erofs_onlinepage_t *o;
142         unsigned long *v;
143 };
144
145 static inline unsigned int z_erofs_onlinepage_index(struct page *page)
146 {
147         union z_erofs_onlinepage_converter u;
148
149         DBG_BUGON(!PagePrivate(page));
150         u.v = &page_private(page);
151
152         return atomic_read(u.o) >> Z_EROFS_ONLINEPAGE_INDEX_SHIFT;
153 }
154
155 static inline void z_erofs_onlinepage_init(struct page *page)
156 {
157         union {
158                 z_erofs_onlinepage_t o;
159                 unsigned long v;
160         /* keep from being unlocked in advance */
161         } u = { .o = ATOMIC_INIT(1) };
162
163         set_page_private(page, u.v);
164         smp_wmb();
165         SetPagePrivate(page);
166 }
167
168 static inline void z_erofs_onlinepage_fixup(struct page *page,
169         uintptr_t index, bool down)
170 {
171         union z_erofs_onlinepage_converter u = { .v = &page_private(page) };
172         int orig, orig_index, val;
173
174 repeat:
175         orig = atomic_read(u.o);
176         orig_index = orig >> Z_EROFS_ONLINEPAGE_INDEX_SHIFT;
177         if (orig_index) {
178                 if (!index)
179                         return;
180
181                 DBG_BUGON(orig_index != index);
182         }
183
184         val = (index << Z_EROFS_ONLINEPAGE_INDEX_SHIFT) |
185                 ((orig & Z_EROFS_ONLINEPAGE_COUNT_MASK) + (unsigned int)down);
186         if (atomic_cmpxchg(u.o, orig, val) != orig)
187                 goto repeat;
188 }
189
190 static inline void z_erofs_onlinepage_endio(struct page *page)
191 {
192         union z_erofs_onlinepage_converter u;
193         unsigned int v;
194
195         DBG_BUGON(!PagePrivate(page));
196         u.v = &page_private(page);
197
198         v = atomic_dec_return(u.o);
199         if (!(v & Z_EROFS_ONLINEPAGE_COUNT_MASK)) {
200                 set_page_private(page, 0);
201                 ClearPagePrivate(page);
202                 if (!PageError(page))
203                         SetPageUptodate(page);
204                 unlock_page(page);
205         }
206         erofs_dbg("%s, page %p value %x", __func__, page, atomic_read(u.o));
207 }
208
209 #define Z_EROFS_VMAP_ONSTACK_PAGES      \
210         min_t(unsigned int, THREAD_SIZE / 8 / sizeof(struct page *), 96U)
211 #define Z_EROFS_VMAP_GLOBAL_PAGES       2048
212
213 #endif