1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Windows System Compression (WOF) decompression glue.
4 *
5 * Copyright (c) 2026 LG Electronics Co., Ltd.
6 */
7
8 #include <linux/fs.h>
9 #include <linux/blkdev.h>
10 #include <linux/overflow.h>
11 #include <linux/pagemap.h>
12 #include <linux/sched/mm.h>
13 #include <linux/slab.h>
14 #include <linux/unaligned.h>
15 #include <linux/vmalloc.h>
16
17 #include "ntfs.h"
18 #include "inode.h"
19 #include "debug.h"
20 #include "ntfs_codec.h"
21 #include "attrib.h"
22
23 static const __le16 WOF_NAME[] = {
24 cpu_to_le16('W'), cpu_to_le16('o'), cpu_to_le16('f'),
25 cpu_to_le16('C'), cpu_to_le16('o'), cpu_to_le16('m'),
26 cpu_to_le16('p'), cpu_to_le16('r'), cpu_to_le16('e'),
27 cpu_to_le16('s'), cpu_to_le16('s'), cpu_to_le16('e'),
28 cpu_to_le16('d'), cpu_to_le16('D'), cpu_to_le16('a'),
29 cpu_to_le16('t'), cpu_to_le16('a'),
30 };
31
32 #define WOF_NAME_LEN 17
33
34 #define NTFS_WOF_MAX_COMP_UNIT (1U << 15)
35 #define NTFS_WOF_MAX_PAGES \
36 DIV_ROUND_UP(NTFS_WOF_MAX_COMP_UNIT + PAGE_SIZE - 1, PAGE_SIZE)
37
38 struct ntfs_wof_workspace {
39 struct mutex *lock;
40 const struct ntfs_codec_ops *codec;
41 u32 comp_unit;
42 void *output;
43 void *scratch;
44 };
45
46 static DEFINE_MUTEX(ntfs_wof_xpress4k_lock);
47 static DEFINE_MUTEX(ntfs_wof_xpress8k_lock);
48 static DEFINE_MUTEX(ntfs_wof_xpress16k_lock);
49 static DEFINE_MUTEX(ntfs_wof_lzx32k_lock);
50
51 static struct ntfs_wof_workspace ntfs_wof_xpress4k_workspace = {
52 .lock = &ntfs_wof_xpress4k_lock,
53 .codec = &ntfs_xpress4k_codec_ops,
54 .comp_unit = 1U << 12,
55 };
56
57 static struct ntfs_wof_workspace ntfs_wof_xpress8k_workspace = {
58 .lock = &ntfs_wof_xpress8k_lock,
59 .codec = &ntfs_xpress8k_codec_ops,
60 .comp_unit = 1U << 13,
61 };
62
63 static struct ntfs_wof_workspace ntfs_wof_xpress16k_workspace = {
64 .lock = &ntfs_wof_xpress16k_lock,
65 .codec = &ntfs_xpress16k_codec_ops,
66 .comp_unit = 1U << 14,
67 };
68
69 static struct ntfs_wof_workspace ntfs_wof_lzx32k_workspace = {
70 .lock = &ntfs_wof_lzx32k_lock,
71 .codec = &ntfs_lzx32k_codec_ops,
72 .comp_unit = 1U << 15,
73 };
74
75 static struct ntfs_wof_workspace *const ntfs_wof_workspaces[] = {
76 &ntfs_wof_xpress4k_workspace,
77 &ntfs_wof_xpress8k_workspace,
78 &ntfs_wof_xpress16k_workspace,
79 &ntfs_wof_lzx32k_workspace,
80 };
81
ntfs_wof_workspace(u8 block_size_bits)82 static struct ntfs_wof_workspace *ntfs_wof_workspace(u8 block_size_bits)
83 {
84 switch (block_size_bits) {
85 case 12:
86 return &ntfs_wof_xpress4k_workspace;
87 case 13:
88 return &ntfs_wof_xpress8k_workspace;
89 case 14:
90 return &ntfs_wof_xpress16k_workspace;
91 case 15:
92 return &ntfs_wof_lzx32k_workspace;
93 default:
94 return NULL;
95 }
96 }
97
98 /*
99 * Size of the buffer a chunk is read into. A chunk is read straight off the
100 * device, so the buffer has to hold @comp_unit bytes plus the leading partial
101 * sector.
102 */
ntfs_wof_input_size(const struct ntfs_wof_workspace * ws)103 static size_t ntfs_wof_input_size(const struct ntfs_wof_workspace *ws)
104 {
105 return round_up((size_t)ws->comp_unit + 511, 512);
106 }
107
ntfs_wof_workspace_prepare(struct ntfs_wof_workspace * ws)108 static int ntfs_wof_workspace_prepare(struct ntfs_wof_workspace *ws)
109 {
110 void *output, *scratch;
111 size_t scratch_size;
112
113 if (ws->output)
114 return 0;
115
116 scratch_size = ws->codec->scratch_size(ws->comp_unit);
117 if (!scratch_size)
118 return -EINVAL;
119
120 output = kvmalloc(ws->comp_unit, GFP_NOFS);
121 scratch = kvzalloc(scratch_size, GFP_NOFS);
122 if (!output || !scratch) {
123 kvfree(output);
124 kvfree(scratch);
125 return -ENOMEM;
126 }
127
128 ws->output = output;
129 ws->scratch = scratch;
130 return 0;
131 }
132
ntfs_wof_free_workspaces(void)133 void ntfs_wof_free_workspaces(void)
134 {
135 unsigned int i;
136
137 for (i = 0; i < ARRAY_SIZE(ntfs_wof_workspaces); i++) {
138 struct ntfs_wof_workspace *ws = ntfs_wof_workspaces[i];
139
140 mutex_lock(ws->lock);
141 kvfree(ws->output);
142 kvfree(ws->scratch);
143 ws->output = NULL;
144 ws->scratch = NULL;
145 mutex_unlock(ws->lock);
146 }
147 }
148
ntfs_bdev_read_from_rl(struct ntfs_volume * vol,struct runlist * runlist,sector_t start_sector,u64 sector_count,void * buf)149 static int ntfs_bdev_read_from_rl(struct ntfs_volume *vol,
150 struct runlist *runlist,
151 sector_t start_sector, u64 sector_count,
152 void *buf)
153 {
154 struct runlist_element *rl;
155 u32 sec_per_clu_bits;
156 s64 vcn;
157 u64 sec_off;
158 size_t buf_off = 0;
159 unsigned int nofs_flags;
160 int err;
161
162 if (vol->cluster_size_bits < 9)
163 return -EINVAL;
164 sec_per_clu_bits = vol->cluster_size_bits - 9;
165 vcn = start_sector >> sec_per_clu_bits;
166 sec_off = start_sector & ((1ULL << sec_per_clu_bits) - 1);
167
168 nofs_flags = memalloc_nofs_save();
169 down_read(&runlist->lock);
170 if (!runlist->rl) {
171 err = -EINVAL;
172 goto out_unlock;
173 }
174
175 rl = __ntfs_attr_find_vcn_nolock(runlist, vcn);
176 if (IS_ERR(rl)) {
177 err = PTR_ERR(rl);
178 goto out_unlock;
179 }
180
181 while (sector_count > 0) {
182 s64 lcn;
183 s64 rl_end;
184 u64 byte_off, byte_len, sectors, available;
185
186 if (rl->length <= 0 || vcn < rl->vcn) {
187 err = -EINVAL;
188 goto out_unlock;
189 }
190
191 lcn = ntfs_rl_vcn_to_lcn(rl, vcn);
192 if (lcn < 0 && lcn != LCN_HOLE) {
193 err = -EINVAL;
194 goto out_unlock;
195 }
196
197 if (check_add_overflow(rl->vcn, rl->length, &rl_end) ||
198 rl_end <= vcn ||
199 (u64)(rl_end - vcn) > (U64_MAX >> sec_per_clu_bits)) {
200 err = -EOVERFLOW;
201 goto out_unlock;
202 }
203 available = (u64)(rl_end - vcn) << sec_per_clu_bits;
204 if (available <= sec_off) {
205 err = -EINVAL;
206 goto out_unlock;
207 }
208 available -= sec_off;
209 sectors = min_t(u64, sector_count, available);
210 if (check_mul_overflow(sectors, (u64)SECTOR_SIZE, &byte_len) ||
211 byte_len > SIZE_MAX - buf_off) {
212 err = -EOVERFLOW;
213 goto out_unlock;
214 }
215
216 if (lcn == LCN_HOLE) {
217 memset((u8 *)buf + buf_off, 0, byte_len);
218 } else {
219 byte_off = ntfs_cluster_to_bytes(vol, lcn);
220 if (check_add_overflow(byte_off, sec_off << 9,
221 &byte_off) ||
222 byte_off > S64_MAX) {
223 err = -EOVERFLOW;
224 goto out_unlock;
225 }
226 err = ntfs_bdev_read(vol->sb->s_bdev,
227 (char *)buf + buf_off,
228 (loff_t)byte_off, byte_len);
229 if (err)
230 goto out_unlock;
231 }
232
233 buf_off += byte_len;
234 sector_count -= sectors;
235 rl++;
236 vcn = rl->vcn;
237 sec_off = 0;
238 }
239
240 err = 0;
241 out_unlock:
242 up_read(&runlist->lock);
243 memalloc_nofs_restore(nofs_flags);
244 return err;
245 }
246
parse_wof_chunk_table(struct ntfs_inode * base_ni,struct ntfs_inode * ni,u64 chunk_idx,u64 chunk_count,u32 decomp_size,u64 * chunk_offset,u32 * chunk_size,void * table_buf,size_t table_buf_size)247 static int parse_wof_chunk_table(struct ntfs_inode *base_ni,
248 struct ntfs_inode *ni, u64 chunk_idx,
249 u64 chunk_count, u32 decomp_size,
250 u64 *chunk_offset, u32 *chunk_size,
251 void *table_buf, size_t table_buf_size)
252 {
253 u8 bytes_per_off;
254 u8 *buf;
255 u64 off[2];
256 u64 byte_off, chunk_data_size, table_size;
257 u32 bytes_to_read;
258 int ret = 0;
259
260 if (i_size_read(VFS_I(base_ni)) < (1ULL << 32))
261 bytes_per_off = sizeof(__le32);
262 else
263 bytes_per_off = sizeof(__le64);
264
265 if (!chunk_count || chunk_idx >= chunk_count)
266 return -EINVAL;
267
268 table_size = (chunk_count - 1) * bytes_per_off;
269 if (ni->data_size < 0 || (u64)ni->data_size < table_size)
270 return -EINVAL;
271 chunk_data_size = (u64)ni->data_size - table_size;
272
273 if (chunk_count == 1) {
274 if (chunk_data_size > decomp_size)
275 return -EINVAL;
276 *chunk_offset = 0;
277 *chunk_size = chunk_data_size;
278 goto out;
279 }
280
281 byte_off = chunk_idx ? (chunk_idx - 1) * bytes_per_off : 0;
282 bytes_to_read = chunk_idx + 1 == chunk_count ?
283 bytes_per_off :
284 (chunk_idx ? 2 : 1) * bytes_per_off;
285
286 if (NInoNonResident(ni)) {
287 sector_t start_sector = byte_off >> 9;
288 u32 sector_off = byte_off & ((1 << 9) - 1);
289 u32 sectors = DIV_ROUND_UP(sector_off + bytes_to_read, 512);
290
291 if ((size_t)sectors << 9 > table_buf_size)
292 return -EINVAL;
293 buf = table_buf;
294 ret = ntfs_bdev_read_from_rl(ni->vol, &ni->runlist,
295 start_sector, sectors, buf);
296 if (ret)
297 return -EIO;
298 buf += sector_off;
299 } else {
300 struct ntfs_attr_search_ctx *ctx;
301 u32 value_length;
302 u16 value_offset;
303
304 if (bytes_to_read > table_buf_size)
305 return -EINVAL;
306
307 mutex_lock(&base_ni->mrec_lock);
308 ctx = ntfs_attr_get_search_ctx(base_ni, NULL);
309 if (!ctx) {
310 ret = -ENOMEM;
311 goto out_unlock_mrec;
312 }
313 ret = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
314 CASE_SENSITIVE, 0, NULL, 0, ctx);
315 if (ret)
316 goto out_put_ctx;
317
318 value_length =
319 le32_to_cpu(ctx->attr->data.resident.value_length);
320 value_offset =
321 le16_to_cpu(ctx->attr->data.resident.value_offset);
322 if (byte_off + bytes_to_read > value_length) {
323 ret = -EINVAL;
324 goto out_put_ctx;
325 }
326 memcpy(table_buf, (u8 *)ctx->attr + value_offset + byte_off,
327 bytes_to_read);
328 buf = table_buf;
329 out_put_ctx:
330 ntfs_attr_put_search_ctx(ctx);
331 out_unlock_mrec:
332 mutex_unlock(&base_ni->mrec_lock);
333 if (ret)
334 return ret;
335 }
336
337 if (bytes_per_off == sizeof(__le32)) {
338 off[0] = chunk_idx ? get_unaligned_le32(buf) : 0;
339 if (chunk_idx + 1 == chunk_count)
340 off[1] = chunk_data_size;
341 else if (chunk_idx)
342 off[1] = get_unaligned_le32(buf + bytes_per_off);
343 else
344 off[1] = get_unaligned_le32(buf);
345 } else {
346 off[0] = chunk_idx ? get_unaligned_le64(buf) : 0;
347 if (chunk_idx + 1 == chunk_count)
348 off[1] = chunk_data_size;
349 else if (chunk_idx)
350 off[1] = get_unaligned_le64(buf + bytes_per_off);
351 else
352 off[1] = get_unaligned_le64(buf);
353 }
354
355 if (off[1] <= off[0] || off[1] > chunk_data_size ||
356 off[1] - off[0] > decomp_size)
357 return -EINVAL;
358
359 *chunk_offset = table_size + off[0];
360 *chunk_size = off[1] - off[0];
361 out:
362 if (!*chunk_size)
363 return -EINVAL;
364 return 0;
365 }
366
ntfs_read_wof_chunk(struct ntfs_volume * vol,struct ntfs_inode * wof_ni,u64 chunk_offset,u32 chunk_size,void * input,size_t input_size,char ** chunk_mem)367 static int ntfs_read_wof_chunk(struct ntfs_volume *vol,
368 struct ntfs_inode *wof_ni, u64 chunk_offset,
369 u32 chunk_size, void *input, size_t input_size,
370 char **chunk_mem)
371 {
372 struct ntfs_inode *base_ni = wof_ni->ext.base_ntfs_ino;
373 struct ntfs_attr_search_ctx *ctx;
374 u32 input_offset = chunk_offset & 511;
375 u32 input_size_aligned;
376 u32 value_length;
377 u16 value_offset;
378 int err;
379
380 input_size_aligned = round_up(chunk_size + input_offset, 512);
381 if (input_size_aligned > input_size)
382 return -EINVAL;
383
384 if (NInoNonResident(wof_ni)) {
385 err = ntfs_bdev_read_from_rl(vol, &wof_ni->runlist,
386 chunk_offset >> 9,
387 input_size_aligned >> 9, input);
388 if (err)
389 return err;
390 *chunk_mem = (u8 *)input + input_offset;
391 return 0;
392 }
393
394 mutex_lock(&base_ni->mrec_lock);
395 ctx = ntfs_attr_get_search_ctx(base_ni, NULL);
396 if (!ctx) {
397 err = -ENOMEM;
398 goto out_unlock_mrec;
399 }
400
401 err = ntfs_attr_lookup(wof_ni->type, wof_ni->name, wof_ni->name_len,
402 CASE_SENSITIVE, 0, NULL, 0, ctx);
403 if (err)
404 goto out_put_ctx;
405
406 value_length = le32_to_cpu(ctx->attr->data.resident.value_length);
407 value_offset = le16_to_cpu(ctx->attr->data.resident.value_offset);
408 if (chunk_offset + chunk_size > value_length) {
409 err = -EINVAL;
410 goto out_put_ctx;
411 }
412 memcpy(input, (u8 *)ctx->attr + value_offset + chunk_offset,
413 chunk_size);
414 *chunk_mem = input;
415 out_put_ctx:
416 ntfs_attr_put_search_ctx(ctx);
417 out_unlock_mrec:
418 mutex_unlock(&base_ni->mrec_lock);
419 return err;
420 }
421
422 struct ntfs_wof_dest {
423 struct folio *folios[NTFS_WOF_MAX_PAGES];
424 struct page *pages[NTFS_WOF_MAX_PAGES];
425 unsigned int nr_folios;
426 unsigned int nr_pages;
427 };
428
ntfs_wof_release_dest(struct ntfs_wof_dest * dest,struct folio * target,bool success)429 static void ntfs_wof_release_dest(struct ntfs_wof_dest *dest,
430 struct folio *target, bool success)
431 {
432 unsigned int i;
433
434 for (i = 0; i < dest->nr_folios; i++) {
435 struct folio *folio = dest->folios[i];
436
437 if (folio == target)
438 continue;
439 if (success) {
440 flush_dcache_folio(folio);
441 folio_mark_uptodate(folio);
442 } else {
443 folio_clear_uptodate(folio);
444 }
445 folio_unlock(folio);
446 folio_put(folio);
447 }
448 }
449
ntfs_wof_collect_dest(struct address_space * mapping,struct folio * target,loff_t chunk_start,loff_t chunk_end,struct ntfs_wof_dest * dest)450 static int ntfs_wof_collect_dest(struct address_space *mapping,
451 struct folio *target, loff_t chunk_start,
452 loff_t chunk_end, struct ntfs_wof_dest *dest)
453 {
454 pgoff_t index, last, page_index;
455 unsigned int i;
456
457 memset(dest, 0, sizeof(*dest));
458 index = chunk_start >> PAGE_SHIFT;
459 last = (chunk_end - 1) >> PAGE_SHIFT;
460 while (index <= last) {
461 struct folio *folio;
462 pgoff_t next;
463 bool is_target;
464
465 if (folio_contains(target, index)) {
466 folio = target;
467 is_target = true;
468 } else {
469 folio = __filemap_get_folio(
470 mapping, index,
471 FGP_LOCK | FGP_CREAT | FGP_NOFS | FGP_NOWAIT,
472 GFP_NOFS);
473 if (IS_ERR(folio))
474 return PTR_ERR(folio);
475 is_target = false;
476 if (folio_pos(folio) < chunk_start ||
477 folio_next_pos(folio) > chunk_end) {
478 folio_unlock(folio);
479 folio_put(folio);
480 return -EAGAIN;
481 }
482 }
483
484 if (dest->nr_folios == ARRAY_SIZE(dest->folios)) {
485 if (!is_target) {
486 folio_unlock(folio);
487 folio_put(folio);
488 }
489 return -EINVAL;
490 }
491 dest->folios[dest->nr_folios++] = folio;
492 next = folio->index + folio_nr_pages(folio);
493 if (next <= index)
494 return -EAGAIN;
495 index = next;
496 }
497
498 for (page_index = chunk_start >> PAGE_SHIFT; page_index <= last;
499 page_index++) {
500 struct folio *folio = NULL;
501
502 for (i = 0; i < dest->nr_folios; i++) {
503 if (folio_contains(dest->folios[i], page_index)) {
504 folio = dest->folios[i];
505 break;
506 }
507 }
508 if (!folio || dest->nr_pages == ARRAY_SIZE(dest->pages))
509 return -EAGAIN;
510 dest->pages[dest->nr_pages++] =
511 folio_page(folio, page_index - folio->index);
512 }
513 return 0;
514 }
515
ntfs_wof_decode(struct ntfs_wof_workspace * ws,const void * src,u32 src_len,void * dst,u32 dst_len)516 static int ntfs_wof_decode(struct ntfs_wof_workspace *ws, const void *src,
517 u32 src_len, void *dst, u32 dst_len)
518 {
519 if (src_len == dst_len) {
520 memcpy(dst, src, dst_len);
521 return 0;
522 }
523 return ws->codec->decompress_chunk(ws->scratch, src, src_len, dst,
524 dst_len, ws->comp_unit);
525 }
526
ntfs_wof_decode_page_direct(struct ntfs_wof_workspace * ws,struct folio * target,loff_t chunk_start,const void * src,u32 src_len,u32 dst_len)527 static int ntfs_wof_decode_page_direct(struct ntfs_wof_workspace *ws,
528 struct folio *target, loff_t chunk_start,
529 const void *src, u32 src_len,
530 u32 dst_len)
531 {
532 unsigned int page_offset = offset_in_page(chunk_start);
533 struct page *page;
534 pgoff_t page_index;
535 void *addr;
536 int err;
537
538 page_index = chunk_start >> PAGE_SHIFT;
539 if (!folio_contains(target, page_index))
540 return -EAGAIN;
541
542 page = folio_page(target, page_index - target->index);
543 addr = kmap_local_page(page);
544 err = ntfs_wof_decode(ws, src, src_len, (u8 *)addr + page_offset,
545 dst_len);
546 kunmap_local(addr);
547 if (err)
548 return -EINVAL;
549 return 0;
550 }
551
ntfs_wof_decode_folios_direct(struct ntfs_wof_workspace * ws,struct address_space * mapping,struct folio * target,loff_t chunk_start,loff_t chunk_end,const void * src,u32 src_len,u32 dst_len)552 static int ntfs_wof_decode_folios_direct(struct ntfs_wof_workspace *ws,
553 struct address_space *mapping,
554 struct folio *target,
555 loff_t chunk_start, loff_t chunk_end,
556 const void *src, u32 src_len,
557 u32 dst_len)
558 {
559 unsigned int page_offset = offset_in_page(chunk_start);
560 struct ntfs_wof_dest dest;
561 void *addr;
562 unsigned int nofs_flags;
563 int err;
564
565 err = ntfs_wof_collect_dest(mapping, target, chunk_start, chunk_end,
566 &dest);
567 if (err) {
568 ntfs_wof_release_dest(&dest, target, false);
569 return -EAGAIN;
570 }
571
572 nofs_flags = memalloc_nofs_save();
573 addr = vmap(dest.pages, dest.nr_pages, VM_MAP, PAGE_KERNEL);
574 memalloc_nofs_restore(nofs_flags);
575 if (!addr) {
576 ntfs_wof_release_dest(&dest, target, false);
577 return -EAGAIN;
578 }
579
580 err = ntfs_wof_decode(ws, src, src_len, (u8 *)addr + page_offset,
581 dst_len);
582 vunmap(addr);
583 if (err) {
584 ntfs_wof_release_dest(&dest, target, false);
585 return -EINVAL;
586 }
587 ntfs_wof_release_dest(&dest, target, true);
588 return 0;
589 }
590
ntfs_wof_try_direct(struct ntfs_wof_workspace * ws,struct address_space * mapping,struct folio * target,loff_t chunk_start,loff_t chunk_end,const void * src,u32 src_len,u32 dst_len)591 static int ntfs_wof_try_direct(struct ntfs_wof_workspace *ws,
592 struct address_space *mapping,
593 struct folio *target, loff_t chunk_start,
594 loff_t chunk_end, const void *src, u32 src_len,
595 u32 dst_len)
596 {
597 unsigned int page_offset = offset_in_page(chunk_start);
598
599 if (dst_len <= PAGE_SIZE - page_offset)
600 return ntfs_wof_decode_page_direct(ws, target, chunk_start, src,
601 src_len, dst_len);
602
603 return ntfs_wof_decode_folios_direct(ws, mapping, target, chunk_start,
604 chunk_end, src, src_len, dst_len);
605 }
606
607 /*
608 * Decompress one chunk into @folio. Only this step needs the workspace, so it
609 * is the only step that takes the workspace lock.
610 */
ntfs_wof_decompress_chunk(struct ntfs_wof_workspace * ws,struct ntfs_volume * vol,struct address_space * mapping,struct folio * folio,loff_t folio_start,loff_t folio_end,u64 chunk_file_offset,char * chunk_mem,u32 chunk_size,u32 decomp_size)611 static int ntfs_wof_decompress_chunk(struct ntfs_wof_workspace *ws,
612 struct ntfs_volume *vol,
613 struct address_space *mapping,
614 struct folio *folio, loff_t folio_start,
615 loff_t folio_end, u64 chunk_file_offset,
616 char *chunk_mem, u32 chunk_size,
617 u32 decomp_size)
618 {
619 loff_t chunk_end = chunk_file_offset + decomp_size;
620 loff_t copy_start, copy_end;
621 int err;
622
623 mutex_lock(ws->lock);
624 err = ntfs_wof_workspace_prepare(ws);
625 if (err)
626 goto out_unlock;
627
628 err = ntfs_wof_try_direct(ws, mapping, folio, chunk_file_offset,
629 chunk_end, chunk_mem, chunk_size,
630 decomp_size);
631 if (err != -EAGAIN)
632 goto out_unlock;
633
634 err = ntfs_wof_decode(ws, chunk_mem, chunk_size, ws->output,
635 decomp_size);
636 if (err) {
637 ntfs_error(vol->sb, "Decompression failed: %d", err);
638 err = -EINVAL;
639 goto out_unlock;
640 }
641
642 copy_start = max_t(loff_t, folio_start, chunk_file_offset);
643 copy_end = min_t(loff_t, folio_end, chunk_file_offset + decomp_size);
644 memcpy_to_folio(folio, copy_start - folio_start,
645 ws->output + copy_start - chunk_file_offset,
646 copy_end - copy_start);
647 out_unlock:
648 mutex_unlock(ws->lock);
649 return err;
650 }
651
ntfs_read_wof_compressed_block(struct folio * folio)652 int ntfs_read_wof_compressed_block(struct folio *folio)
653 {
654 struct address_space *mapping = folio->mapping;
655 struct ntfs_inode *ni = NTFS_I(mapping->host), *wof_ni;
656 struct inode *wof_inode;
657 struct ntfs_volume *vol = ni->vol;
658 struct ntfs_wof_workspace *ws;
659 loff_t i_size = i_size_read(VFS_I(ni));
660 loff_t folio_start = folio_pos(folio);
661 loff_t folio_end = folio_next_pos(folio);
662 char *chunk_mem;
663 void *input;
664 size_t input_size;
665 u32 decomp_size;
666 u64 chunk_count, chunk_idx, last_chunk, chunk_offset;
667 int err = 0;
668
669 ws = ntfs_wof_workspace(ni->itype.compressed.block_size_bits);
670 if (!ws) {
671 err = -EOPNOTSUPP;
672 goto out;
673 }
674
675 if (folio_start >= i_size) {
676 folio_zero_segment(folio, 0, folio_size(folio));
677 goto out;
678 }
679
680 wof_inode = ntfs_attr_iget(VFS_I(ni), AT_DATA, (__le16 *)WOF_NAME,
681 WOF_NAME_LEN);
682 if (IS_ERR(wof_inode)) {
683 err = PTR_ERR(wof_inode);
684 goto out;
685 }
686
687 wof_ni = NTFS_I(wof_inode);
688 if (wof_ni->initialized_size != wof_ni->data_size) {
689 ntfs_error(vol->sb,
690 "WOF compressed stream is not fully initialized (init %lld, data %lld).",
691 wof_ni->initialized_size, wof_ni->data_size);
692 err = -EIO;
693 goto out_iput;
694 }
695 if (NInoNonResident(wof_ni) && !NInoFullyMapped(wof_ni)) {
696 down_write(&wof_ni->runlist.lock);
697 if (!NInoFullyMapped(wof_ni))
698 err = ntfs_attr_map_whole_runlist(wof_ni);
699 up_write(&wof_ni->runlist.lock);
700 if (err)
701 goto out_iput;
702 }
703
704 input_size = ntfs_wof_input_size(ws);
705 input = kvmalloc(input_size, GFP_NOFS);
706 if (!input) {
707 err = -ENOMEM;
708 goto out_iput;
709 }
710
711 chunk_idx = div_u64(folio_start, ws->comp_unit);
712 last_chunk =
713 div_u64(min_t(loff_t, folio_end, i_size) - 1, ws->comp_unit);
714 chunk_count = DIV_ROUND_UP_ULL(i_size, ws->comp_unit);
715 for (; chunk_idx <= last_chunk; chunk_idx++) {
716 u32 chunk_size;
717
718 decomp_size = chunk_idx + 1 == chunk_count ?
719 i_size - chunk_idx * ws->comp_unit :
720 ws->comp_unit;
721 err = parse_wof_chunk_table(ni, wof_ni, chunk_idx, chunk_count,
722 decomp_size, &chunk_offset,
723 &chunk_size, input, input_size);
724 if (err)
725 goto out_free_input;
726
727 err = ntfs_read_wof_chunk(vol, wof_ni, chunk_offset, chunk_size,
728 input, input_size, &chunk_mem);
729 if (err)
730 goto out_free_input;
731
732 err = ntfs_wof_decompress_chunk(ws, vol, mapping, folio,
733 folio_start, folio_end,
734 chunk_idx * ws->comp_unit,
735 chunk_mem, chunk_size,
736 decomp_size);
737 if (err)
738 goto out_free_input;
739 }
740
741 if (folio_end > i_size)
742 folio_zero_segment(folio, i_size - folio_start,
743 folio_size(folio));
744 out_free_input:
745 kvfree(input);
746 out_iput:
747 iput(wof_inode);
748 out:
749 if (!err) {
750 flush_dcache_folio(folio);
751 folio_mark_uptodate(folio);
752 } else {
753 folio_clear_uptodate(folio);
754 }
755 folio_unlock(folio);
756 return err;
757 }
758