18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * f2fs compress support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2019 Chao Yu <chao@kernel.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/fs.h> 98c2ecf20Sopenharmony_ci#include <linux/f2fs_fs.h> 108c2ecf20Sopenharmony_ci#include <linux/writeback.h> 118c2ecf20Sopenharmony_ci#include <linux/backing-dev.h> 128c2ecf20Sopenharmony_ci#include <linux/lzo.h> 138c2ecf20Sopenharmony_ci#include <linux/lz4.h> 148c2ecf20Sopenharmony_ci#include <linux/zstd.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "f2fs.h" 178c2ecf20Sopenharmony_ci#include "node.h" 188c2ecf20Sopenharmony_ci#include <trace/events/f2fs.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic struct kmem_cache *cic_entry_slab; 218c2ecf20Sopenharmony_cistatic struct kmem_cache *dic_entry_slab; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic void *page_array_alloc(struct inode *inode, int nr) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 268c2ecf20Sopenharmony_ci unsigned int size = sizeof(struct page *) * nr; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci if (likely(size <= sbi->page_array_slab_size)) 298c2ecf20Sopenharmony_ci return kmem_cache_zalloc(sbi->page_array_slab, GFP_NOFS); 308c2ecf20Sopenharmony_ci return f2fs_kzalloc(sbi, size, GFP_NOFS); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic void page_array_free(struct inode *inode, void *pages, int nr) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 368c2ecf20Sopenharmony_ci unsigned int size = sizeof(struct page *) * nr; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (!pages) 398c2ecf20Sopenharmony_ci return; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (likely(size <= sbi->page_array_slab_size)) 428c2ecf20Sopenharmony_ci kmem_cache_free(sbi->page_array_slab, pages); 438c2ecf20Sopenharmony_ci else 448c2ecf20Sopenharmony_ci kfree(pages); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct f2fs_compress_ops { 488c2ecf20Sopenharmony_ci int (*init_compress_ctx)(struct compress_ctx *cc); 498c2ecf20Sopenharmony_ci void (*destroy_compress_ctx)(struct compress_ctx *cc); 508c2ecf20Sopenharmony_ci int (*compress_pages)(struct compress_ctx *cc); 518c2ecf20Sopenharmony_ci int (*init_decompress_ctx)(struct decompress_io_ctx *dic); 528c2ecf20Sopenharmony_ci void (*destroy_decompress_ctx)(struct decompress_io_ctx *dic); 538c2ecf20Sopenharmony_ci int (*decompress_pages)(struct decompress_io_ctx *dic); 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic unsigned int offset_in_cluster(struct compress_ctx *cc, pgoff_t index) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci return index & (cc->cluster_size - 1); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic pgoff_t cluster_idx(struct compress_ctx *cc, pgoff_t index) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci return index >> cc->log_cluster_size; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic pgoff_t start_idx_of_cluster(struct compress_ctx *cc) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci return cc->cluster_idx << cc->log_cluster_size; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cibool f2fs_is_compressed_page(struct page *page) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci if (!PagePrivate(page)) 748c2ecf20Sopenharmony_ci return false; 758c2ecf20Sopenharmony_ci if (!page_private(page)) 768c2ecf20Sopenharmony_ci return false; 778c2ecf20Sopenharmony_ci if (IS_ATOMIC_WRITTEN_PAGE(page) || IS_DUMMY_WRITTEN_PAGE(page)) 788c2ecf20Sopenharmony_ci return false; 798c2ecf20Sopenharmony_ci /* 808c2ecf20Sopenharmony_ci * page->private may be set with pid. 818c2ecf20Sopenharmony_ci * pid_max is enough to check if it is traced. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci if (IS_IO_TRACED_PAGE(page)) 848c2ecf20Sopenharmony_ci return false; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci f2fs_bug_on(F2FS_M_SB(page->mapping), 878c2ecf20Sopenharmony_ci *((u32 *)page_private(page)) != F2FS_COMPRESSED_PAGE_MAGIC); 888c2ecf20Sopenharmony_ci return true; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic void f2fs_set_compressed_page(struct page *page, 928c2ecf20Sopenharmony_ci struct inode *inode, pgoff_t index, void *data) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci SetPagePrivate(page); 958c2ecf20Sopenharmony_ci set_page_private(page, (unsigned long)data); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* i_crypto_info and iv index */ 988c2ecf20Sopenharmony_ci page->index = index; 998c2ecf20Sopenharmony_ci page->mapping = inode->i_mapping; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic void f2fs_drop_rpages(struct compress_ctx *cc, int len, bool unlock) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci int i; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 1078c2ecf20Sopenharmony_ci if (!cc->rpages[i]) 1088c2ecf20Sopenharmony_ci continue; 1098c2ecf20Sopenharmony_ci if (unlock) 1108c2ecf20Sopenharmony_ci unlock_page(cc->rpages[i]); 1118c2ecf20Sopenharmony_ci else 1128c2ecf20Sopenharmony_ci put_page(cc->rpages[i]); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void f2fs_put_rpages(struct compress_ctx *cc) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci f2fs_drop_rpages(cc, cc->cluster_size, false); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void f2fs_unlock_rpages(struct compress_ctx *cc, int len) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci f2fs_drop_rpages(cc, len, true); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void f2fs_put_rpages_wbc(struct compress_ctx *cc, 1278c2ecf20Sopenharmony_ci struct writeback_control *wbc, bool redirty, int unlock) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci unsigned int i; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 1328c2ecf20Sopenharmony_ci if (!cc->rpages[i]) 1338c2ecf20Sopenharmony_ci continue; 1348c2ecf20Sopenharmony_ci if (redirty) 1358c2ecf20Sopenharmony_ci redirty_page_for_writepage(wbc, cc->rpages[i]); 1368c2ecf20Sopenharmony_ci f2fs_put_page(cc->rpages[i], unlock); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistruct page *f2fs_compress_control_page(struct page *page) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci return ((struct compress_io_ctx *)page_private(page))->rpages[0]; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ciint f2fs_init_compress_ctx(struct compress_ctx *cc) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci if (cc->rpages) 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci cc->rpages = page_array_alloc(cc->inode, cc->cluster_size); 1518c2ecf20Sopenharmony_ci return cc->rpages ? 0 : -ENOMEM; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_civoid f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci page_array_free(cc->inode, cc->rpages, cc->cluster_size); 1578c2ecf20Sopenharmony_ci cc->rpages = NULL; 1588c2ecf20Sopenharmony_ci cc->nr_rpages = 0; 1598c2ecf20Sopenharmony_ci cc->nr_cpages = 0; 1608c2ecf20Sopenharmony_ci if (!reuse) 1618c2ecf20Sopenharmony_ci cc->cluster_idx = NULL_CLUSTER; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_civoid f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci unsigned int cluster_ofs; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (!f2fs_cluster_can_merge_page(cc, page->index)) 1698c2ecf20Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(cc->inode), 1); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci cluster_ofs = offset_in_cluster(cc, page->index); 1728c2ecf20Sopenharmony_ci cc->rpages[cluster_ofs] = page; 1738c2ecf20Sopenharmony_ci cc->nr_rpages++; 1748c2ecf20Sopenharmony_ci cc->cluster_idx = cluster_idx(cc, page->index); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZO 1788c2ecf20Sopenharmony_cistatic int lzo_init_compress_ctx(struct compress_ctx *cc) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci cc->private = f2fs_kvmalloc(F2FS_I_SB(cc->inode), 1818c2ecf20Sopenharmony_ci LZO1X_MEM_COMPRESS, GFP_NOFS); 1828c2ecf20Sopenharmony_ci if (!cc->private) 1838c2ecf20Sopenharmony_ci return -ENOMEM; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci cc->clen = lzo1x_worst_compress(PAGE_SIZE << cc->log_cluster_size); 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void lzo_destroy_compress_ctx(struct compress_ctx *cc) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci kvfree(cc->private); 1928c2ecf20Sopenharmony_ci cc->private = NULL; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int lzo_compress_pages(struct compress_ctx *cc) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci int ret; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci ret = lzo1x_1_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata, 2008c2ecf20Sopenharmony_ci &cc->clen, cc->private); 2018c2ecf20Sopenharmony_ci if (ret != LZO_E_OK) { 2028c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lzo compress failed, ret:%d\n", 2038c2ecf20Sopenharmony_ci KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ret); 2048c2ecf20Sopenharmony_ci return -EIO; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int lzo_decompress_pages(struct decompress_io_ctx *dic) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci int ret; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ret = lzo1x_decompress_safe(dic->cbuf->cdata, dic->clen, 2148c2ecf20Sopenharmony_ci dic->rbuf, &dic->rlen); 2158c2ecf20Sopenharmony_ci if (ret != LZO_E_OK) { 2168c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lzo decompress failed, ret:%d\n", 2178c2ecf20Sopenharmony_ci KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ret); 2188c2ecf20Sopenharmony_ci return -EIO; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (dic->rlen != PAGE_SIZE << dic->log_cluster_size) { 2228c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lzo invalid rlen:%zu, " 2238c2ecf20Sopenharmony_ci "expected:%lu\n", KERN_ERR, 2248c2ecf20Sopenharmony_ci F2FS_I_SB(dic->inode)->sb->s_id, 2258c2ecf20Sopenharmony_ci dic->rlen, 2268c2ecf20Sopenharmony_ci PAGE_SIZE << dic->log_cluster_size); 2278c2ecf20Sopenharmony_ci return -EIO; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic const struct f2fs_compress_ops f2fs_lzo_ops = { 2338c2ecf20Sopenharmony_ci .init_compress_ctx = lzo_init_compress_ctx, 2348c2ecf20Sopenharmony_ci .destroy_compress_ctx = lzo_destroy_compress_ctx, 2358c2ecf20Sopenharmony_ci .compress_pages = lzo_compress_pages, 2368c2ecf20Sopenharmony_ci .decompress_pages = lzo_decompress_pages, 2378c2ecf20Sopenharmony_ci}; 2388c2ecf20Sopenharmony_ci#endif 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZ4 2418c2ecf20Sopenharmony_cistatic int lz4_init_compress_ctx(struct compress_ctx *cc) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci cc->private = f2fs_kvmalloc(F2FS_I_SB(cc->inode), 2448c2ecf20Sopenharmony_ci LZ4_MEM_COMPRESS, GFP_NOFS); 2458c2ecf20Sopenharmony_ci if (!cc->private) 2468c2ecf20Sopenharmony_ci return -ENOMEM; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* 2498c2ecf20Sopenharmony_ci * we do not change cc->clen to LZ4_compressBound(inputsize) to 2508c2ecf20Sopenharmony_ci * adapt worst compress case, because lz4 compressor can handle 2518c2ecf20Sopenharmony_ci * output budget properly. 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ci cc->clen = cc->rlen - PAGE_SIZE - COMPRESS_HEADER_SIZE; 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void lz4_destroy_compress_ctx(struct compress_ctx *cc) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci kvfree(cc->private); 2608c2ecf20Sopenharmony_ci cc->private = NULL; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int lz4_compress_pages(struct compress_ctx *cc) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci int len; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci len = LZ4_compress_default(cc->rbuf, cc->cbuf->cdata, cc->rlen, 2688c2ecf20Sopenharmony_ci cc->clen, cc->private); 2698c2ecf20Sopenharmony_ci if (!len) 2708c2ecf20Sopenharmony_ci return -EAGAIN; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci cc->clen = len; 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic int lz4_decompress_pages(struct decompress_io_ctx *dic) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci int ret; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ret = LZ4_decompress_safe(dic->cbuf->cdata, dic->rbuf, 2818c2ecf20Sopenharmony_ci dic->clen, dic->rlen); 2828c2ecf20Sopenharmony_ci if (ret < 0) { 2838c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lz4 decompress failed, ret:%d\n", 2848c2ecf20Sopenharmony_ci KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ret); 2858c2ecf20Sopenharmony_ci return -EIO; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (ret != PAGE_SIZE << dic->log_cluster_size) { 2898c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lz4 invalid ret:%d, " 2908c2ecf20Sopenharmony_ci "expected:%lu\n", KERN_ERR, 2918c2ecf20Sopenharmony_ci F2FS_I_SB(dic->inode)->sb->s_id, ret, 2928c2ecf20Sopenharmony_ci PAGE_SIZE << dic->log_cluster_size); 2938c2ecf20Sopenharmony_ci return -EIO; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic const struct f2fs_compress_ops f2fs_lz4_ops = { 2998c2ecf20Sopenharmony_ci .init_compress_ctx = lz4_init_compress_ctx, 3008c2ecf20Sopenharmony_ci .destroy_compress_ctx = lz4_destroy_compress_ctx, 3018c2ecf20Sopenharmony_ci .compress_pages = lz4_compress_pages, 3028c2ecf20Sopenharmony_ci .decompress_pages = lz4_decompress_pages, 3038c2ecf20Sopenharmony_ci}; 3048c2ecf20Sopenharmony_ci#endif 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_ZSTD 3078c2ecf20Sopenharmony_ci#define F2FS_ZSTD_DEFAULT_CLEVEL 1 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int zstd_init_compress_ctx(struct compress_ctx *cc) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci ZSTD_parameters params; 3128c2ecf20Sopenharmony_ci ZSTD_CStream *stream; 3138c2ecf20Sopenharmony_ci void *workspace; 3148c2ecf20Sopenharmony_ci unsigned int workspace_size; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci params = ZSTD_getParams(F2FS_ZSTD_DEFAULT_CLEVEL, cc->rlen, 0); 3178c2ecf20Sopenharmony_ci workspace_size = ZSTD_CStreamWorkspaceBound(params.cParams); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci workspace = f2fs_kvmalloc(F2FS_I_SB(cc->inode), 3208c2ecf20Sopenharmony_ci workspace_size, GFP_NOFS); 3218c2ecf20Sopenharmony_ci if (!workspace) 3228c2ecf20Sopenharmony_ci return -ENOMEM; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci stream = ZSTD_initCStream(params, 0, workspace, workspace_size); 3258c2ecf20Sopenharmony_ci if (!stream) { 3268c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initCStream failed\n", 3278c2ecf20Sopenharmony_ci KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, 3288c2ecf20Sopenharmony_ci __func__); 3298c2ecf20Sopenharmony_ci kvfree(workspace); 3308c2ecf20Sopenharmony_ci return -EIO; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci cc->private = workspace; 3348c2ecf20Sopenharmony_ci cc->private2 = stream; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci cc->clen = cc->rlen - PAGE_SIZE - COMPRESS_HEADER_SIZE; 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void zstd_destroy_compress_ctx(struct compress_ctx *cc) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci kvfree(cc->private); 3438c2ecf20Sopenharmony_ci cc->private = NULL; 3448c2ecf20Sopenharmony_ci cc->private2 = NULL; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int zstd_compress_pages(struct compress_ctx *cc) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci ZSTD_CStream *stream = cc->private2; 3508c2ecf20Sopenharmony_ci ZSTD_inBuffer inbuf; 3518c2ecf20Sopenharmony_ci ZSTD_outBuffer outbuf; 3528c2ecf20Sopenharmony_ci int src_size = cc->rlen; 3538c2ecf20Sopenharmony_ci int dst_size = src_size - PAGE_SIZE - COMPRESS_HEADER_SIZE; 3548c2ecf20Sopenharmony_ci int ret; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci inbuf.pos = 0; 3578c2ecf20Sopenharmony_ci inbuf.src = cc->rbuf; 3588c2ecf20Sopenharmony_ci inbuf.size = src_size; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci outbuf.pos = 0; 3618c2ecf20Sopenharmony_ci outbuf.dst = cc->cbuf->cdata; 3628c2ecf20Sopenharmony_ci outbuf.size = dst_size; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ret = ZSTD_compressStream(stream, &outbuf, &inbuf); 3658c2ecf20Sopenharmony_ci if (ZSTD_isError(ret)) { 3668c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n", 3678c2ecf20Sopenharmony_ci KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, 3688c2ecf20Sopenharmony_ci __func__, ZSTD_getErrorCode(ret)); 3698c2ecf20Sopenharmony_ci return -EIO; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci ret = ZSTD_endStream(stream, &outbuf); 3738c2ecf20Sopenharmony_ci if (ZSTD_isError(ret)) { 3748c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_endStream returned %d\n", 3758c2ecf20Sopenharmony_ci KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, 3768c2ecf20Sopenharmony_ci __func__, ZSTD_getErrorCode(ret)); 3778c2ecf20Sopenharmony_ci return -EIO; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* 3818c2ecf20Sopenharmony_ci * there is compressed data remained in intermediate buffer due to 3828c2ecf20Sopenharmony_ci * no more space in cbuf.cdata 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci if (ret) 3858c2ecf20Sopenharmony_ci return -EAGAIN; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci cc->clen = outbuf.pos; 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic int zstd_init_decompress_ctx(struct decompress_io_ctx *dic) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci ZSTD_DStream *stream; 3948c2ecf20Sopenharmony_ci void *workspace; 3958c2ecf20Sopenharmony_ci unsigned int workspace_size; 3968c2ecf20Sopenharmony_ci unsigned int max_window_size = 3978c2ecf20Sopenharmony_ci MAX_COMPRESS_WINDOW_SIZE(dic->log_cluster_size); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci workspace_size = ZSTD_DStreamWorkspaceBound(max_window_size); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci workspace = f2fs_kvmalloc(F2FS_I_SB(dic->inode), 4028c2ecf20Sopenharmony_ci workspace_size, GFP_NOFS); 4038c2ecf20Sopenharmony_ci if (!workspace) 4048c2ecf20Sopenharmony_ci return -ENOMEM; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci stream = ZSTD_initDStream(max_window_size, workspace, workspace_size); 4078c2ecf20Sopenharmony_ci if (!stream) { 4088c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initDStream failed\n", 4098c2ecf20Sopenharmony_ci KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, 4108c2ecf20Sopenharmony_ci __func__); 4118c2ecf20Sopenharmony_ci kvfree(workspace); 4128c2ecf20Sopenharmony_ci return -EIO; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci dic->private = workspace; 4168c2ecf20Sopenharmony_ci dic->private2 = stream; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void zstd_destroy_decompress_ctx(struct decompress_io_ctx *dic) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci kvfree(dic->private); 4248c2ecf20Sopenharmony_ci dic->private = NULL; 4258c2ecf20Sopenharmony_ci dic->private2 = NULL; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int zstd_decompress_pages(struct decompress_io_ctx *dic) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci ZSTD_DStream *stream = dic->private2; 4318c2ecf20Sopenharmony_ci ZSTD_inBuffer inbuf; 4328c2ecf20Sopenharmony_ci ZSTD_outBuffer outbuf; 4338c2ecf20Sopenharmony_ci int ret; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci inbuf.pos = 0; 4368c2ecf20Sopenharmony_ci inbuf.src = dic->cbuf->cdata; 4378c2ecf20Sopenharmony_ci inbuf.size = dic->clen; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci outbuf.pos = 0; 4408c2ecf20Sopenharmony_ci outbuf.dst = dic->rbuf; 4418c2ecf20Sopenharmony_ci outbuf.size = dic->rlen; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci ret = ZSTD_decompressStream(stream, &outbuf, &inbuf); 4448c2ecf20Sopenharmony_ci if (ZSTD_isError(ret)) { 4458c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n", 4468c2ecf20Sopenharmony_ci KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, 4478c2ecf20Sopenharmony_ci __func__, ZSTD_getErrorCode(ret)); 4488c2ecf20Sopenharmony_ci return -EIO; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (dic->rlen != outbuf.pos) { 4528c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s ZSTD invalid rlen:%zu, " 4538c2ecf20Sopenharmony_ci "expected:%lu\n", KERN_ERR, 4548c2ecf20Sopenharmony_ci F2FS_I_SB(dic->inode)->sb->s_id, 4558c2ecf20Sopenharmony_ci __func__, dic->rlen, 4568c2ecf20Sopenharmony_ci PAGE_SIZE << dic->log_cluster_size); 4578c2ecf20Sopenharmony_ci return -EIO; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic const struct f2fs_compress_ops f2fs_zstd_ops = { 4648c2ecf20Sopenharmony_ci .init_compress_ctx = zstd_init_compress_ctx, 4658c2ecf20Sopenharmony_ci .destroy_compress_ctx = zstd_destroy_compress_ctx, 4668c2ecf20Sopenharmony_ci .compress_pages = zstd_compress_pages, 4678c2ecf20Sopenharmony_ci .init_decompress_ctx = zstd_init_decompress_ctx, 4688c2ecf20Sopenharmony_ci .destroy_decompress_ctx = zstd_destroy_decompress_ctx, 4698c2ecf20Sopenharmony_ci .decompress_pages = zstd_decompress_pages, 4708c2ecf20Sopenharmony_ci}; 4718c2ecf20Sopenharmony_ci#endif 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZO 4748c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZORLE 4758c2ecf20Sopenharmony_cistatic int lzorle_compress_pages(struct compress_ctx *cc) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci int ret; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci ret = lzorle1x_1_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata, 4808c2ecf20Sopenharmony_ci &cc->clen, cc->private); 4818c2ecf20Sopenharmony_ci if (ret != LZO_E_OK) { 4828c2ecf20Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lzo-rle compress failed, ret:%d\n", 4838c2ecf20Sopenharmony_ci KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ret); 4848c2ecf20Sopenharmony_ci return -EIO; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic const struct f2fs_compress_ops f2fs_lzorle_ops = { 4908c2ecf20Sopenharmony_ci .init_compress_ctx = lzo_init_compress_ctx, 4918c2ecf20Sopenharmony_ci .destroy_compress_ctx = lzo_destroy_compress_ctx, 4928c2ecf20Sopenharmony_ci .compress_pages = lzorle_compress_pages, 4938c2ecf20Sopenharmony_ci .decompress_pages = lzo_decompress_pages, 4948c2ecf20Sopenharmony_ci}; 4958c2ecf20Sopenharmony_ci#endif 4968c2ecf20Sopenharmony_ci#endif 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = { 4998c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZO 5008c2ecf20Sopenharmony_ci &f2fs_lzo_ops, 5018c2ecf20Sopenharmony_ci#else 5028c2ecf20Sopenharmony_ci NULL, 5038c2ecf20Sopenharmony_ci#endif 5048c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZ4 5058c2ecf20Sopenharmony_ci &f2fs_lz4_ops, 5068c2ecf20Sopenharmony_ci#else 5078c2ecf20Sopenharmony_ci NULL, 5088c2ecf20Sopenharmony_ci#endif 5098c2ecf20Sopenharmony_ci#ifdef CONFIG_F2FS_FS_ZSTD 5108c2ecf20Sopenharmony_ci &f2fs_zstd_ops, 5118c2ecf20Sopenharmony_ci#else 5128c2ecf20Sopenharmony_ci NULL, 5138c2ecf20Sopenharmony_ci#endif 5148c2ecf20Sopenharmony_ci#if defined(CONFIG_F2FS_FS_LZO) && defined(CONFIG_F2FS_FS_LZORLE) 5158c2ecf20Sopenharmony_ci &f2fs_lzorle_ops, 5168c2ecf20Sopenharmony_ci#else 5178c2ecf20Sopenharmony_ci NULL, 5188c2ecf20Sopenharmony_ci#endif 5198c2ecf20Sopenharmony_ci}; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cibool f2fs_is_compress_backend_ready(struct inode *inode) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci if (!f2fs_compressed_file(inode)) 5248c2ecf20Sopenharmony_ci return true; 5258c2ecf20Sopenharmony_ci return f2fs_cops[F2FS_I(inode)->i_compress_algorithm]; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic mempool_t *compress_page_pool; 5298c2ecf20Sopenharmony_cistatic int num_compress_pages = 512; 5308c2ecf20Sopenharmony_cimodule_param(num_compress_pages, uint, 0444); 5318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(num_compress_pages, 5328c2ecf20Sopenharmony_ci "Number of intermediate compress pages to preallocate"); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ciint f2fs_init_compress_mempool(void) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci compress_page_pool = mempool_create_page_pool(num_compress_pages, 0); 5378c2ecf20Sopenharmony_ci if (!compress_page_pool) 5388c2ecf20Sopenharmony_ci return -ENOMEM; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_civoid f2fs_destroy_compress_mempool(void) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci mempool_destroy(compress_page_pool); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic struct page *f2fs_compress_alloc_page(void) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct page *page; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci page = mempool_alloc(compress_page_pool, GFP_NOFS); 5538c2ecf20Sopenharmony_ci lock_page(page); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci return page; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistatic void f2fs_compress_free_page(struct page *page) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci if (!page) 5618c2ecf20Sopenharmony_ci return; 5628c2ecf20Sopenharmony_ci set_page_private(page, (unsigned long)NULL); 5638c2ecf20Sopenharmony_ci ClearPagePrivate(page); 5648c2ecf20Sopenharmony_ci page->mapping = NULL; 5658c2ecf20Sopenharmony_ci unlock_page(page); 5668c2ecf20Sopenharmony_ci mempool_free(page, compress_page_pool); 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci#define MAX_VMAP_RETRIES 3 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic void *f2fs_vmap(struct page **pages, unsigned int count) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci int i; 5748c2ecf20Sopenharmony_ci void *buf = NULL; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci for (i = 0; i < MAX_VMAP_RETRIES; i++) { 5778c2ecf20Sopenharmony_ci buf = vm_map_ram(pages, count, -1); 5788c2ecf20Sopenharmony_ci if (buf) 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci vm_unmap_aliases(); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci return buf; 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistatic int f2fs_compress_pages(struct compress_ctx *cc) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(cc->inode); 5888c2ecf20Sopenharmony_ci const struct f2fs_compress_ops *cops = 5898c2ecf20Sopenharmony_ci f2fs_cops[fi->i_compress_algorithm]; 5908c2ecf20Sopenharmony_ci unsigned int max_len, new_nr_cpages; 5918c2ecf20Sopenharmony_ci struct page **new_cpages; 5928c2ecf20Sopenharmony_ci int i, ret; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci trace_f2fs_compress_pages_start(cc->inode, cc->cluster_idx, 5958c2ecf20Sopenharmony_ci cc->cluster_size, fi->i_compress_algorithm); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (cops->init_compress_ctx) { 5988c2ecf20Sopenharmony_ci ret = cops->init_compress_ctx(cc); 5998c2ecf20Sopenharmony_ci if (ret) 6008c2ecf20Sopenharmony_ci goto out; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci max_len = COMPRESS_HEADER_SIZE + cc->clen; 6048c2ecf20Sopenharmony_ci cc->nr_cpages = DIV_ROUND_UP(max_len, PAGE_SIZE); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci cc->cpages = page_array_alloc(cc->inode, cc->nr_cpages); 6078c2ecf20Sopenharmony_ci if (!cc->cpages) { 6088c2ecf20Sopenharmony_ci ret = -ENOMEM; 6098c2ecf20Sopenharmony_ci goto destroy_compress_ctx; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci for (i = 0; i < cc->nr_cpages; i++) { 6138c2ecf20Sopenharmony_ci cc->cpages[i] = f2fs_compress_alloc_page(); 6148c2ecf20Sopenharmony_ci if (!cc->cpages[i]) { 6158c2ecf20Sopenharmony_ci ret = -ENOMEM; 6168c2ecf20Sopenharmony_ci goto out_free_cpages; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci cc->rbuf = f2fs_vmap(cc->rpages, cc->cluster_size); 6218c2ecf20Sopenharmony_ci if (!cc->rbuf) { 6228c2ecf20Sopenharmony_ci ret = -ENOMEM; 6238c2ecf20Sopenharmony_ci goto out_free_cpages; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci cc->cbuf = f2fs_vmap(cc->cpages, cc->nr_cpages); 6278c2ecf20Sopenharmony_ci if (!cc->cbuf) { 6288c2ecf20Sopenharmony_ci ret = -ENOMEM; 6298c2ecf20Sopenharmony_ci goto out_vunmap_rbuf; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci ret = cops->compress_pages(cc); 6338c2ecf20Sopenharmony_ci if (ret) 6348c2ecf20Sopenharmony_ci goto out_vunmap_cbuf; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci max_len = PAGE_SIZE * (cc->cluster_size - 1) - COMPRESS_HEADER_SIZE; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (cc->clen > max_len) { 6398c2ecf20Sopenharmony_ci ret = -EAGAIN; 6408c2ecf20Sopenharmony_ci goto out_vunmap_cbuf; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci cc->cbuf->clen = cpu_to_le32(cc->clen); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci for (i = 0; i < COMPRESS_DATA_RESERVED_SIZE; i++) 6468c2ecf20Sopenharmony_ci cc->cbuf->reserved[i] = cpu_to_le32(0); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci new_nr_cpages = DIV_ROUND_UP(cc->clen + COMPRESS_HEADER_SIZE, PAGE_SIZE); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* Now we're going to cut unnecessary tail pages */ 6518c2ecf20Sopenharmony_ci new_cpages = page_array_alloc(cc->inode, new_nr_cpages); 6528c2ecf20Sopenharmony_ci if (!new_cpages) { 6538c2ecf20Sopenharmony_ci ret = -ENOMEM; 6548c2ecf20Sopenharmony_ci goto out_vunmap_cbuf; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* zero out any unused part of the last page */ 6588c2ecf20Sopenharmony_ci memset(&cc->cbuf->cdata[cc->clen], 0, 6598c2ecf20Sopenharmony_ci (new_nr_cpages * PAGE_SIZE) - 6608c2ecf20Sopenharmony_ci (cc->clen + COMPRESS_HEADER_SIZE)); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci vm_unmap_ram(cc->cbuf, cc->nr_cpages); 6638c2ecf20Sopenharmony_ci vm_unmap_ram(cc->rbuf, cc->cluster_size); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci for (i = 0; i < cc->nr_cpages; i++) { 6668c2ecf20Sopenharmony_ci if (i < new_nr_cpages) { 6678c2ecf20Sopenharmony_ci new_cpages[i] = cc->cpages[i]; 6688c2ecf20Sopenharmony_ci continue; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci f2fs_compress_free_page(cc->cpages[i]); 6718c2ecf20Sopenharmony_ci cc->cpages[i] = NULL; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (cops->destroy_compress_ctx) 6758c2ecf20Sopenharmony_ci cops->destroy_compress_ctx(cc); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci page_array_free(cc->inode, cc->cpages, cc->nr_cpages); 6788c2ecf20Sopenharmony_ci cc->cpages = new_cpages; 6798c2ecf20Sopenharmony_ci cc->nr_cpages = new_nr_cpages; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci trace_f2fs_compress_pages_end(cc->inode, cc->cluster_idx, 6828c2ecf20Sopenharmony_ci cc->clen, ret); 6838c2ecf20Sopenharmony_ci return 0; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ciout_vunmap_cbuf: 6868c2ecf20Sopenharmony_ci vm_unmap_ram(cc->cbuf, cc->nr_cpages); 6878c2ecf20Sopenharmony_ciout_vunmap_rbuf: 6888c2ecf20Sopenharmony_ci vm_unmap_ram(cc->rbuf, cc->cluster_size); 6898c2ecf20Sopenharmony_ciout_free_cpages: 6908c2ecf20Sopenharmony_ci for (i = 0; i < cc->nr_cpages; i++) { 6918c2ecf20Sopenharmony_ci if (cc->cpages[i]) 6928c2ecf20Sopenharmony_ci f2fs_compress_free_page(cc->cpages[i]); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci page_array_free(cc->inode, cc->cpages, cc->nr_cpages); 6958c2ecf20Sopenharmony_ci cc->cpages = NULL; 6968c2ecf20Sopenharmony_cidestroy_compress_ctx: 6978c2ecf20Sopenharmony_ci if (cops->destroy_compress_ctx) 6988c2ecf20Sopenharmony_ci cops->destroy_compress_ctx(cc); 6998c2ecf20Sopenharmony_ciout: 7008c2ecf20Sopenharmony_ci trace_f2fs_compress_pages_end(cc->inode, cc->cluster_idx, 7018c2ecf20Sopenharmony_ci cc->clen, ret); 7028c2ecf20Sopenharmony_ci return ret; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_civoid f2fs_decompress_pages(struct bio *bio, struct page *page, bool verity) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci struct decompress_io_ctx *dic = 7088c2ecf20Sopenharmony_ci (struct decompress_io_ctx *)page_private(page); 7098c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); 7108c2ecf20Sopenharmony_ci struct f2fs_inode_info *fi= F2FS_I(dic->inode); 7118c2ecf20Sopenharmony_ci const struct f2fs_compress_ops *cops = 7128c2ecf20Sopenharmony_ci f2fs_cops[fi->i_compress_algorithm]; 7138c2ecf20Sopenharmony_ci int ret; 7148c2ecf20Sopenharmony_ci int i; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci dec_page_count(sbi, F2FS_RD_DATA); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (bio->bi_status || PageError(page)) 7198c2ecf20Sopenharmony_ci dic->failed = true; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (atomic_dec_return(&dic->pending_pages)) 7228c2ecf20Sopenharmony_ci return; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci trace_f2fs_decompress_pages_start(dic->inode, dic->cluster_idx, 7258c2ecf20Sopenharmony_ci dic->cluster_size, fi->i_compress_algorithm); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* submit partial compressed pages */ 7288c2ecf20Sopenharmony_ci if (dic->failed) { 7298c2ecf20Sopenharmony_ci ret = -EIO; 7308c2ecf20Sopenharmony_ci goto out_free_dic; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci dic->tpages = page_array_alloc(dic->inode, dic->cluster_size); 7348c2ecf20Sopenharmony_ci if (!dic->tpages) { 7358c2ecf20Sopenharmony_ci ret = -ENOMEM; 7368c2ecf20Sopenharmony_ci goto out_free_dic; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci for (i = 0; i < dic->cluster_size; i++) { 7408c2ecf20Sopenharmony_ci if (dic->rpages[i]) { 7418c2ecf20Sopenharmony_ci dic->tpages[i] = dic->rpages[i]; 7428c2ecf20Sopenharmony_ci continue; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci dic->tpages[i] = f2fs_compress_alloc_page(); 7468c2ecf20Sopenharmony_ci if (!dic->tpages[i]) { 7478c2ecf20Sopenharmony_ci ret = -ENOMEM; 7488c2ecf20Sopenharmony_ci goto out_free_dic; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (cops->init_decompress_ctx) { 7538c2ecf20Sopenharmony_ci ret = cops->init_decompress_ctx(dic); 7548c2ecf20Sopenharmony_ci if (ret) 7558c2ecf20Sopenharmony_ci goto out_free_dic; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci dic->rbuf = f2fs_vmap(dic->tpages, dic->cluster_size); 7598c2ecf20Sopenharmony_ci if (!dic->rbuf) { 7608c2ecf20Sopenharmony_ci ret = -ENOMEM; 7618c2ecf20Sopenharmony_ci goto destroy_decompress_ctx; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci dic->cbuf = f2fs_vmap(dic->cpages, dic->nr_cpages); 7658c2ecf20Sopenharmony_ci if (!dic->cbuf) { 7668c2ecf20Sopenharmony_ci ret = -ENOMEM; 7678c2ecf20Sopenharmony_ci goto out_vunmap_rbuf; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci dic->clen = le32_to_cpu(dic->cbuf->clen); 7718c2ecf20Sopenharmony_ci dic->rlen = PAGE_SIZE << dic->log_cluster_size; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (dic->clen > PAGE_SIZE * dic->nr_cpages - COMPRESS_HEADER_SIZE) { 7748c2ecf20Sopenharmony_ci ret = -EFSCORRUPTED; 7758c2ecf20Sopenharmony_ci goto out_vunmap_cbuf; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci ret = cops->decompress_pages(dic); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ciout_vunmap_cbuf: 7818c2ecf20Sopenharmony_ci vm_unmap_ram(dic->cbuf, dic->nr_cpages); 7828c2ecf20Sopenharmony_ciout_vunmap_rbuf: 7838c2ecf20Sopenharmony_ci vm_unmap_ram(dic->rbuf, dic->cluster_size); 7848c2ecf20Sopenharmony_cidestroy_decompress_ctx: 7858c2ecf20Sopenharmony_ci if (cops->destroy_decompress_ctx) 7868c2ecf20Sopenharmony_ci cops->destroy_decompress_ctx(dic); 7878c2ecf20Sopenharmony_ciout_free_dic: 7888c2ecf20Sopenharmony_ci if (!verity) 7898c2ecf20Sopenharmony_ci f2fs_decompress_end_io(dic->rpages, dic->cluster_size, 7908c2ecf20Sopenharmony_ci ret, false); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci trace_f2fs_decompress_pages_end(dic->inode, dic->cluster_idx, 7938c2ecf20Sopenharmony_ci dic->clen, ret); 7948c2ecf20Sopenharmony_ci if (!verity) 7958c2ecf20Sopenharmony_ci f2fs_free_dic(dic); 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic bool is_page_in_cluster(struct compress_ctx *cc, pgoff_t index) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci if (cc->cluster_idx == NULL_CLUSTER) 8018c2ecf20Sopenharmony_ci return true; 8028c2ecf20Sopenharmony_ci return cc->cluster_idx == cluster_idx(cc, index); 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cibool f2fs_cluster_is_empty(struct compress_ctx *cc) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci return cc->nr_rpages == 0; 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic bool f2fs_cluster_is_full(struct compress_ctx *cc) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci return cc->cluster_size == cc->nr_rpages; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cibool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci if (f2fs_cluster_is_empty(cc)) 8188c2ecf20Sopenharmony_ci return true; 8198c2ecf20Sopenharmony_ci return is_page_in_cluster(cc, index); 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic bool __cluster_may_compress(struct compress_ctx *cc) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); 8258c2ecf20Sopenharmony_ci loff_t i_size = i_size_read(cc->inode); 8268c2ecf20Sopenharmony_ci unsigned nr_pages = DIV_ROUND_UP(i_size, PAGE_SIZE); 8278c2ecf20Sopenharmony_ci int i; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 8308c2ecf20Sopenharmony_ci struct page *page = cc->rpages[i]; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, !page); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) 8358c2ecf20Sopenharmony_ci return false; 8368c2ecf20Sopenharmony_ci if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) 8378c2ecf20Sopenharmony_ci return false; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci /* beyond EOF */ 8408c2ecf20Sopenharmony_ci if (page->index >= nr_pages) 8418c2ecf20Sopenharmony_ci return false; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci return true; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct dnode_of_data dn; 8498c2ecf20Sopenharmony_ci int ret; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci set_new_dnode(&dn, cc->inode, NULL, NULL, 0); 8528c2ecf20Sopenharmony_ci ret = f2fs_get_dnode_of_data(&dn, start_idx_of_cluster(cc), 8538c2ecf20Sopenharmony_ci LOOKUP_NODE); 8548c2ecf20Sopenharmony_ci if (ret) { 8558c2ecf20Sopenharmony_ci if (ret == -ENOENT) 8568c2ecf20Sopenharmony_ci ret = 0; 8578c2ecf20Sopenharmony_ci goto fail; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (dn.data_blkaddr == COMPRESS_ADDR) { 8618c2ecf20Sopenharmony_ci int i; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci ret = 1; 8648c2ecf20Sopenharmony_ci for (i = 1; i < cc->cluster_size; i++) { 8658c2ecf20Sopenharmony_ci block_t blkaddr; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci blkaddr = data_blkaddr(dn.inode, 8688c2ecf20Sopenharmony_ci dn.node_page, dn.ofs_in_node + i); 8698c2ecf20Sopenharmony_ci if (compr) { 8708c2ecf20Sopenharmony_ci if (__is_valid_data_blkaddr(blkaddr)) 8718c2ecf20Sopenharmony_ci ret++; 8728c2ecf20Sopenharmony_ci } else { 8738c2ecf20Sopenharmony_ci if (blkaddr != NULL_ADDR) 8748c2ecf20Sopenharmony_ci ret++; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_cifail: 8798c2ecf20Sopenharmony_ci f2fs_put_dnode(&dn); 8808c2ecf20Sopenharmony_ci return ret; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci/* return # of compressed blocks in compressed cluster */ 8848c2ecf20Sopenharmony_cistatic int f2fs_compressed_blocks(struct compress_ctx *cc) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci return __f2fs_cluster_blocks(cc, true); 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci/* return # of valid blocks in compressed cluster */ 8908c2ecf20Sopenharmony_cistatic int f2fs_cluster_blocks(struct compress_ctx *cc) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci return __f2fs_cluster_blocks(cc, false); 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ciint f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct compress_ctx cc = { 8988c2ecf20Sopenharmony_ci .inode = inode, 8998c2ecf20Sopenharmony_ci .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, 9008c2ecf20Sopenharmony_ci .cluster_size = F2FS_I(inode)->i_cluster_size, 9018c2ecf20Sopenharmony_ci .cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size, 9028c2ecf20Sopenharmony_ci }; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci return f2fs_cluster_blocks(&cc); 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic bool cluster_may_compress(struct compress_ctx *cc) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci if (!f2fs_compressed_file(cc->inode)) 9108c2ecf20Sopenharmony_ci return false; 9118c2ecf20Sopenharmony_ci if (f2fs_is_atomic_file(cc->inode)) 9128c2ecf20Sopenharmony_ci return false; 9138c2ecf20Sopenharmony_ci if (f2fs_is_mmap_file(cc->inode)) 9148c2ecf20Sopenharmony_ci return false; 9158c2ecf20Sopenharmony_ci if (!f2fs_cluster_is_full(cc)) 9168c2ecf20Sopenharmony_ci return false; 9178c2ecf20Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(cc->inode)))) 9188c2ecf20Sopenharmony_ci return false; 9198c2ecf20Sopenharmony_ci return __cluster_may_compress(cc); 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic void set_cluster_writeback(struct compress_ctx *cc) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci int i; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 9278c2ecf20Sopenharmony_ci if (cc->rpages[i]) 9288c2ecf20Sopenharmony_ci set_page_writeback(cc->rpages[i]); 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic void set_cluster_dirty(struct compress_ctx *cc) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci int i; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) 9378c2ecf20Sopenharmony_ci if (cc->rpages[i]) 9388c2ecf20Sopenharmony_ci set_page_dirty(cc->rpages[i]); 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic int prepare_compress_overwrite(struct compress_ctx *cc, 9428c2ecf20Sopenharmony_ci struct page **pagep, pgoff_t index, void **fsdata) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); 9458c2ecf20Sopenharmony_ci struct address_space *mapping = cc->inode->i_mapping; 9468c2ecf20Sopenharmony_ci struct page *page; 9478c2ecf20Sopenharmony_ci struct dnode_of_data dn; 9488c2ecf20Sopenharmony_ci sector_t last_block_in_bio; 9498c2ecf20Sopenharmony_ci unsigned fgp_flag = FGP_LOCK | FGP_WRITE | FGP_CREAT; 9508c2ecf20Sopenharmony_ci pgoff_t start_idx = start_idx_of_cluster(cc); 9518c2ecf20Sopenharmony_ci int i, ret; 9528c2ecf20Sopenharmony_ci bool prealloc; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ciretry: 9558c2ecf20Sopenharmony_ci ret = f2fs_cluster_blocks(cc); 9568c2ecf20Sopenharmony_ci if (ret <= 0) 9578c2ecf20Sopenharmony_ci return ret; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci /* compressed case */ 9608c2ecf20Sopenharmony_ci prealloc = (ret < cc->cluster_size); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci ret = f2fs_init_compress_ctx(cc); 9638c2ecf20Sopenharmony_ci if (ret) 9648c2ecf20Sopenharmony_ci return ret; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci /* keep page reference to avoid page reclaim */ 9678c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 9688c2ecf20Sopenharmony_ci page = f2fs_pagecache_get_page(mapping, start_idx + i, 9698c2ecf20Sopenharmony_ci fgp_flag, GFP_NOFS); 9708c2ecf20Sopenharmony_ci if (!page) { 9718c2ecf20Sopenharmony_ci ret = -ENOMEM; 9728c2ecf20Sopenharmony_ci goto unlock_pages; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (PageUptodate(page)) 9768c2ecf20Sopenharmony_ci f2fs_put_page(page, 1); 9778c2ecf20Sopenharmony_ci else 9788c2ecf20Sopenharmony_ci f2fs_compress_ctx_add_page(cc, page); 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (!f2fs_cluster_is_empty(cc)) { 9828c2ecf20Sopenharmony_ci struct bio *bio = NULL; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci ret = f2fs_read_multi_pages(cc, &bio, cc->cluster_size, 9858c2ecf20Sopenharmony_ci &last_block_in_bio, false, true); 9868c2ecf20Sopenharmony_ci f2fs_put_rpages(cc); 9878c2ecf20Sopenharmony_ci f2fs_destroy_compress_ctx(cc, true); 9888c2ecf20Sopenharmony_ci if (ret) 9898c2ecf20Sopenharmony_ci goto out; 9908c2ecf20Sopenharmony_ci if (bio) 9918c2ecf20Sopenharmony_ci f2fs_submit_bio(sbi, bio, DATA); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci ret = f2fs_init_compress_ctx(cc); 9948c2ecf20Sopenharmony_ci if (ret) 9958c2ecf20Sopenharmony_ci goto out; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 9998c2ecf20Sopenharmony_ci f2fs_bug_on(sbi, cc->rpages[i]); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci page = find_lock_page(mapping, start_idx + i); 10028c2ecf20Sopenharmony_ci if (!page) { 10038c2ecf20Sopenharmony_ci /* page can be truncated */ 10048c2ecf20Sopenharmony_ci goto release_and_retry; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci f2fs_wait_on_page_writeback(page, DATA, true, true); 10088c2ecf20Sopenharmony_ci f2fs_compress_ctx_add_page(cc, page); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci if (!PageUptodate(page)) { 10118c2ecf20Sopenharmony_cirelease_and_retry: 10128c2ecf20Sopenharmony_ci f2fs_put_rpages(cc); 10138c2ecf20Sopenharmony_ci f2fs_unlock_rpages(cc, i + 1); 10148c2ecf20Sopenharmony_ci f2fs_destroy_compress_ctx(cc, true); 10158c2ecf20Sopenharmony_ci goto retry; 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (prealloc) { 10208c2ecf20Sopenharmony_ci f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci set_new_dnode(&dn, cc->inode, NULL, NULL, 0); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci for (i = cc->cluster_size - 1; i > 0; i--) { 10258c2ecf20Sopenharmony_ci ret = f2fs_get_block(&dn, start_idx + i); 10268c2ecf20Sopenharmony_ci if (ret) { 10278c2ecf20Sopenharmony_ci i = cc->cluster_size; 10288c2ecf20Sopenharmony_ci break; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (dn.data_blkaddr != NEW_ADDR) 10328c2ecf20Sopenharmony_ci break; 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci if (likely(!ret)) { 10398c2ecf20Sopenharmony_ci *fsdata = cc->rpages; 10408c2ecf20Sopenharmony_ci *pagep = cc->rpages[offset_in_cluster(cc, index)]; 10418c2ecf20Sopenharmony_ci return cc->cluster_size; 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ciunlock_pages: 10458c2ecf20Sopenharmony_ci f2fs_put_rpages(cc); 10468c2ecf20Sopenharmony_ci f2fs_unlock_rpages(cc, i); 10478c2ecf20Sopenharmony_ci f2fs_destroy_compress_ctx(cc, true); 10488c2ecf20Sopenharmony_ciout: 10498c2ecf20Sopenharmony_ci return ret; 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ciint f2fs_prepare_compress_overwrite(struct inode *inode, 10538c2ecf20Sopenharmony_ci struct page **pagep, pgoff_t index, void **fsdata) 10548c2ecf20Sopenharmony_ci{ 10558c2ecf20Sopenharmony_ci struct compress_ctx cc = { 10568c2ecf20Sopenharmony_ci .inode = inode, 10578c2ecf20Sopenharmony_ci .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, 10588c2ecf20Sopenharmony_ci .cluster_size = F2FS_I(inode)->i_cluster_size, 10598c2ecf20Sopenharmony_ci .cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size, 10608c2ecf20Sopenharmony_ci .rpages = NULL, 10618c2ecf20Sopenharmony_ci .nr_rpages = 0, 10628c2ecf20Sopenharmony_ci }; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci return prepare_compress_overwrite(&cc, pagep, index, fsdata); 10658c2ecf20Sopenharmony_ci} 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cibool f2fs_compress_write_end(struct inode *inode, void *fsdata, 10688c2ecf20Sopenharmony_ci pgoff_t index, unsigned copied) 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci{ 10718c2ecf20Sopenharmony_ci struct compress_ctx cc = { 10728c2ecf20Sopenharmony_ci .inode = inode, 10738c2ecf20Sopenharmony_ci .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, 10748c2ecf20Sopenharmony_ci .cluster_size = F2FS_I(inode)->i_cluster_size, 10758c2ecf20Sopenharmony_ci .rpages = fsdata, 10768c2ecf20Sopenharmony_ci }; 10778c2ecf20Sopenharmony_ci bool first_index = (index == cc.rpages[0]->index); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (copied) 10808c2ecf20Sopenharmony_ci set_cluster_dirty(&cc); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci f2fs_put_rpages_wbc(&cc, NULL, false, 1); 10838c2ecf20Sopenharmony_ci f2fs_destroy_compress_ctx(&cc, false); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci return first_index; 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ciint f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci void *fsdata = NULL; 10918c2ecf20Sopenharmony_ci struct page *pagep; 10928c2ecf20Sopenharmony_ci int log_cluster_size = F2FS_I(inode)->i_log_cluster_size; 10938c2ecf20Sopenharmony_ci pgoff_t start_idx = from >> (PAGE_SHIFT + log_cluster_size) << 10948c2ecf20Sopenharmony_ci log_cluster_size; 10958c2ecf20Sopenharmony_ci int err; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci err = f2fs_is_compressed_cluster(inode, start_idx); 10988c2ecf20Sopenharmony_ci if (err < 0) 10998c2ecf20Sopenharmony_ci return err; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* truncate normal cluster */ 11028c2ecf20Sopenharmony_ci if (!err) 11038c2ecf20Sopenharmony_ci return f2fs_do_truncate_blocks(inode, from, lock); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci /* truncate compressed cluster */ 11068c2ecf20Sopenharmony_ci err = f2fs_prepare_compress_overwrite(inode, &pagep, 11078c2ecf20Sopenharmony_ci start_idx, &fsdata); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci /* should not be a normal cluster */ 11108c2ecf20Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(inode), err == 0); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (err <= 0) 11138c2ecf20Sopenharmony_ci return err; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (err > 0) { 11168c2ecf20Sopenharmony_ci struct page **rpages = fsdata; 11178c2ecf20Sopenharmony_ci int cluster_size = F2FS_I(inode)->i_cluster_size; 11188c2ecf20Sopenharmony_ci int i; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci for (i = cluster_size - 1; i >= 0; i--) { 11218c2ecf20Sopenharmony_ci loff_t start = rpages[i]->index << PAGE_SHIFT; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (from <= start) { 11248c2ecf20Sopenharmony_ci zero_user_segment(rpages[i], 0, PAGE_SIZE); 11258c2ecf20Sopenharmony_ci } else { 11268c2ecf20Sopenharmony_ci zero_user_segment(rpages[i], from - start, 11278c2ecf20Sopenharmony_ci PAGE_SIZE); 11288c2ecf20Sopenharmony_ci break; 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci f2fs_compress_write_end(inode, fsdata, start_idx, true); 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci return 0; 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic int f2fs_write_compressed_pages(struct compress_ctx *cc, 11388c2ecf20Sopenharmony_ci int *submitted, 11398c2ecf20Sopenharmony_ci struct writeback_control *wbc, 11408c2ecf20Sopenharmony_ci enum iostat_type io_type) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci struct inode *inode = cc->inode; 11438c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 11448c2ecf20Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 11458c2ecf20Sopenharmony_ci struct f2fs_io_info fio = { 11468c2ecf20Sopenharmony_ci .sbi = sbi, 11478c2ecf20Sopenharmony_ci .ino = cc->inode->i_ino, 11488c2ecf20Sopenharmony_ci .type = DATA, 11498c2ecf20Sopenharmony_ci .op = REQ_OP_WRITE, 11508c2ecf20Sopenharmony_ci .op_flags = wbc_to_write_flags(wbc), 11518c2ecf20Sopenharmony_ci .old_blkaddr = NEW_ADDR, 11528c2ecf20Sopenharmony_ci .page = NULL, 11538c2ecf20Sopenharmony_ci .encrypted_page = NULL, 11548c2ecf20Sopenharmony_ci .compressed_page = NULL, 11558c2ecf20Sopenharmony_ci .submitted = false, 11568c2ecf20Sopenharmony_ci .io_type = io_type, 11578c2ecf20Sopenharmony_ci .io_wbc = wbc, 11588c2ecf20Sopenharmony_ci .encrypted = fscrypt_inode_uses_fs_layer_crypto(cc->inode), 11598c2ecf20Sopenharmony_ci }; 11608c2ecf20Sopenharmony_ci struct dnode_of_data dn; 11618c2ecf20Sopenharmony_ci struct node_info ni; 11628c2ecf20Sopenharmony_ci struct compress_io_ctx *cic; 11638c2ecf20Sopenharmony_ci pgoff_t start_idx = start_idx_of_cluster(cc); 11648c2ecf20Sopenharmony_ci unsigned int last_index = cc->cluster_size - 1; 11658c2ecf20Sopenharmony_ci loff_t psize; 11668c2ecf20Sopenharmony_ci int i, err; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (IS_NOQUOTA(inode)) { 11698c2ecf20Sopenharmony_ci /* 11708c2ecf20Sopenharmony_ci * We need to wait for node_write to avoid block allocation during 11718c2ecf20Sopenharmony_ci * checkpoint. This can only happen to quota writes which can cause 11728c2ecf20Sopenharmony_ci * the below discard race condition. 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_ci down_read(&sbi->node_write); 11758c2ecf20Sopenharmony_ci } else if (!f2fs_trylock_op(sbi)) { 11768c2ecf20Sopenharmony_ci goto out_free; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci set_new_dnode(&dn, cc->inode, NULL, NULL, 0); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci err = f2fs_get_dnode_of_data(&dn, start_idx, LOOKUP_NODE); 11828c2ecf20Sopenharmony_ci if (err) 11838c2ecf20Sopenharmony_ci goto out_unlock_op; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 11868c2ecf20Sopenharmony_ci if (data_blkaddr(dn.inode, dn.node_page, 11878c2ecf20Sopenharmony_ci dn.ofs_in_node + i) == NULL_ADDR) 11888c2ecf20Sopenharmony_ci goto out_put_dnode; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci psize = (loff_t)(cc->rpages[last_index]->index + 1) << PAGE_SHIFT; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci err = f2fs_get_node_info(fio.sbi, dn.nid, &ni); 11948c2ecf20Sopenharmony_ci if (err) 11958c2ecf20Sopenharmony_ci goto out_put_dnode; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci fio.version = ni.version; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci cic = kmem_cache_zalloc(cic_entry_slab, GFP_NOFS); 12008c2ecf20Sopenharmony_ci if (!cic) 12018c2ecf20Sopenharmony_ci goto out_put_dnode; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci cic->magic = F2FS_COMPRESSED_PAGE_MAGIC; 12048c2ecf20Sopenharmony_ci cic->inode = inode; 12058c2ecf20Sopenharmony_ci atomic_set(&cic->pending_pages, cc->nr_cpages); 12068c2ecf20Sopenharmony_ci cic->rpages = page_array_alloc(cc->inode, cc->cluster_size); 12078c2ecf20Sopenharmony_ci if (!cic->rpages) 12088c2ecf20Sopenharmony_ci goto out_put_cic; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci cic->nr_rpages = cc->cluster_size; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci for (i = 0; i < cc->nr_cpages; i++) { 12138c2ecf20Sopenharmony_ci f2fs_set_compressed_page(cc->cpages[i], inode, 12148c2ecf20Sopenharmony_ci cc->rpages[i + 1]->index, cic); 12158c2ecf20Sopenharmony_ci fio.compressed_page = cc->cpages[i]; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci fio.old_blkaddr = data_blkaddr(dn.inode, dn.node_page, 12188c2ecf20Sopenharmony_ci dn.ofs_in_node + i + 1); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci /* wait for GCed page writeback via META_MAPPING */ 12218c2ecf20Sopenharmony_ci f2fs_wait_on_block_writeback(inode, fio.old_blkaddr); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci if (fio.encrypted) { 12248c2ecf20Sopenharmony_ci fio.page = cc->rpages[i + 1]; 12258c2ecf20Sopenharmony_ci err = f2fs_encrypt_one_page(&fio); 12268c2ecf20Sopenharmony_ci if (err) 12278c2ecf20Sopenharmony_ci goto out_destroy_crypt; 12288c2ecf20Sopenharmony_ci cc->cpages[i] = fio.encrypted_page; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci set_cluster_writeback(cc); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) 12358c2ecf20Sopenharmony_ci cic->rpages[i] = cc->rpages[i]; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++, dn.ofs_in_node++) { 12388c2ecf20Sopenharmony_ci block_t blkaddr; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci blkaddr = f2fs_data_blkaddr(&dn); 12418c2ecf20Sopenharmony_ci fio.page = cc->rpages[i]; 12428c2ecf20Sopenharmony_ci fio.old_blkaddr = blkaddr; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci /* cluster header */ 12458c2ecf20Sopenharmony_ci if (i == 0) { 12468c2ecf20Sopenharmony_ci if (blkaddr == COMPRESS_ADDR) 12478c2ecf20Sopenharmony_ci fio.compr_blocks++; 12488c2ecf20Sopenharmony_ci if (__is_valid_data_blkaddr(blkaddr)) 12498c2ecf20Sopenharmony_ci f2fs_invalidate_blocks(sbi, blkaddr); 12508c2ecf20Sopenharmony_ci f2fs_update_data_blkaddr(&dn, COMPRESS_ADDR); 12518c2ecf20Sopenharmony_ci goto unlock_continue; 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (fio.compr_blocks && __is_valid_data_blkaddr(blkaddr)) 12558c2ecf20Sopenharmony_ci fio.compr_blocks++; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci if (i > cc->nr_cpages) { 12588c2ecf20Sopenharmony_ci if (__is_valid_data_blkaddr(blkaddr)) { 12598c2ecf20Sopenharmony_ci f2fs_invalidate_blocks(sbi, blkaddr); 12608c2ecf20Sopenharmony_ci f2fs_update_data_blkaddr(&dn, NEW_ADDR); 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci goto unlock_continue; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci f2fs_bug_on(fio.sbi, blkaddr == NULL_ADDR); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (fio.encrypted) 12688c2ecf20Sopenharmony_ci fio.encrypted_page = cc->cpages[i - 1]; 12698c2ecf20Sopenharmony_ci else 12708c2ecf20Sopenharmony_ci fio.compressed_page = cc->cpages[i - 1]; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci cc->cpages[i - 1] = NULL; 12738c2ecf20Sopenharmony_ci f2fs_outplace_write_data(&dn, &fio); 12748c2ecf20Sopenharmony_ci (*submitted)++; 12758c2ecf20Sopenharmony_ciunlock_continue: 12768c2ecf20Sopenharmony_ci inode_dec_dirty_pages(cc->inode); 12778c2ecf20Sopenharmony_ci unlock_page(fio.page); 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci if (fio.compr_blocks) 12818c2ecf20Sopenharmony_ci f2fs_i_compr_blocks_update(inode, fio.compr_blocks - 1, false); 12828c2ecf20Sopenharmony_ci f2fs_i_compr_blocks_update(inode, cc->nr_cpages, true); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci set_inode_flag(cc->inode, FI_APPEND_WRITE); 12858c2ecf20Sopenharmony_ci if (cc->cluster_idx == 0) 12868c2ecf20Sopenharmony_ci set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci f2fs_put_dnode(&dn); 12898c2ecf20Sopenharmony_ci if (IS_NOQUOTA(inode)) 12908c2ecf20Sopenharmony_ci up_read(&sbi->node_write); 12918c2ecf20Sopenharmony_ci else 12928c2ecf20Sopenharmony_ci f2fs_unlock_op(sbi); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci spin_lock(&fi->i_size_lock); 12958c2ecf20Sopenharmony_ci if (fi->last_disk_size < psize) 12968c2ecf20Sopenharmony_ci fi->last_disk_size = psize; 12978c2ecf20Sopenharmony_ci spin_unlock(&fi->i_size_lock); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci f2fs_put_rpages(cc); 13008c2ecf20Sopenharmony_ci page_array_free(cc->inode, cc->cpages, cc->nr_cpages); 13018c2ecf20Sopenharmony_ci cc->cpages = NULL; 13028c2ecf20Sopenharmony_ci f2fs_destroy_compress_ctx(cc, false); 13038c2ecf20Sopenharmony_ci return 0; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ciout_destroy_crypt: 13068c2ecf20Sopenharmony_ci page_array_free(cc->inode, cic->rpages, cc->cluster_size); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci for (--i; i >= 0; i--) 13098c2ecf20Sopenharmony_ci fscrypt_finalize_bounce_page(&cc->cpages[i]); 13108c2ecf20Sopenharmony_ciout_put_cic: 13118c2ecf20Sopenharmony_ci kmem_cache_free(cic_entry_slab, cic); 13128c2ecf20Sopenharmony_ciout_put_dnode: 13138c2ecf20Sopenharmony_ci f2fs_put_dnode(&dn); 13148c2ecf20Sopenharmony_ciout_unlock_op: 13158c2ecf20Sopenharmony_ci if (IS_NOQUOTA(inode)) 13168c2ecf20Sopenharmony_ci up_read(&sbi->node_write); 13178c2ecf20Sopenharmony_ci else 13188c2ecf20Sopenharmony_ci f2fs_unlock_op(sbi); 13198c2ecf20Sopenharmony_ciout_free: 13208c2ecf20Sopenharmony_ci for (i = 0; i < cc->nr_cpages; i++) { 13218c2ecf20Sopenharmony_ci if (!cc->cpages[i]) 13228c2ecf20Sopenharmony_ci continue; 13238c2ecf20Sopenharmony_ci f2fs_compress_free_page(cc->cpages[i]); 13248c2ecf20Sopenharmony_ci cc->cpages[i] = NULL; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci page_array_free(cc->inode, cc->cpages, cc->nr_cpages); 13278c2ecf20Sopenharmony_ci cc->cpages = NULL; 13288c2ecf20Sopenharmony_ci return -EAGAIN; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_civoid f2fs_compress_write_end_io(struct bio *bio, struct page *page) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci struct f2fs_sb_info *sbi = bio->bi_private; 13348c2ecf20Sopenharmony_ci struct compress_io_ctx *cic = 13358c2ecf20Sopenharmony_ci (struct compress_io_ctx *)page_private(page); 13368c2ecf20Sopenharmony_ci int i; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci if (unlikely(bio->bi_status)) 13398c2ecf20Sopenharmony_ci mapping_set_error(cic->inode->i_mapping, -EIO); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci f2fs_compress_free_page(page); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci dec_page_count(sbi, F2FS_WB_DATA); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci if (atomic_dec_return(&cic->pending_pages)) 13468c2ecf20Sopenharmony_ci return; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci for (i = 0; i < cic->nr_rpages; i++) { 13498c2ecf20Sopenharmony_ci WARN_ON(!cic->rpages[i]); 13508c2ecf20Sopenharmony_ci clear_cold_data(cic->rpages[i]); 13518c2ecf20Sopenharmony_ci end_page_writeback(cic->rpages[i]); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci page_array_free(cic->inode, cic->rpages, cic->nr_rpages); 13558c2ecf20Sopenharmony_ci kmem_cache_free(cic_entry_slab, cic); 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cistatic int f2fs_write_raw_pages(struct compress_ctx *cc, 13598c2ecf20Sopenharmony_ci int *submitted, 13608c2ecf20Sopenharmony_ci struct writeback_control *wbc, 13618c2ecf20Sopenharmony_ci enum iostat_type io_type) 13628c2ecf20Sopenharmony_ci{ 13638c2ecf20Sopenharmony_ci struct address_space *mapping = cc->inode->i_mapping; 13648c2ecf20Sopenharmony_ci int _submitted, compr_blocks, ret, i; 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci compr_blocks = f2fs_compressed_blocks(cc); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 13698c2ecf20Sopenharmony_ci if (!cc->rpages[i]) 13708c2ecf20Sopenharmony_ci continue; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci redirty_page_for_writepage(wbc, cc->rpages[i]); 13738c2ecf20Sopenharmony_ci unlock_page(cc->rpages[i]); 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (compr_blocks < 0) 13778c2ecf20Sopenharmony_ci return compr_blocks; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 13808c2ecf20Sopenharmony_ci if (!cc->rpages[i]) 13818c2ecf20Sopenharmony_ci continue; 13828c2ecf20Sopenharmony_ciretry_write: 13838c2ecf20Sopenharmony_ci lock_page(cc->rpages[i]); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci if (cc->rpages[i]->mapping != mapping) { 13868c2ecf20Sopenharmony_cicontinue_unlock: 13878c2ecf20Sopenharmony_ci unlock_page(cc->rpages[i]); 13888c2ecf20Sopenharmony_ci continue; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci if (!PageDirty(cc->rpages[i])) 13928c2ecf20Sopenharmony_ci goto continue_unlock; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (PageWriteback(cc->rpages[i])) { 13958c2ecf20Sopenharmony_ci if (wbc->sync_mode == WB_SYNC_NONE) 13968c2ecf20Sopenharmony_ci goto continue_unlock; 13978c2ecf20Sopenharmony_ci f2fs_wait_on_page_writeback(cc->rpages[i], DATA, true, true); 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (!clear_page_dirty_for_io(cc->rpages[i])) 14018c2ecf20Sopenharmony_ci goto continue_unlock; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci ret = f2fs_write_single_data_page(cc->rpages[i], &_submitted, 14048c2ecf20Sopenharmony_ci NULL, NULL, wbc, io_type, 14058c2ecf20Sopenharmony_ci compr_blocks, false); 14068c2ecf20Sopenharmony_ci if (ret) { 14078c2ecf20Sopenharmony_ci if (ret == AOP_WRITEPAGE_ACTIVATE) { 14088c2ecf20Sopenharmony_ci unlock_page(cc->rpages[i]); 14098c2ecf20Sopenharmony_ci ret = 0; 14108c2ecf20Sopenharmony_ci } else if (ret == -EAGAIN) { 14118c2ecf20Sopenharmony_ci /* 14128c2ecf20Sopenharmony_ci * for quota file, just redirty left pages to 14138c2ecf20Sopenharmony_ci * avoid deadlock caused by cluster update race 14148c2ecf20Sopenharmony_ci * from foreground operation. 14158c2ecf20Sopenharmony_ci */ 14168c2ecf20Sopenharmony_ci if (IS_NOQUOTA(cc->inode)) 14178c2ecf20Sopenharmony_ci return 0; 14188c2ecf20Sopenharmony_ci ret = 0; 14198c2ecf20Sopenharmony_ci cond_resched(); 14208c2ecf20Sopenharmony_ci congestion_wait(BLK_RW_ASYNC, 14218c2ecf20Sopenharmony_ci DEFAULT_IO_TIMEOUT); 14228c2ecf20Sopenharmony_ci goto retry_write; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci return ret; 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci *submitted += _submitted; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci f2fs_balance_fs(F2FS_M_SB(mapping), true); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci return 0; 14338c2ecf20Sopenharmony_ci} 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ciint f2fs_write_multi_pages(struct compress_ctx *cc, 14368c2ecf20Sopenharmony_ci int *submitted, 14378c2ecf20Sopenharmony_ci struct writeback_control *wbc, 14388c2ecf20Sopenharmony_ci enum iostat_type io_type) 14398c2ecf20Sopenharmony_ci{ 14408c2ecf20Sopenharmony_ci int err; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci *submitted = 0; 14438c2ecf20Sopenharmony_ci if (cluster_may_compress(cc)) { 14448c2ecf20Sopenharmony_ci err = f2fs_compress_pages(cc); 14458c2ecf20Sopenharmony_ci if (err == -EAGAIN) { 14468c2ecf20Sopenharmony_ci goto write; 14478c2ecf20Sopenharmony_ci } else if (err) { 14488c2ecf20Sopenharmony_ci f2fs_put_rpages_wbc(cc, wbc, true, 1); 14498c2ecf20Sopenharmony_ci goto destroy_out; 14508c2ecf20Sopenharmony_ci } 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci err = f2fs_write_compressed_pages(cc, submitted, 14538c2ecf20Sopenharmony_ci wbc, io_type); 14548c2ecf20Sopenharmony_ci if (!err) 14558c2ecf20Sopenharmony_ci return 0; 14568c2ecf20Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(cc->inode), err != -EAGAIN); 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ciwrite: 14598c2ecf20Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(cc->inode), *submitted); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci err = f2fs_write_raw_pages(cc, submitted, wbc, io_type); 14628c2ecf20Sopenharmony_ci f2fs_put_rpages_wbc(cc, wbc, false, 0); 14638c2ecf20Sopenharmony_cidestroy_out: 14648c2ecf20Sopenharmony_ci f2fs_destroy_compress_ctx(cc, false); 14658c2ecf20Sopenharmony_ci return err; 14668c2ecf20Sopenharmony_ci} 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_cistruct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc) 14698c2ecf20Sopenharmony_ci{ 14708c2ecf20Sopenharmony_ci struct decompress_io_ctx *dic; 14718c2ecf20Sopenharmony_ci pgoff_t start_idx = start_idx_of_cluster(cc); 14728c2ecf20Sopenharmony_ci int i; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci dic = kmem_cache_zalloc(dic_entry_slab, GFP_NOFS); 14758c2ecf20Sopenharmony_ci if (!dic) 14768c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci dic->rpages = page_array_alloc(cc->inode, cc->cluster_size); 14798c2ecf20Sopenharmony_ci if (!dic->rpages) { 14808c2ecf20Sopenharmony_ci kmem_cache_free(dic_entry_slab, dic); 14818c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci dic->magic = F2FS_COMPRESSED_PAGE_MAGIC; 14858c2ecf20Sopenharmony_ci dic->inode = cc->inode; 14868c2ecf20Sopenharmony_ci atomic_set(&dic->pending_pages, cc->nr_cpages); 14878c2ecf20Sopenharmony_ci dic->cluster_idx = cc->cluster_idx; 14888c2ecf20Sopenharmony_ci dic->cluster_size = cc->cluster_size; 14898c2ecf20Sopenharmony_ci dic->log_cluster_size = cc->log_cluster_size; 14908c2ecf20Sopenharmony_ci dic->nr_cpages = cc->nr_cpages; 14918c2ecf20Sopenharmony_ci dic->failed = false; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci for (i = 0; i < dic->cluster_size; i++) 14948c2ecf20Sopenharmony_ci dic->rpages[i] = cc->rpages[i]; 14958c2ecf20Sopenharmony_ci dic->nr_rpages = cc->cluster_size; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci dic->cpages = page_array_alloc(dic->inode, dic->nr_cpages); 14988c2ecf20Sopenharmony_ci if (!dic->cpages) 14998c2ecf20Sopenharmony_ci goto out_free; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci for (i = 0; i < dic->nr_cpages; i++) { 15028c2ecf20Sopenharmony_ci struct page *page; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci page = f2fs_compress_alloc_page(); 15058c2ecf20Sopenharmony_ci if (!page) 15068c2ecf20Sopenharmony_ci goto out_free; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci f2fs_set_compressed_page(page, cc->inode, 15098c2ecf20Sopenharmony_ci start_idx + i + 1, dic); 15108c2ecf20Sopenharmony_ci dic->cpages[i] = page; 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci return dic; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ciout_free: 15168c2ecf20Sopenharmony_ci f2fs_free_dic(dic); 15178c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 15188c2ecf20Sopenharmony_ci} 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_civoid f2fs_free_dic(struct decompress_io_ctx *dic) 15218c2ecf20Sopenharmony_ci{ 15228c2ecf20Sopenharmony_ci int i; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci if (dic->tpages) { 15258c2ecf20Sopenharmony_ci for (i = 0; i < dic->cluster_size; i++) { 15268c2ecf20Sopenharmony_ci if (dic->rpages[i]) 15278c2ecf20Sopenharmony_ci continue; 15288c2ecf20Sopenharmony_ci if (!dic->tpages[i]) 15298c2ecf20Sopenharmony_ci continue; 15308c2ecf20Sopenharmony_ci f2fs_compress_free_page(dic->tpages[i]); 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci page_array_free(dic->inode, dic->tpages, dic->cluster_size); 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (dic->cpages) { 15368c2ecf20Sopenharmony_ci for (i = 0; i < dic->nr_cpages; i++) { 15378c2ecf20Sopenharmony_ci if (!dic->cpages[i]) 15388c2ecf20Sopenharmony_ci continue; 15398c2ecf20Sopenharmony_ci f2fs_compress_free_page(dic->cpages[i]); 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci page_array_free(dic->inode, dic->cpages, dic->nr_cpages); 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci page_array_free(dic->inode, dic->rpages, dic->nr_rpages); 15458c2ecf20Sopenharmony_ci kmem_cache_free(dic_entry_slab, dic); 15468c2ecf20Sopenharmony_ci} 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_civoid f2fs_decompress_end_io(struct page **rpages, 15498c2ecf20Sopenharmony_ci unsigned int cluster_size, bool err, bool verity) 15508c2ecf20Sopenharmony_ci{ 15518c2ecf20Sopenharmony_ci int i; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci for (i = 0; i < cluster_size; i++) { 15548c2ecf20Sopenharmony_ci struct page *rpage = rpages[i]; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (!rpage) 15578c2ecf20Sopenharmony_ci continue; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci if (err || PageError(rpage)) 15608c2ecf20Sopenharmony_ci goto clear_uptodate; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci if (!verity || fsverity_verify_page(rpage)) { 15638c2ecf20Sopenharmony_ci SetPageUptodate(rpage); 15648c2ecf20Sopenharmony_ci goto unlock; 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ciclear_uptodate: 15678c2ecf20Sopenharmony_ci ClearPageUptodate(rpage); 15688c2ecf20Sopenharmony_ci ClearPageError(rpage); 15698c2ecf20Sopenharmony_ciunlock: 15708c2ecf20Sopenharmony_ci unlock_page(rpage); 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci} 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ciint f2fs_init_page_array_cache(struct f2fs_sb_info *sbi) 15758c2ecf20Sopenharmony_ci{ 15768c2ecf20Sopenharmony_ci dev_t dev = sbi->sb->s_bdev->bd_dev; 15778c2ecf20Sopenharmony_ci char slab_name[35]; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci sprintf(slab_name, "f2fs_page_array_entry-%u:%u", MAJOR(dev), MINOR(dev)); 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci sbi->page_array_slab_size = sizeof(struct page *) << 15828c2ecf20Sopenharmony_ci F2FS_OPTION(sbi).compress_log_size; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci sbi->page_array_slab = f2fs_kmem_cache_create(slab_name, 15858c2ecf20Sopenharmony_ci sbi->page_array_slab_size); 15868c2ecf20Sopenharmony_ci if (!sbi->page_array_slab) 15878c2ecf20Sopenharmony_ci return -ENOMEM; 15888c2ecf20Sopenharmony_ci return 0; 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_civoid f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci kmem_cache_destroy(sbi->page_array_slab); 15948c2ecf20Sopenharmony_ci} 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_cistatic int __init f2fs_init_cic_cache(void) 15978c2ecf20Sopenharmony_ci{ 15988c2ecf20Sopenharmony_ci cic_entry_slab = f2fs_kmem_cache_create("f2fs_cic_entry", 15998c2ecf20Sopenharmony_ci sizeof(struct compress_io_ctx)); 16008c2ecf20Sopenharmony_ci if (!cic_entry_slab) 16018c2ecf20Sopenharmony_ci return -ENOMEM; 16028c2ecf20Sopenharmony_ci return 0; 16038c2ecf20Sopenharmony_ci} 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_cistatic void f2fs_destroy_cic_cache(void) 16068c2ecf20Sopenharmony_ci{ 16078c2ecf20Sopenharmony_ci kmem_cache_destroy(cic_entry_slab); 16088c2ecf20Sopenharmony_ci} 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cistatic int __init f2fs_init_dic_cache(void) 16118c2ecf20Sopenharmony_ci{ 16128c2ecf20Sopenharmony_ci dic_entry_slab = f2fs_kmem_cache_create("f2fs_dic_entry", 16138c2ecf20Sopenharmony_ci sizeof(struct decompress_io_ctx)); 16148c2ecf20Sopenharmony_ci if (!dic_entry_slab) 16158c2ecf20Sopenharmony_ci return -ENOMEM; 16168c2ecf20Sopenharmony_ci return 0; 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cistatic void f2fs_destroy_dic_cache(void) 16208c2ecf20Sopenharmony_ci{ 16218c2ecf20Sopenharmony_ci kmem_cache_destroy(dic_entry_slab); 16228c2ecf20Sopenharmony_ci} 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ciint __init f2fs_init_compress_cache(void) 16258c2ecf20Sopenharmony_ci{ 16268c2ecf20Sopenharmony_ci int err; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci err = f2fs_init_cic_cache(); 16298c2ecf20Sopenharmony_ci if (err) 16308c2ecf20Sopenharmony_ci goto out; 16318c2ecf20Sopenharmony_ci err = f2fs_init_dic_cache(); 16328c2ecf20Sopenharmony_ci if (err) 16338c2ecf20Sopenharmony_ci goto free_cic; 16348c2ecf20Sopenharmony_ci return 0; 16358c2ecf20Sopenharmony_cifree_cic: 16368c2ecf20Sopenharmony_ci f2fs_destroy_cic_cache(); 16378c2ecf20Sopenharmony_ciout: 16388c2ecf20Sopenharmony_ci return -ENOMEM; 16398c2ecf20Sopenharmony_ci} 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_civoid f2fs_destroy_compress_cache(void) 16428c2ecf20Sopenharmony_ci{ 16438c2ecf20Sopenharmony_ci f2fs_destroy_dic_cache(); 16448c2ecf20Sopenharmony_ci f2fs_destroy_cic_cache(); 16458c2ecf20Sopenharmony_ci} 1646