fs/erofs: Introduce new features including ztailpacking, fragments and dedupe
[platform/kernel/u-boot.git] / fs / erofs / data.c
1 // SPDX-License-Identifier: GPL-2.0+
2 #include "internal.h"
3 #include "decompress.h"
4
5 static int erofs_map_blocks_flatmode(struct erofs_inode *inode,
6                                      struct erofs_map_blocks *map,
7                                      int flags)
8 {
9         int err = 0;
10         erofs_blk_t nblocks, lastblk;
11         u64 offset = map->m_la;
12         struct erofs_inode *vi = inode;
13         bool tailendpacking = (vi->datalayout == EROFS_INODE_FLAT_INLINE);
14
15         nblocks = BLK_ROUND_UP(inode->i_size);
16         lastblk = nblocks - tailendpacking;
17
18         /* there is no hole in flatmode */
19         map->m_flags = EROFS_MAP_MAPPED;
20
21         if (offset < erofs_pos(lastblk)) {
22                 map->m_pa = erofs_pos(vi->u.i_blkaddr) + map->m_la;
23                 map->m_plen = erofs_pos(lastblk) - offset;
24         } else if (tailendpacking) {
25                 /* 2 - inode inline B: inode, [xattrs], inline last blk... */
26                 map->m_pa = iloc(vi->nid) + vi->inode_isize +
27                         vi->xattr_isize + erofs_blkoff(map->m_la);
28                 map->m_plen = inode->i_size - offset;
29
30                 /* inline data should be located in the same meta block */
31                 if (erofs_blkoff(map->m_pa) + map->m_plen > erofs_blksiz()) {
32                         erofs_err("inline data cross block boundary @ nid %" PRIu64,
33                                   vi->nid);
34                         DBG_BUGON(1);
35                         err = -EFSCORRUPTED;
36                         goto err_out;
37                 }
38
39                 map->m_flags |= EROFS_MAP_META;
40         } else {
41                 erofs_err("internal error @ nid: %" PRIu64 " (size %llu), m_la 0x%" PRIx64,
42                           vi->nid, (unsigned long long)inode->i_size, map->m_la);
43                 DBG_BUGON(1);
44                 err = -EIO;
45                 goto err_out;
46         }
47
48         map->m_llen = map->m_plen;
49 err_out:
50         return err;
51 }
52
53 int erofs_map_blocks(struct erofs_inode *inode,
54                      struct erofs_map_blocks *map, int flags)
55 {
56         struct erofs_inode *vi = inode;
57         struct erofs_inode_chunk_index *idx;
58         u8 buf[EROFS_MAX_BLOCK_SIZE];
59         u64 chunknr;
60         unsigned int unit;
61         erofs_off_t pos;
62         int err = 0;
63
64         map->m_deviceid = 0;
65         if (map->m_la >= inode->i_size) {
66                 /* leave out-of-bound access unmapped */
67                 map->m_flags = 0;
68                 map->m_plen = 0;
69                 goto out;
70         }
71
72         if (vi->datalayout != EROFS_INODE_CHUNK_BASED)
73                 return erofs_map_blocks_flatmode(inode, map, flags);
74
75         if (vi->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES)
76                 unit = sizeof(*idx);                    /* chunk index */
77         else
78                 unit = EROFS_BLOCK_MAP_ENTRY_SIZE;      /* block map */
79
80         chunknr = map->m_la >> vi->u.chunkbits;
81         pos = roundup(iloc(vi->nid) + vi->inode_isize +
82                       vi->xattr_isize, unit) + unit * chunknr;
83
84         err = erofs_blk_read(buf, erofs_blknr(pos), 1);
85         if (err < 0)
86                 return -EIO;
87
88         map->m_la = chunknr << vi->u.chunkbits;
89         map->m_plen = min_t(erofs_off_t, 1UL << vi->u.chunkbits,
90                             roundup(inode->i_size - map->m_la, erofs_blksiz()));
91
92         /* handle block map */
93         if (!(vi->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES)) {
94                 __le32 *blkaddr = (void *)buf + erofs_blkoff(pos);
95
96                 if (le32_to_cpu(*blkaddr) == EROFS_NULL_ADDR) {
97                         map->m_flags = 0;
98                 } else {
99                         map->m_pa = erofs_pos(le32_to_cpu(*blkaddr));
100                         map->m_flags = EROFS_MAP_MAPPED;
101                 }
102                 goto out;
103         }
104         /* parse chunk indexes */
105         idx = (void *)buf + erofs_blkoff(pos);
106         switch (le32_to_cpu(idx->blkaddr)) {
107         case EROFS_NULL_ADDR:
108                 map->m_flags = 0;
109                 break;
110         default:
111                 map->m_deviceid = le16_to_cpu(idx->device_id) &
112                         sbi.device_id_mask;
113                 map->m_pa = erofs_pos(le32_to_cpu(idx->blkaddr));
114                 map->m_flags = EROFS_MAP_MAPPED;
115                 break;
116         }
117 out:
118         map->m_llen = map->m_plen;
119         return err;
120 }
121
122 int erofs_map_dev(struct erofs_map_dev *map)
123 {
124         struct erofs_device_info *dif;
125         int id;
126
127         if (map->m_deviceid) {
128                 if (sbi.extra_devices < map->m_deviceid)
129                         return -ENODEV;
130         } else if (sbi.extra_devices) {
131                 for (id = 0; id < sbi.extra_devices; ++id) {
132                         erofs_off_t startoff, length;
133
134                         dif = sbi.devs + id;
135                         if (!dif->mapped_blkaddr)
136                                 continue;
137                         startoff = erofs_pos(dif->mapped_blkaddr);
138                         length = erofs_pos(dif->blocks);
139
140                         if (map->m_pa >= startoff &&
141                             map->m_pa < startoff + length) {
142                                 map->m_pa -= startoff;
143                                 break;
144                         }
145                 }
146         }
147         return 0;
148 }
149
150 int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset,
151                         size_t len)
152 {
153         struct erofs_map_dev mdev;
154         int ret;
155
156         mdev = (struct erofs_map_dev) {
157                 .m_deviceid = map->m_deviceid,
158                 .m_pa = map->m_pa,
159         };
160         ret = erofs_map_dev(&mdev);
161         if (ret)
162                 return ret;
163
164         ret = erofs_dev_read(mdev.m_deviceid, buffer, mdev.m_pa + offset, len);
165         if (ret < 0)
166                 return -EIO;
167         return 0;
168 }
169
170 static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
171                                erofs_off_t size, erofs_off_t offset)
172 {
173         struct erofs_map_blocks map = {
174                 .index = UINT_MAX,
175         };
176         int ret;
177         erofs_off_t ptr = offset;
178
179         while (ptr < offset + size) {
180                 char *const estart = buffer + ptr - offset;
181                 erofs_off_t eend, moff = 0;
182
183                 map.m_la = ptr;
184                 ret = erofs_map_blocks(inode, &map, 0);
185                 if (ret)
186                         return ret;
187
188                 DBG_BUGON(map.m_plen != map.m_llen);
189
190                 /* trim extent */
191                 eend = min(offset + size, map.m_la + map.m_llen);
192                 DBG_BUGON(ptr < map.m_la);
193
194                 if (!(map.m_flags & EROFS_MAP_MAPPED)) {
195                         if (!map.m_llen) {
196                                 /* reached EOF */
197                                 memset(estart, 0, offset + size - ptr);
198                                 ptr = offset + size;
199                                 continue;
200                         }
201                         memset(estart, 0, eend - ptr);
202                         ptr = eend;
203                         continue;
204                 }
205
206                 if (ptr > map.m_la) {
207                         moff = ptr - map.m_la;
208                         map.m_la = ptr;
209                 }
210
211                 ret = erofs_read_one_data(&map, estart, moff, eend - map.m_la);
212                 if (ret)
213                         return ret;
214                 ptr = eend;
215         }
216         return 0;
217 }
218
219 int z_erofs_read_one_data(struct erofs_inode *inode,
220                           struct erofs_map_blocks *map, char *raw, char *buffer,
221                           erofs_off_t skip, erofs_off_t length, bool trimmed)
222 {
223         struct erofs_map_dev mdev;
224         int ret = 0;
225
226         if (map->m_flags & EROFS_MAP_FRAGMENT) {
227                 struct erofs_inode packed_inode = {
228                         .nid = sbi.packed_nid,
229                 };
230
231                 ret = erofs_read_inode_from_disk(&packed_inode);
232                 if (ret) {
233                         erofs_err("failed to read packed inode from disk");
234                         return ret;
235                 }
236
237                 return erofs_pread(&packed_inode, buffer, length - skip,
238                                    inode->fragmentoff + skip);
239         }
240
241         /* no device id here, thus it will always succeed */
242         mdev = (struct erofs_map_dev) {
243                 .m_pa = map->m_pa,
244         };
245         ret = erofs_map_dev(&mdev);
246         if (ret) {
247                 DBG_BUGON(1);
248                 return ret;
249         }
250
251         ret = erofs_dev_read(mdev.m_deviceid, raw, mdev.m_pa, map->m_plen);
252         if (ret < 0)
253                 return ret;
254
255         ret = z_erofs_decompress(&(struct z_erofs_decompress_req) {
256                         .in = raw,
257                         .out = buffer,
258                         .decodedskip = skip,
259                         .interlaced_offset =
260                                 map->m_algorithmformat == Z_EROFS_COMPRESSION_INTERLACED ?
261                                         erofs_blkoff(map->m_la) : 0,
262                         .inputsize = map->m_plen,
263                         .decodedlength = length,
264                         .alg = map->m_algorithmformat,
265                         .partial_decoding = trimmed ? true :
266                                 !(map->m_flags & EROFS_MAP_FULL_MAPPED) ||
267                                         (map->m_flags & EROFS_MAP_PARTIAL_REF),
268                          });
269         if (ret < 0)
270                 return ret;
271         return 0;
272 }
273
274 static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
275                              erofs_off_t size, erofs_off_t offset)
276 {
277         erofs_off_t end, length, skip;
278         struct erofs_map_blocks map = {
279                 .index = UINT_MAX,
280         };
281         bool trimmed;
282         unsigned int bufsize = 0;
283         char *raw = NULL;
284         int ret = 0;
285
286         end = offset + size;
287         while (end > offset) {
288                 map.m_la = end - 1;
289
290                 ret = z_erofs_map_blocks_iter(inode, &map, 0);
291                 if (ret)
292                         break;
293
294                 /*
295                  * trim to the needed size if the returned extent is quite
296                  * larger than requested, and set up partial flag as well.
297                  */
298                 if (end < map.m_la + map.m_llen) {
299                         length = end - map.m_la;
300                         trimmed = true;
301                 } else {
302                         DBG_BUGON(end != map.m_la + map.m_llen);
303                         length = map.m_llen;
304                         trimmed = false;
305                 }
306
307                 if (map.m_la < offset) {
308                         skip = offset - map.m_la;
309                         end = offset;
310                 } else {
311                         skip = 0;
312                         end = map.m_la;
313                 }
314
315                 if (!(map.m_flags & EROFS_MAP_MAPPED)) {
316                         memset(buffer + end - offset, 0, length);
317                         end = map.m_la;
318                         continue;
319                 }
320
321                 if (map.m_plen > bufsize) {
322                         bufsize = map.m_plen;
323                         raw = realloc(raw, bufsize);
324                         if (!raw) {
325                                 ret = -ENOMEM;
326                                 break;
327                         }
328                 }
329
330                 ret = z_erofs_read_one_data(inode, &map, raw,
331                                             buffer + end - offset, skip, length,
332                                             trimmed);
333                 if (ret < 0)
334                         break;
335         }
336         if (raw)
337                 free(raw);
338         return ret < 0 ? ret : 0;
339 }
340
341 int erofs_pread(struct erofs_inode *inode, char *buf,
342                 erofs_off_t count, erofs_off_t offset)
343 {
344         switch (inode->datalayout) {
345         case EROFS_INODE_FLAT_PLAIN:
346         case EROFS_INODE_FLAT_INLINE:
347         case EROFS_INODE_CHUNK_BASED:
348                 return erofs_read_raw_data(inode, buf, count, offset);
349         case EROFS_INODE_COMPRESSED_FULL:
350         case EROFS_INODE_COMPRESSED_COMPACT:
351                 return z_erofs_read_data(inode, buf, count, offset);
352         default:
353                 break;
354         }
355         return -EINVAL;
356 }