162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * f2fs compress support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2019 Chao Yu <chao@kernel.org> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/fs.h> 962306a36Sopenharmony_ci#include <linux/f2fs_fs.h> 1062306a36Sopenharmony_ci#include <linux/moduleparam.h> 1162306a36Sopenharmony_ci#include <linux/writeback.h> 1262306a36Sopenharmony_ci#include <linux/backing-dev.h> 1362306a36Sopenharmony_ci#include <linux/lzo.h> 1462306a36Sopenharmony_ci#include <linux/lz4.h> 1562306a36Sopenharmony_ci#include <linux/zstd.h> 1662306a36Sopenharmony_ci#include <linux/pagevec.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "f2fs.h" 1962306a36Sopenharmony_ci#include "node.h" 2062306a36Sopenharmony_ci#include "segment.h" 2162306a36Sopenharmony_ci#include <trace/events/f2fs.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic struct kmem_cache *cic_entry_slab; 2462306a36Sopenharmony_cistatic struct kmem_cache *dic_entry_slab; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic void *page_array_alloc(struct inode *inode, int nr) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 2962306a36Sopenharmony_ci unsigned int size = sizeof(struct page *) * nr; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci if (likely(size <= sbi->page_array_slab_size)) 3262306a36Sopenharmony_ci return f2fs_kmem_cache_alloc(sbi->page_array_slab, 3362306a36Sopenharmony_ci GFP_F2FS_ZERO, false, F2FS_I_SB(inode)); 3462306a36Sopenharmony_ci return f2fs_kzalloc(sbi, size, GFP_NOFS); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic void page_array_free(struct inode *inode, void *pages, int nr) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 4062306a36Sopenharmony_ci unsigned int size = sizeof(struct page *) * nr; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (!pages) 4362306a36Sopenharmony_ci return; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (likely(size <= sbi->page_array_slab_size)) 4662306a36Sopenharmony_ci kmem_cache_free(sbi->page_array_slab, pages); 4762306a36Sopenharmony_ci else 4862306a36Sopenharmony_ci kfree(pages); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct f2fs_compress_ops { 5262306a36Sopenharmony_ci int (*init_compress_ctx)(struct compress_ctx *cc); 5362306a36Sopenharmony_ci void (*destroy_compress_ctx)(struct compress_ctx *cc); 5462306a36Sopenharmony_ci int (*compress_pages)(struct compress_ctx *cc); 5562306a36Sopenharmony_ci int (*init_decompress_ctx)(struct decompress_io_ctx *dic); 5662306a36Sopenharmony_ci void (*destroy_decompress_ctx)(struct decompress_io_ctx *dic); 5762306a36Sopenharmony_ci int (*decompress_pages)(struct decompress_io_ctx *dic); 5862306a36Sopenharmony_ci bool (*is_level_valid)(int level); 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic unsigned int offset_in_cluster(struct compress_ctx *cc, pgoff_t index) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci return index & (cc->cluster_size - 1); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic pgoff_t cluster_idx(struct compress_ctx *cc, pgoff_t index) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci return index >> cc->log_cluster_size; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic pgoff_t start_idx_of_cluster(struct compress_ctx *cc) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci return cc->cluster_idx << cc->log_cluster_size; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cibool f2fs_is_compressed_page(struct page *page) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci if (!PagePrivate(page)) 7962306a36Sopenharmony_ci return false; 8062306a36Sopenharmony_ci if (!page_private(page)) 8162306a36Sopenharmony_ci return false; 8262306a36Sopenharmony_ci if (page_private_nonpointer(page)) 8362306a36Sopenharmony_ci return false; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci f2fs_bug_on(F2FS_M_SB(page->mapping), 8662306a36Sopenharmony_ci *((u32 *)page_private(page)) != F2FS_COMPRESSED_PAGE_MAGIC); 8762306a36Sopenharmony_ci return true; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic void f2fs_set_compressed_page(struct page *page, 9162306a36Sopenharmony_ci struct inode *inode, pgoff_t index, void *data) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci attach_page_private(page, (void *)data); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* i_crypto_info and iv index */ 9662306a36Sopenharmony_ci page->index = index; 9762306a36Sopenharmony_ci page->mapping = inode->i_mapping; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic void f2fs_drop_rpages(struct compress_ctx *cc, int len, bool unlock) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci int i; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci for (i = 0; i < len; i++) { 10562306a36Sopenharmony_ci if (!cc->rpages[i]) 10662306a36Sopenharmony_ci continue; 10762306a36Sopenharmony_ci if (unlock) 10862306a36Sopenharmony_ci unlock_page(cc->rpages[i]); 10962306a36Sopenharmony_ci else 11062306a36Sopenharmony_ci put_page(cc->rpages[i]); 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic void f2fs_put_rpages(struct compress_ctx *cc) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci f2fs_drop_rpages(cc, cc->cluster_size, false); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic void f2fs_unlock_rpages(struct compress_ctx *cc, int len) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci f2fs_drop_rpages(cc, len, true); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void f2fs_put_rpages_wbc(struct compress_ctx *cc, 12562306a36Sopenharmony_ci struct writeback_control *wbc, bool redirty, int unlock) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci unsigned int i; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 13062306a36Sopenharmony_ci if (!cc->rpages[i]) 13162306a36Sopenharmony_ci continue; 13262306a36Sopenharmony_ci if (redirty) 13362306a36Sopenharmony_ci redirty_page_for_writepage(wbc, cc->rpages[i]); 13462306a36Sopenharmony_ci f2fs_put_page(cc->rpages[i], unlock); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistruct page *f2fs_compress_control_page(struct page *page) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci return ((struct compress_io_ctx *)page_private(page))->rpages[0]; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ciint f2fs_init_compress_ctx(struct compress_ctx *cc) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci if (cc->rpages) 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci cc->rpages = page_array_alloc(cc->inode, cc->cluster_size); 14962306a36Sopenharmony_ci return cc->rpages ? 0 : -ENOMEM; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_civoid f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci page_array_free(cc->inode, cc->rpages, cc->cluster_size); 15562306a36Sopenharmony_ci cc->rpages = NULL; 15662306a36Sopenharmony_ci cc->nr_rpages = 0; 15762306a36Sopenharmony_ci cc->nr_cpages = 0; 15862306a36Sopenharmony_ci cc->valid_nr_cpages = 0; 15962306a36Sopenharmony_ci if (!reuse) 16062306a36Sopenharmony_ci cc->cluster_idx = NULL_CLUSTER; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_civoid f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci unsigned int cluster_ofs; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (!f2fs_cluster_can_merge_page(cc, page->index)) 16862306a36Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(cc->inode), 1); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci cluster_ofs = offset_in_cluster(cc, page->index); 17162306a36Sopenharmony_ci cc->rpages[cluster_ofs] = page; 17262306a36Sopenharmony_ci cc->nr_rpages++; 17362306a36Sopenharmony_ci cc->cluster_idx = cluster_idx(cc, page->index); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZO 17762306a36Sopenharmony_cistatic int lzo_init_compress_ctx(struct compress_ctx *cc) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci cc->private = f2fs_kvmalloc(F2FS_I_SB(cc->inode), 18062306a36Sopenharmony_ci LZO1X_MEM_COMPRESS, GFP_NOFS); 18162306a36Sopenharmony_ci if (!cc->private) 18262306a36Sopenharmony_ci return -ENOMEM; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci cc->clen = lzo1x_worst_compress(PAGE_SIZE << cc->log_cluster_size); 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void lzo_destroy_compress_ctx(struct compress_ctx *cc) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci kvfree(cc->private); 19162306a36Sopenharmony_ci cc->private = NULL; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int lzo_compress_pages(struct compress_ctx *cc) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci int ret; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci ret = lzo1x_1_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata, 19962306a36Sopenharmony_ci &cc->clen, cc->private); 20062306a36Sopenharmony_ci if (ret != LZO_E_OK) { 20162306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lzo compress failed, ret:%d\n", 20262306a36Sopenharmony_ci KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ret); 20362306a36Sopenharmony_ci return -EIO; 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic int lzo_decompress_pages(struct decompress_io_ctx *dic) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci int ret; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci ret = lzo1x_decompress_safe(dic->cbuf->cdata, dic->clen, 21362306a36Sopenharmony_ci dic->rbuf, &dic->rlen); 21462306a36Sopenharmony_ci if (ret != LZO_E_OK) { 21562306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lzo decompress failed, ret:%d\n", 21662306a36Sopenharmony_ci KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ret); 21762306a36Sopenharmony_ci return -EIO; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (dic->rlen != PAGE_SIZE << dic->log_cluster_size) { 22162306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lzo invalid rlen:%zu, " 22262306a36Sopenharmony_ci "expected:%lu\n", KERN_ERR, 22362306a36Sopenharmony_ci F2FS_I_SB(dic->inode)->sb->s_id, 22462306a36Sopenharmony_ci dic->rlen, 22562306a36Sopenharmony_ci PAGE_SIZE << dic->log_cluster_size); 22662306a36Sopenharmony_ci return -EIO; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic const struct f2fs_compress_ops f2fs_lzo_ops = { 23262306a36Sopenharmony_ci .init_compress_ctx = lzo_init_compress_ctx, 23362306a36Sopenharmony_ci .destroy_compress_ctx = lzo_destroy_compress_ctx, 23462306a36Sopenharmony_ci .compress_pages = lzo_compress_pages, 23562306a36Sopenharmony_ci .decompress_pages = lzo_decompress_pages, 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_ci#endif 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZ4 24062306a36Sopenharmony_cistatic int lz4_init_compress_ctx(struct compress_ctx *cc) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci unsigned int size = LZ4_MEM_COMPRESS; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZ4HC 24562306a36Sopenharmony_ci if (F2FS_I(cc->inode)->i_compress_level) 24662306a36Sopenharmony_ci size = LZ4HC_MEM_COMPRESS; 24762306a36Sopenharmony_ci#endif 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci cc->private = f2fs_kvmalloc(F2FS_I_SB(cc->inode), size, GFP_NOFS); 25062306a36Sopenharmony_ci if (!cc->private) 25162306a36Sopenharmony_ci return -ENOMEM; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * we do not change cc->clen to LZ4_compressBound(inputsize) to 25562306a36Sopenharmony_ci * adapt worst compress case, because lz4 compressor can handle 25662306a36Sopenharmony_ci * output budget properly. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci cc->clen = cc->rlen - PAGE_SIZE - COMPRESS_HEADER_SIZE; 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void lz4_destroy_compress_ctx(struct compress_ctx *cc) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci kvfree(cc->private); 26562306a36Sopenharmony_ci cc->private = NULL; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int lz4_compress_pages(struct compress_ctx *cc) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci int len = -EINVAL; 27162306a36Sopenharmony_ci unsigned char level = F2FS_I(cc->inode)->i_compress_level; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (!level) 27462306a36Sopenharmony_ci len = LZ4_compress_default(cc->rbuf, cc->cbuf->cdata, cc->rlen, 27562306a36Sopenharmony_ci cc->clen, cc->private); 27662306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZ4HC 27762306a36Sopenharmony_ci else 27862306a36Sopenharmony_ci len = LZ4_compress_HC(cc->rbuf, cc->cbuf->cdata, cc->rlen, 27962306a36Sopenharmony_ci cc->clen, level, cc->private); 28062306a36Sopenharmony_ci#endif 28162306a36Sopenharmony_ci if (len < 0) 28262306a36Sopenharmony_ci return len; 28362306a36Sopenharmony_ci if (!len) 28462306a36Sopenharmony_ci return -EAGAIN; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci cc->clen = len; 28762306a36Sopenharmony_ci return 0; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic int lz4_decompress_pages(struct decompress_io_ctx *dic) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci int ret; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci ret = LZ4_decompress_safe(dic->cbuf->cdata, dic->rbuf, 29562306a36Sopenharmony_ci dic->clen, dic->rlen); 29662306a36Sopenharmony_ci if (ret < 0) { 29762306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lz4 decompress failed, ret:%d\n", 29862306a36Sopenharmony_ci KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ret); 29962306a36Sopenharmony_ci return -EIO; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (ret != PAGE_SIZE << dic->log_cluster_size) { 30362306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lz4 invalid ret:%d, " 30462306a36Sopenharmony_ci "expected:%lu\n", KERN_ERR, 30562306a36Sopenharmony_ci F2FS_I_SB(dic->inode)->sb->s_id, ret, 30662306a36Sopenharmony_ci PAGE_SIZE << dic->log_cluster_size); 30762306a36Sopenharmony_ci return -EIO; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci return 0; 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic bool lz4_is_level_valid(int lvl) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZ4HC 31562306a36Sopenharmony_ci return !lvl || (lvl >= LZ4HC_MIN_CLEVEL && lvl <= LZ4HC_MAX_CLEVEL); 31662306a36Sopenharmony_ci#else 31762306a36Sopenharmony_ci return lvl == 0; 31862306a36Sopenharmony_ci#endif 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic const struct f2fs_compress_ops f2fs_lz4_ops = { 32262306a36Sopenharmony_ci .init_compress_ctx = lz4_init_compress_ctx, 32362306a36Sopenharmony_ci .destroy_compress_ctx = lz4_destroy_compress_ctx, 32462306a36Sopenharmony_ci .compress_pages = lz4_compress_pages, 32562306a36Sopenharmony_ci .decompress_pages = lz4_decompress_pages, 32662306a36Sopenharmony_ci .is_level_valid = lz4_is_level_valid, 32762306a36Sopenharmony_ci}; 32862306a36Sopenharmony_ci#endif 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_ZSTD 33162306a36Sopenharmony_cistatic int zstd_init_compress_ctx(struct compress_ctx *cc) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci zstd_parameters params; 33462306a36Sopenharmony_ci zstd_cstream *stream; 33562306a36Sopenharmony_ci void *workspace; 33662306a36Sopenharmony_ci unsigned int workspace_size; 33762306a36Sopenharmony_ci unsigned char level = F2FS_I(cc->inode)->i_compress_level; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* Need to remain this for backward compatibility */ 34062306a36Sopenharmony_ci if (!level) 34162306a36Sopenharmony_ci level = F2FS_ZSTD_DEFAULT_CLEVEL; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci params = zstd_get_params(level, cc->rlen); 34462306a36Sopenharmony_ci workspace_size = zstd_cstream_workspace_bound(¶ms.cParams); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci workspace = f2fs_kvmalloc(F2FS_I_SB(cc->inode), 34762306a36Sopenharmony_ci workspace_size, GFP_NOFS); 34862306a36Sopenharmony_ci if (!workspace) 34962306a36Sopenharmony_ci return -ENOMEM; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci stream = zstd_init_cstream(¶ms, 0, workspace, workspace_size); 35262306a36Sopenharmony_ci if (!stream) { 35362306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s zstd_init_cstream failed\n", 35462306a36Sopenharmony_ci KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, 35562306a36Sopenharmony_ci __func__); 35662306a36Sopenharmony_ci kvfree(workspace); 35762306a36Sopenharmony_ci return -EIO; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci cc->private = workspace; 36162306a36Sopenharmony_ci cc->private2 = stream; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci cc->clen = cc->rlen - PAGE_SIZE - COMPRESS_HEADER_SIZE; 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic void zstd_destroy_compress_ctx(struct compress_ctx *cc) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci kvfree(cc->private); 37062306a36Sopenharmony_ci cc->private = NULL; 37162306a36Sopenharmony_ci cc->private2 = NULL; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic int zstd_compress_pages(struct compress_ctx *cc) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci zstd_cstream *stream = cc->private2; 37762306a36Sopenharmony_ci zstd_in_buffer inbuf; 37862306a36Sopenharmony_ci zstd_out_buffer outbuf; 37962306a36Sopenharmony_ci int src_size = cc->rlen; 38062306a36Sopenharmony_ci int dst_size = src_size - PAGE_SIZE - COMPRESS_HEADER_SIZE; 38162306a36Sopenharmony_ci int ret; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci inbuf.pos = 0; 38462306a36Sopenharmony_ci inbuf.src = cc->rbuf; 38562306a36Sopenharmony_ci inbuf.size = src_size; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci outbuf.pos = 0; 38862306a36Sopenharmony_ci outbuf.dst = cc->cbuf->cdata; 38962306a36Sopenharmony_ci outbuf.size = dst_size; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci ret = zstd_compress_stream(stream, &outbuf, &inbuf); 39262306a36Sopenharmony_ci if (zstd_is_error(ret)) { 39362306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s zstd_compress_stream failed, ret: %d\n", 39462306a36Sopenharmony_ci KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, 39562306a36Sopenharmony_ci __func__, zstd_get_error_code(ret)); 39662306a36Sopenharmony_ci return -EIO; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci ret = zstd_end_stream(stream, &outbuf); 40062306a36Sopenharmony_ci if (zstd_is_error(ret)) { 40162306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s zstd_end_stream returned %d\n", 40262306a36Sopenharmony_ci KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, 40362306a36Sopenharmony_ci __func__, zstd_get_error_code(ret)); 40462306a36Sopenharmony_ci return -EIO; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* 40862306a36Sopenharmony_ci * there is compressed data remained in intermediate buffer due to 40962306a36Sopenharmony_ci * no more space in cbuf.cdata 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_ci if (ret) 41262306a36Sopenharmony_ci return -EAGAIN; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci cc->clen = outbuf.pos; 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int zstd_init_decompress_ctx(struct decompress_io_ctx *dic) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci zstd_dstream *stream; 42162306a36Sopenharmony_ci void *workspace; 42262306a36Sopenharmony_ci unsigned int workspace_size; 42362306a36Sopenharmony_ci unsigned int max_window_size = 42462306a36Sopenharmony_ci MAX_COMPRESS_WINDOW_SIZE(dic->log_cluster_size); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci workspace_size = zstd_dstream_workspace_bound(max_window_size); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci workspace = f2fs_kvmalloc(F2FS_I_SB(dic->inode), 42962306a36Sopenharmony_ci workspace_size, GFP_NOFS); 43062306a36Sopenharmony_ci if (!workspace) 43162306a36Sopenharmony_ci return -ENOMEM; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci stream = zstd_init_dstream(max_window_size, workspace, workspace_size); 43462306a36Sopenharmony_ci if (!stream) { 43562306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s zstd_init_dstream failed\n", 43662306a36Sopenharmony_ci KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, 43762306a36Sopenharmony_ci __func__); 43862306a36Sopenharmony_ci kvfree(workspace); 43962306a36Sopenharmony_ci return -EIO; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci dic->private = workspace; 44362306a36Sopenharmony_ci dic->private2 = stream; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci return 0; 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic void zstd_destroy_decompress_ctx(struct decompress_io_ctx *dic) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci kvfree(dic->private); 45162306a36Sopenharmony_ci dic->private = NULL; 45262306a36Sopenharmony_ci dic->private2 = NULL; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic int zstd_decompress_pages(struct decompress_io_ctx *dic) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci zstd_dstream *stream = dic->private2; 45862306a36Sopenharmony_ci zstd_in_buffer inbuf; 45962306a36Sopenharmony_ci zstd_out_buffer outbuf; 46062306a36Sopenharmony_ci int ret; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci inbuf.pos = 0; 46362306a36Sopenharmony_ci inbuf.src = dic->cbuf->cdata; 46462306a36Sopenharmony_ci inbuf.size = dic->clen; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci outbuf.pos = 0; 46762306a36Sopenharmony_ci outbuf.dst = dic->rbuf; 46862306a36Sopenharmony_ci outbuf.size = dic->rlen; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci ret = zstd_decompress_stream(stream, &outbuf, &inbuf); 47162306a36Sopenharmony_ci if (zstd_is_error(ret)) { 47262306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s zstd_decompress_stream failed, ret: %d\n", 47362306a36Sopenharmony_ci KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, 47462306a36Sopenharmony_ci __func__, zstd_get_error_code(ret)); 47562306a36Sopenharmony_ci return -EIO; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (dic->rlen != outbuf.pos) { 47962306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): %s ZSTD invalid rlen:%zu, " 48062306a36Sopenharmony_ci "expected:%lu\n", KERN_ERR, 48162306a36Sopenharmony_ci F2FS_I_SB(dic->inode)->sb->s_id, 48262306a36Sopenharmony_ci __func__, dic->rlen, 48362306a36Sopenharmony_ci PAGE_SIZE << dic->log_cluster_size); 48462306a36Sopenharmony_ci return -EIO; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci return 0; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic bool zstd_is_level_valid(int lvl) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci return lvl >= zstd_min_clevel() && lvl <= zstd_max_clevel(); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic const struct f2fs_compress_ops f2fs_zstd_ops = { 49662306a36Sopenharmony_ci .init_compress_ctx = zstd_init_compress_ctx, 49762306a36Sopenharmony_ci .destroy_compress_ctx = zstd_destroy_compress_ctx, 49862306a36Sopenharmony_ci .compress_pages = zstd_compress_pages, 49962306a36Sopenharmony_ci .init_decompress_ctx = zstd_init_decompress_ctx, 50062306a36Sopenharmony_ci .destroy_decompress_ctx = zstd_destroy_decompress_ctx, 50162306a36Sopenharmony_ci .decompress_pages = zstd_decompress_pages, 50262306a36Sopenharmony_ci .is_level_valid = zstd_is_level_valid, 50362306a36Sopenharmony_ci}; 50462306a36Sopenharmony_ci#endif 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZO 50762306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZORLE 50862306a36Sopenharmony_cistatic int lzorle_compress_pages(struct compress_ctx *cc) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci int ret; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci ret = lzorle1x_1_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata, 51362306a36Sopenharmony_ci &cc->clen, cc->private); 51462306a36Sopenharmony_ci if (ret != LZO_E_OK) { 51562306a36Sopenharmony_ci printk_ratelimited("%sF2FS-fs (%s): lzo-rle compress failed, ret:%d\n", 51662306a36Sopenharmony_ci KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ret); 51762306a36Sopenharmony_ci return -EIO; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci return 0; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic const struct f2fs_compress_ops f2fs_lzorle_ops = { 52362306a36Sopenharmony_ci .init_compress_ctx = lzo_init_compress_ctx, 52462306a36Sopenharmony_ci .destroy_compress_ctx = lzo_destroy_compress_ctx, 52562306a36Sopenharmony_ci .compress_pages = lzorle_compress_pages, 52662306a36Sopenharmony_ci .decompress_pages = lzo_decompress_pages, 52762306a36Sopenharmony_ci}; 52862306a36Sopenharmony_ci#endif 52962306a36Sopenharmony_ci#endif 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = { 53262306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZO 53362306a36Sopenharmony_ci &f2fs_lzo_ops, 53462306a36Sopenharmony_ci#else 53562306a36Sopenharmony_ci NULL, 53662306a36Sopenharmony_ci#endif 53762306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_LZ4 53862306a36Sopenharmony_ci &f2fs_lz4_ops, 53962306a36Sopenharmony_ci#else 54062306a36Sopenharmony_ci NULL, 54162306a36Sopenharmony_ci#endif 54262306a36Sopenharmony_ci#ifdef CONFIG_F2FS_FS_ZSTD 54362306a36Sopenharmony_ci &f2fs_zstd_ops, 54462306a36Sopenharmony_ci#else 54562306a36Sopenharmony_ci NULL, 54662306a36Sopenharmony_ci#endif 54762306a36Sopenharmony_ci#if defined(CONFIG_F2FS_FS_LZO) && defined(CONFIG_F2FS_FS_LZORLE) 54862306a36Sopenharmony_ci &f2fs_lzorle_ops, 54962306a36Sopenharmony_ci#else 55062306a36Sopenharmony_ci NULL, 55162306a36Sopenharmony_ci#endif 55262306a36Sopenharmony_ci}; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cibool f2fs_is_compress_backend_ready(struct inode *inode) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci if (!f2fs_compressed_file(inode)) 55762306a36Sopenharmony_ci return true; 55862306a36Sopenharmony_ci return f2fs_cops[F2FS_I(inode)->i_compress_algorithm]; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cibool f2fs_is_compress_level_valid(int alg, int lvl) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci const struct f2fs_compress_ops *cops = f2fs_cops[alg]; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (cops->is_level_valid) 56662306a36Sopenharmony_ci return cops->is_level_valid(lvl); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return lvl == 0; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic mempool_t *compress_page_pool; 57262306a36Sopenharmony_cistatic int num_compress_pages = 512; 57362306a36Sopenharmony_cimodule_param(num_compress_pages, uint, 0444); 57462306a36Sopenharmony_ciMODULE_PARM_DESC(num_compress_pages, 57562306a36Sopenharmony_ci "Number of intermediate compress pages to preallocate"); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ciint __init f2fs_init_compress_mempool(void) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci compress_page_pool = mempool_create_page_pool(num_compress_pages, 0); 58062306a36Sopenharmony_ci return compress_page_pool ? 0 : -ENOMEM; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_civoid f2fs_destroy_compress_mempool(void) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci mempool_destroy(compress_page_pool); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic struct page *f2fs_compress_alloc_page(void) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci struct page *page; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci page = mempool_alloc(compress_page_pool, GFP_NOFS); 59362306a36Sopenharmony_ci lock_page(page); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci return page; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic void f2fs_compress_free_page(struct page *page) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci if (!page) 60162306a36Sopenharmony_ci return; 60262306a36Sopenharmony_ci detach_page_private(page); 60362306a36Sopenharmony_ci page->mapping = NULL; 60462306a36Sopenharmony_ci unlock_page(page); 60562306a36Sopenharmony_ci mempool_free(page, compress_page_pool); 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci#define MAX_VMAP_RETRIES 3 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic void *f2fs_vmap(struct page **pages, unsigned int count) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci int i; 61362306a36Sopenharmony_ci void *buf = NULL; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci for (i = 0; i < MAX_VMAP_RETRIES; i++) { 61662306a36Sopenharmony_ci buf = vm_map_ram(pages, count, -1); 61762306a36Sopenharmony_ci if (buf) 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci vm_unmap_aliases(); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci return buf; 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic int f2fs_compress_pages(struct compress_ctx *cc) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(cc->inode); 62762306a36Sopenharmony_ci const struct f2fs_compress_ops *cops = 62862306a36Sopenharmony_ci f2fs_cops[fi->i_compress_algorithm]; 62962306a36Sopenharmony_ci unsigned int max_len, new_nr_cpages; 63062306a36Sopenharmony_ci u32 chksum = 0; 63162306a36Sopenharmony_ci int i, ret; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci trace_f2fs_compress_pages_start(cc->inode, cc->cluster_idx, 63462306a36Sopenharmony_ci cc->cluster_size, fi->i_compress_algorithm); 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (cops->init_compress_ctx) { 63762306a36Sopenharmony_ci ret = cops->init_compress_ctx(cc); 63862306a36Sopenharmony_ci if (ret) 63962306a36Sopenharmony_ci goto out; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci max_len = COMPRESS_HEADER_SIZE + cc->clen; 64362306a36Sopenharmony_ci cc->nr_cpages = DIV_ROUND_UP(max_len, PAGE_SIZE); 64462306a36Sopenharmony_ci cc->valid_nr_cpages = cc->nr_cpages; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci cc->cpages = page_array_alloc(cc->inode, cc->nr_cpages); 64762306a36Sopenharmony_ci if (!cc->cpages) { 64862306a36Sopenharmony_ci ret = -ENOMEM; 64962306a36Sopenharmony_ci goto destroy_compress_ctx; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci for (i = 0; i < cc->nr_cpages; i++) 65362306a36Sopenharmony_ci cc->cpages[i] = f2fs_compress_alloc_page(); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci cc->rbuf = f2fs_vmap(cc->rpages, cc->cluster_size); 65662306a36Sopenharmony_ci if (!cc->rbuf) { 65762306a36Sopenharmony_ci ret = -ENOMEM; 65862306a36Sopenharmony_ci goto out_free_cpages; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci cc->cbuf = f2fs_vmap(cc->cpages, cc->nr_cpages); 66262306a36Sopenharmony_ci if (!cc->cbuf) { 66362306a36Sopenharmony_ci ret = -ENOMEM; 66462306a36Sopenharmony_ci goto out_vunmap_rbuf; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci ret = cops->compress_pages(cc); 66862306a36Sopenharmony_ci if (ret) 66962306a36Sopenharmony_ci goto out_vunmap_cbuf; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci max_len = PAGE_SIZE * (cc->cluster_size - 1) - COMPRESS_HEADER_SIZE; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (cc->clen > max_len) { 67462306a36Sopenharmony_ci ret = -EAGAIN; 67562306a36Sopenharmony_ci goto out_vunmap_cbuf; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci cc->cbuf->clen = cpu_to_le32(cc->clen); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (fi->i_compress_flag & BIT(COMPRESS_CHKSUM)) 68162306a36Sopenharmony_ci chksum = f2fs_crc32(F2FS_I_SB(cc->inode), 68262306a36Sopenharmony_ci cc->cbuf->cdata, cc->clen); 68362306a36Sopenharmony_ci cc->cbuf->chksum = cpu_to_le32(chksum); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci for (i = 0; i < COMPRESS_DATA_RESERVED_SIZE; i++) 68662306a36Sopenharmony_ci cc->cbuf->reserved[i] = cpu_to_le32(0); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci new_nr_cpages = DIV_ROUND_UP(cc->clen + COMPRESS_HEADER_SIZE, PAGE_SIZE); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* zero out any unused part of the last page */ 69162306a36Sopenharmony_ci memset(&cc->cbuf->cdata[cc->clen], 0, 69262306a36Sopenharmony_ci (new_nr_cpages * PAGE_SIZE) - 69362306a36Sopenharmony_ci (cc->clen + COMPRESS_HEADER_SIZE)); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci vm_unmap_ram(cc->cbuf, cc->nr_cpages); 69662306a36Sopenharmony_ci vm_unmap_ram(cc->rbuf, cc->cluster_size); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci for (i = new_nr_cpages; i < cc->nr_cpages; i++) { 69962306a36Sopenharmony_ci f2fs_compress_free_page(cc->cpages[i]); 70062306a36Sopenharmony_ci cc->cpages[i] = NULL; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (cops->destroy_compress_ctx) 70462306a36Sopenharmony_ci cops->destroy_compress_ctx(cc); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci cc->valid_nr_cpages = new_nr_cpages; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci trace_f2fs_compress_pages_end(cc->inode, cc->cluster_idx, 70962306a36Sopenharmony_ci cc->clen, ret); 71062306a36Sopenharmony_ci return 0; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ciout_vunmap_cbuf: 71362306a36Sopenharmony_ci vm_unmap_ram(cc->cbuf, cc->nr_cpages); 71462306a36Sopenharmony_ciout_vunmap_rbuf: 71562306a36Sopenharmony_ci vm_unmap_ram(cc->rbuf, cc->cluster_size); 71662306a36Sopenharmony_ciout_free_cpages: 71762306a36Sopenharmony_ci for (i = 0; i < cc->nr_cpages; i++) { 71862306a36Sopenharmony_ci if (cc->cpages[i]) 71962306a36Sopenharmony_ci f2fs_compress_free_page(cc->cpages[i]); 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci page_array_free(cc->inode, cc->cpages, cc->nr_cpages); 72262306a36Sopenharmony_ci cc->cpages = NULL; 72362306a36Sopenharmony_cidestroy_compress_ctx: 72462306a36Sopenharmony_ci if (cops->destroy_compress_ctx) 72562306a36Sopenharmony_ci cops->destroy_compress_ctx(cc); 72662306a36Sopenharmony_ciout: 72762306a36Sopenharmony_ci trace_f2fs_compress_pages_end(cc->inode, cc->cluster_idx, 72862306a36Sopenharmony_ci cc->clen, ret); 72962306a36Sopenharmony_ci return ret; 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic int f2fs_prepare_decomp_mem(struct decompress_io_ctx *dic, 73362306a36Sopenharmony_ci bool pre_alloc); 73462306a36Sopenharmony_cistatic void f2fs_release_decomp_mem(struct decompress_io_ctx *dic, 73562306a36Sopenharmony_ci bool bypass_destroy_callback, bool pre_alloc); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_civoid f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); 74062306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(dic->inode); 74162306a36Sopenharmony_ci const struct f2fs_compress_ops *cops = 74262306a36Sopenharmony_ci f2fs_cops[fi->i_compress_algorithm]; 74362306a36Sopenharmony_ci bool bypass_callback = false; 74462306a36Sopenharmony_ci int ret; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci trace_f2fs_decompress_pages_start(dic->inode, dic->cluster_idx, 74762306a36Sopenharmony_ci dic->cluster_size, fi->i_compress_algorithm); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (dic->failed) { 75062306a36Sopenharmony_ci ret = -EIO; 75162306a36Sopenharmony_ci goto out_end_io; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = f2fs_prepare_decomp_mem(dic, false); 75562306a36Sopenharmony_ci if (ret) { 75662306a36Sopenharmony_ci bypass_callback = true; 75762306a36Sopenharmony_ci goto out_release; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci dic->clen = le32_to_cpu(dic->cbuf->clen); 76162306a36Sopenharmony_ci dic->rlen = PAGE_SIZE << dic->log_cluster_size; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci if (dic->clen > PAGE_SIZE * dic->nr_cpages - COMPRESS_HEADER_SIZE) { 76462306a36Sopenharmony_ci ret = -EFSCORRUPTED; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* Avoid f2fs_commit_super in irq context */ 76762306a36Sopenharmony_ci if (!in_task) 76862306a36Sopenharmony_ci f2fs_handle_error_async(sbi, ERROR_FAIL_DECOMPRESSION); 76962306a36Sopenharmony_ci else 77062306a36Sopenharmony_ci f2fs_handle_error(sbi, ERROR_FAIL_DECOMPRESSION); 77162306a36Sopenharmony_ci goto out_release; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci ret = cops->decompress_pages(dic); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (!ret && (fi->i_compress_flag & BIT(COMPRESS_CHKSUM))) { 77762306a36Sopenharmony_ci u32 provided = le32_to_cpu(dic->cbuf->chksum); 77862306a36Sopenharmony_ci u32 calculated = f2fs_crc32(sbi, dic->cbuf->cdata, dic->clen); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (provided != calculated) { 78162306a36Sopenharmony_ci if (!is_inode_flag_set(dic->inode, FI_COMPRESS_CORRUPT)) { 78262306a36Sopenharmony_ci set_inode_flag(dic->inode, FI_COMPRESS_CORRUPT); 78362306a36Sopenharmony_ci printk_ratelimited( 78462306a36Sopenharmony_ci "%sF2FS-fs (%s): checksum invalid, nid = %lu, %x vs %x", 78562306a36Sopenharmony_ci KERN_INFO, sbi->sb->s_id, dic->inode->i_ino, 78662306a36Sopenharmony_ci provided, calculated); 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ciout_release: 79362306a36Sopenharmony_ci f2fs_release_decomp_mem(dic, bypass_callback, false); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ciout_end_io: 79662306a36Sopenharmony_ci trace_f2fs_decompress_pages_end(dic->inode, dic->cluster_idx, 79762306a36Sopenharmony_ci dic->clen, ret); 79862306a36Sopenharmony_ci f2fs_decompress_end_io(dic, ret, in_task); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci/* 80262306a36Sopenharmony_ci * This is called when a page of a compressed cluster has been read from disk 80362306a36Sopenharmony_ci * (or failed to be read from disk). It checks whether this page was the last 80462306a36Sopenharmony_ci * page being waited on in the cluster, and if so, it decompresses the cluster 80562306a36Sopenharmony_ci * (or in the case of a failure, cleans up without actually decompressing). 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_civoid f2fs_end_read_compressed_page(struct page *page, bool failed, 80862306a36Sopenharmony_ci block_t blkaddr, bool in_task) 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci struct decompress_io_ctx *dic = 81162306a36Sopenharmony_ci (struct decompress_io_ctx *)page_private(page); 81262306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci dec_page_count(sbi, F2FS_RD_DATA); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (failed) 81762306a36Sopenharmony_ci WRITE_ONCE(dic->failed, true); 81862306a36Sopenharmony_ci else if (blkaddr && in_task) 81962306a36Sopenharmony_ci f2fs_cache_compressed_page(sbi, page, 82062306a36Sopenharmony_ci dic->inode->i_ino, blkaddr); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (atomic_dec_and_test(&dic->remaining_pages)) 82362306a36Sopenharmony_ci f2fs_decompress_cluster(dic, in_task); 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic bool is_page_in_cluster(struct compress_ctx *cc, pgoff_t index) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci if (cc->cluster_idx == NULL_CLUSTER) 82962306a36Sopenharmony_ci return true; 83062306a36Sopenharmony_ci return cc->cluster_idx == cluster_idx(cc, index); 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cibool f2fs_cluster_is_empty(struct compress_ctx *cc) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci return cc->nr_rpages == 0; 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic bool f2fs_cluster_is_full(struct compress_ctx *cc) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci return cc->cluster_size == cc->nr_rpages; 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cibool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index) 84462306a36Sopenharmony_ci{ 84562306a36Sopenharmony_ci if (f2fs_cluster_is_empty(cc)) 84662306a36Sopenharmony_ci return true; 84762306a36Sopenharmony_ci return is_page_in_cluster(cc, index); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cibool f2fs_all_cluster_page_ready(struct compress_ctx *cc, struct page **pages, 85162306a36Sopenharmony_ci int index, int nr_pages, bool uptodate) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci unsigned long pgidx = pages[index]->index; 85462306a36Sopenharmony_ci int i = uptodate ? 0 : 1; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* 85762306a36Sopenharmony_ci * when uptodate set to true, try to check all pages in cluster is 85862306a36Sopenharmony_ci * uptodate or not. 85962306a36Sopenharmony_ci */ 86062306a36Sopenharmony_ci if (uptodate && (pgidx % cc->cluster_size)) 86162306a36Sopenharmony_ci return false; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci if (nr_pages - index < cc->cluster_size) 86462306a36Sopenharmony_ci return false; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci for (; i < cc->cluster_size; i++) { 86762306a36Sopenharmony_ci if (pages[index + i]->index != pgidx + i) 86862306a36Sopenharmony_ci return false; 86962306a36Sopenharmony_ci if (uptodate && !PageUptodate(pages[index + i])) 87062306a36Sopenharmony_ci return false; 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci return true; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic bool cluster_has_invalid_data(struct compress_ctx *cc) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci loff_t i_size = i_size_read(cc->inode); 87962306a36Sopenharmony_ci unsigned nr_pages = DIV_ROUND_UP(i_size, PAGE_SIZE); 88062306a36Sopenharmony_ci int i; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 88362306a36Sopenharmony_ci struct page *page = cc->rpages[i]; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(cc->inode), !page); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* beyond EOF */ 88862306a36Sopenharmony_ci if (page->index >= nr_pages) 88962306a36Sopenharmony_ci return true; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci return false; 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cibool f2fs_sanity_check_cluster(struct dnode_of_data *dn) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); 89762306a36Sopenharmony_ci unsigned int cluster_size = F2FS_I(dn->inode)->i_cluster_size; 89862306a36Sopenharmony_ci bool compressed = dn->data_blkaddr == COMPRESS_ADDR; 89962306a36Sopenharmony_ci int cluster_end = 0; 90062306a36Sopenharmony_ci int i; 90162306a36Sopenharmony_ci char *reason = ""; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (!compressed) 90462306a36Sopenharmony_ci return false; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci /* [..., COMPR_ADDR, ...] */ 90762306a36Sopenharmony_ci if (dn->ofs_in_node % cluster_size) { 90862306a36Sopenharmony_ci reason = "[*|C|*|*]"; 90962306a36Sopenharmony_ci goto out; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci for (i = 1; i < cluster_size; i++) { 91362306a36Sopenharmony_ci block_t blkaddr = data_blkaddr(dn->inode, dn->node_page, 91462306a36Sopenharmony_ci dn->ofs_in_node + i); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* [COMPR_ADDR, ..., COMPR_ADDR] */ 91762306a36Sopenharmony_ci if (blkaddr == COMPRESS_ADDR) { 91862306a36Sopenharmony_ci reason = "[C|*|C|*]"; 91962306a36Sopenharmony_ci goto out; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci if (!__is_valid_data_blkaddr(blkaddr)) { 92262306a36Sopenharmony_ci if (!cluster_end) 92362306a36Sopenharmony_ci cluster_end = i; 92462306a36Sopenharmony_ci continue; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci /* [COMPR_ADDR, NULL_ADDR or NEW_ADDR, valid_blkaddr] */ 92762306a36Sopenharmony_ci if (cluster_end) { 92862306a36Sopenharmony_ci reason = "[C|N|N|V]"; 92962306a36Sopenharmony_ci goto out; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci return false; 93362306a36Sopenharmony_ciout: 93462306a36Sopenharmony_ci f2fs_warn(sbi, "access invalid cluster, ino:%lu, nid:%u, ofs_in_node:%u, reason:%s", 93562306a36Sopenharmony_ci dn->inode->i_ino, dn->nid, dn->ofs_in_node, reason); 93662306a36Sopenharmony_ci set_sbi_flag(sbi, SBI_NEED_FSCK); 93762306a36Sopenharmony_ci return true; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic int __f2fs_cluster_blocks(struct inode *inode, 94162306a36Sopenharmony_ci unsigned int cluster_idx, bool compr) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct dnode_of_data dn; 94462306a36Sopenharmony_ci unsigned int cluster_size = F2FS_I(inode)->i_cluster_size; 94562306a36Sopenharmony_ci unsigned int start_idx = cluster_idx << 94662306a36Sopenharmony_ci F2FS_I(inode)->i_log_cluster_size; 94762306a36Sopenharmony_ci int ret; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci set_new_dnode(&dn, inode, NULL, NULL, 0); 95062306a36Sopenharmony_ci ret = f2fs_get_dnode_of_data(&dn, start_idx, LOOKUP_NODE); 95162306a36Sopenharmony_ci if (ret) { 95262306a36Sopenharmony_ci if (ret == -ENOENT) 95362306a36Sopenharmony_ci ret = 0; 95462306a36Sopenharmony_ci goto fail; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (f2fs_sanity_check_cluster(&dn)) { 95862306a36Sopenharmony_ci ret = -EFSCORRUPTED; 95962306a36Sopenharmony_ci f2fs_handle_error(F2FS_I_SB(inode), ERROR_CORRUPTED_CLUSTER); 96062306a36Sopenharmony_ci goto fail; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if (dn.data_blkaddr == COMPRESS_ADDR) { 96462306a36Sopenharmony_ci int i; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci ret = 1; 96762306a36Sopenharmony_ci for (i = 1; i < cluster_size; i++) { 96862306a36Sopenharmony_ci block_t blkaddr; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci blkaddr = data_blkaddr(dn.inode, 97162306a36Sopenharmony_ci dn.node_page, dn.ofs_in_node + i); 97262306a36Sopenharmony_ci if (compr) { 97362306a36Sopenharmony_ci if (__is_valid_data_blkaddr(blkaddr)) 97462306a36Sopenharmony_ci ret++; 97562306a36Sopenharmony_ci } else { 97662306a36Sopenharmony_ci if (blkaddr != NULL_ADDR) 97762306a36Sopenharmony_ci ret++; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(inode), 98262306a36Sopenharmony_ci !compr && ret != cluster_size && 98362306a36Sopenharmony_ci !is_inode_flag_set(inode, FI_COMPRESS_RELEASED)); 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_cifail: 98662306a36Sopenharmony_ci f2fs_put_dnode(&dn); 98762306a36Sopenharmony_ci return ret; 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci/* return # of compressed blocks in compressed cluster */ 99162306a36Sopenharmony_cistatic int f2fs_compressed_blocks(struct compress_ctx *cc) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci return __f2fs_cluster_blocks(cc->inode, cc->cluster_idx, true); 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci/* return # of valid blocks in compressed cluster */ 99762306a36Sopenharmony_ciint f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci return __f2fs_cluster_blocks(inode, 100062306a36Sopenharmony_ci index >> F2FS_I(inode)->i_log_cluster_size, 100162306a36Sopenharmony_ci false); 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic bool cluster_may_compress(struct compress_ctx *cc) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci if (!f2fs_need_compress_data(cc->inode)) 100762306a36Sopenharmony_ci return false; 100862306a36Sopenharmony_ci if (f2fs_is_atomic_file(cc->inode)) 100962306a36Sopenharmony_ci return false; 101062306a36Sopenharmony_ci if (!f2fs_cluster_is_full(cc)) 101162306a36Sopenharmony_ci return false; 101262306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(F2FS_I_SB(cc->inode)))) 101362306a36Sopenharmony_ci return false; 101462306a36Sopenharmony_ci return !cluster_has_invalid_data(cc); 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic void set_cluster_writeback(struct compress_ctx *cc) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci int i; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 102262306a36Sopenharmony_ci if (cc->rpages[i]) 102362306a36Sopenharmony_ci set_page_writeback(cc->rpages[i]); 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic void set_cluster_dirty(struct compress_ctx *cc) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci int i; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) 103262306a36Sopenharmony_ci if (cc->rpages[i]) { 103362306a36Sopenharmony_ci set_page_dirty(cc->rpages[i]); 103462306a36Sopenharmony_ci set_page_private_gcing(cc->rpages[i]); 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic int prepare_compress_overwrite(struct compress_ctx *cc, 103962306a36Sopenharmony_ci struct page **pagep, pgoff_t index, void **fsdata) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); 104262306a36Sopenharmony_ci struct address_space *mapping = cc->inode->i_mapping; 104362306a36Sopenharmony_ci struct page *page; 104462306a36Sopenharmony_ci sector_t last_block_in_bio; 104562306a36Sopenharmony_ci fgf_t fgp_flag = FGP_LOCK | FGP_WRITE | FGP_CREAT; 104662306a36Sopenharmony_ci pgoff_t start_idx = start_idx_of_cluster(cc); 104762306a36Sopenharmony_ci int i, ret; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ciretry: 105062306a36Sopenharmony_ci ret = f2fs_is_compressed_cluster(cc->inode, start_idx); 105162306a36Sopenharmony_ci if (ret <= 0) 105262306a36Sopenharmony_ci return ret; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci ret = f2fs_init_compress_ctx(cc); 105562306a36Sopenharmony_ci if (ret) 105662306a36Sopenharmony_ci return ret; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* keep page reference to avoid page reclaim */ 105962306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 106062306a36Sopenharmony_ci page = f2fs_pagecache_get_page(mapping, start_idx + i, 106162306a36Sopenharmony_ci fgp_flag, GFP_NOFS); 106262306a36Sopenharmony_ci if (!page) { 106362306a36Sopenharmony_ci ret = -ENOMEM; 106462306a36Sopenharmony_ci goto unlock_pages; 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (PageUptodate(page)) 106862306a36Sopenharmony_ci f2fs_put_page(page, 1); 106962306a36Sopenharmony_ci else 107062306a36Sopenharmony_ci f2fs_compress_ctx_add_page(cc, page); 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (!f2fs_cluster_is_empty(cc)) { 107462306a36Sopenharmony_ci struct bio *bio = NULL; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci ret = f2fs_read_multi_pages(cc, &bio, cc->cluster_size, 107762306a36Sopenharmony_ci &last_block_in_bio, false, true); 107862306a36Sopenharmony_ci f2fs_put_rpages(cc); 107962306a36Sopenharmony_ci f2fs_destroy_compress_ctx(cc, true); 108062306a36Sopenharmony_ci if (ret) 108162306a36Sopenharmony_ci goto out; 108262306a36Sopenharmony_ci if (bio) 108362306a36Sopenharmony_ci f2fs_submit_read_bio(sbi, bio, DATA); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci ret = f2fs_init_compress_ctx(cc); 108662306a36Sopenharmony_ci if (ret) 108762306a36Sopenharmony_ci goto out; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 109162306a36Sopenharmony_ci f2fs_bug_on(sbi, cc->rpages[i]); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci page = find_lock_page(mapping, start_idx + i); 109462306a36Sopenharmony_ci if (!page) { 109562306a36Sopenharmony_ci /* page can be truncated */ 109662306a36Sopenharmony_ci goto release_and_retry; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci f2fs_wait_on_page_writeback(page, DATA, true, true); 110062306a36Sopenharmony_ci f2fs_compress_ctx_add_page(cc, page); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (!PageUptodate(page)) { 110362306a36Sopenharmony_cirelease_and_retry: 110462306a36Sopenharmony_ci f2fs_put_rpages(cc); 110562306a36Sopenharmony_ci f2fs_unlock_rpages(cc, i + 1); 110662306a36Sopenharmony_ci f2fs_destroy_compress_ctx(cc, true); 110762306a36Sopenharmony_ci goto retry; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (likely(!ret)) { 111262306a36Sopenharmony_ci *fsdata = cc->rpages; 111362306a36Sopenharmony_ci *pagep = cc->rpages[offset_in_cluster(cc, index)]; 111462306a36Sopenharmony_ci return cc->cluster_size; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ciunlock_pages: 111862306a36Sopenharmony_ci f2fs_put_rpages(cc); 111962306a36Sopenharmony_ci f2fs_unlock_rpages(cc, i); 112062306a36Sopenharmony_ci f2fs_destroy_compress_ctx(cc, true); 112162306a36Sopenharmony_ciout: 112262306a36Sopenharmony_ci return ret; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ciint f2fs_prepare_compress_overwrite(struct inode *inode, 112662306a36Sopenharmony_ci struct page **pagep, pgoff_t index, void **fsdata) 112762306a36Sopenharmony_ci{ 112862306a36Sopenharmony_ci struct compress_ctx cc = { 112962306a36Sopenharmony_ci .inode = inode, 113062306a36Sopenharmony_ci .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, 113162306a36Sopenharmony_ci .cluster_size = F2FS_I(inode)->i_cluster_size, 113262306a36Sopenharmony_ci .cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size, 113362306a36Sopenharmony_ci .rpages = NULL, 113462306a36Sopenharmony_ci .nr_rpages = 0, 113562306a36Sopenharmony_ci }; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci return prepare_compress_overwrite(&cc, pagep, index, fsdata); 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cibool f2fs_compress_write_end(struct inode *inode, void *fsdata, 114162306a36Sopenharmony_ci pgoff_t index, unsigned copied) 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci{ 114462306a36Sopenharmony_ci struct compress_ctx cc = { 114562306a36Sopenharmony_ci .inode = inode, 114662306a36Sopenharmony_ci .log_cluster_size = F2FS_I(inode)->i_log_cluster_size, 114762306a36Sopenharmony_ci .cluster_size = F2FS_I(inode)->i_cluster_size, 114862306a36Sopenharmony_ci .rpages = fsdata, 114962306a36Sopenharmony_ci }; 115062306a36Sopenharmony_ci bool first_index = (index == cc.rpages[0]->index); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci if (copied) 115362306a36Sopenharmony_ci set_cluster_dirty(&cc); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci f2fs_put_rpages_wbc(&cc, NULL, false, 1); 115662306a36Sopenharmony_ci f2fs_destroy_compress_ctx(&cc, false); 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci return first_index; 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ciint f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock) 116262306a36Sopenharmony_ci{ 116362306a36Sopenharmony_ci void *fsdata = NULL; 116462306a36Sopenharmony_ci struct page *pagep; 116562306a36Sopenharmony_ci int log_cluster_size = F2FS_I(inode)->i_log_cluster_size; 116662306a36Sopenharmony_ci pgoff_t start_idx = from >> (PAGE_SHIFT + log_cluster_size) << 116762306a36Sopenharmony_ci log_cluster_size; 116862306a36Sopenharmony_ci int err; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci err = f2fs_is_compressed_cluster(inode, start_idx); 117162306a36Sopenharmony_ci if (err < 0) 117262306a36Sopenharmony_ci return err; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci /* truncate normal cluster */ 117562306a36Sopenharmony_ci if (!err) 117662306a36Sopenharmony_ci return f2fs_do_truncate_blocks(inode, from, lock); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci /* truncate compressed cluster */ 117962306a36Sopenharmony_ci err = f2fs_prepare_compress_overwrite(inode, &pagep, 118062306a36Sopenharmony_ci start_idx, &fsdata); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci /* should not be a normal cluster */ 118362306a36Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(inode), err == 0); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (err <= 0) 118662306a36Sopenharmony_ci return err; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (err > 0) { 118962306a36Sopenharmony_ci struct page **rpages = fsdata; 119062306a36Sopenharmony_ci int cluster_size = F2FS_I(inode)->i_cluster_size; 119162306a36Sopenharmony_ci int i; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci for (i = cluster_size - 1; i >= 0; i--) { 119462306a36Sopenharmony_ci loff_t start = rpages[i]->index << PAGE_SHIFT; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (from <= start) { 119762306a36Sopenharmony_ci zero_user_segment(rpages[i], 0, PAGE_SIZE); 119862306a36Sopenharmony_ci } else { 119962306a36Sopenharmony_ci zero_user_segment(rpages[i], from - start, 120062306a36Sopenharmony_ci PAGE_SIZE); 120162306a36Sopenharmony_ci break; 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci f2fs_compress_write_end(inode, fsdata, start_idx, true); 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci return 0; 120862306a36Sopenharmony_ci} 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_cistatic int f2fs_write_compressed_pages(struct compress_ctx *cc, 121162306a36Sopenharmony_ci int *submitted, 121262306a36Sopenharmony_ci struct writeback_control *wbc, 121362306a36Sopenharmony_ci enum iostat_type io_type) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci struct inode *inode = cc->inode; 121662306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 121762306a36Sopenharmony_ci struct f2fs_inode_info *fi = F2FS_I(inode); 121862306a36Sopenharmony_ci struct f2fs_io_info fio = { 121962306a36Sopenharmony_ci .sbi = sbi, 122062306a36Sopenharmony_ci .ino = cc->inode->i_ino, 122162306a36Sopenharmony_ci .type = DATA, 122262306a36Sopenharmony_ci .op = REQ_OP_WRITE, 122362306a36Sopenharmony_ci .op_flags = wbc_to_write_flags(wbc), 122462306a36Sopenharmony_ci .old_blkaddr = NEW_ADDR, 122562306a36Sopenharmony_ci .page = NULL, 122662306a36Sopenharmony_ci .encrypted_page = NULL, 122762306a36Sopenharmony_ci .compressed_page = NULL, 122862306a36Sopenharmony_ci .submitted = 0, 122962306a36Sopenharmony_ci .io_type = io_type, 123062306a36Sopenharmony_ci .io_wbc = wbc, 123162306a36Sopenharmony_ci .encrypted = fscrypt_inode_uses_fs_layer_crypto(cc->inode) ? 123262306a36Sopenharmony_ci 1 : 0, 123362306a36Sopenharmony_ci }; 123462306a36Sopenharmony_ci struct dnode_of_data dn; 123562306a36Sopenharmony_ci struct node_info ni; 123662306a36Sopenharmony_ci struct compress_io_ctx *cic; 123762306a36Sopenharmony_ci pgoff_t start_idx = start_idx_of_cluster(cc); 123862306a36Sopenharmony_ci unsigned int last_index = cc->cluster_size - 1; 123962306a36Sopenharmony_ci loff_t psize; 124062306a36Sopenharmony_ci int i, err; 124162306a36Sopenharmony_ci bool quota_inode = IS_NOQUOTA(inode); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* we should bypass data pages to proceed the kworker jobs */ 124462306a36Sopenharmony_ci if (unlikely(f2fs_cp_error(sbi))) { 124562306a36Sopenharmony_ci mapping_set_error(cc->rpages[0]->mapping, -EIO); 124662306a36Sopenharmony_ci goto out_free; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci if (quota_inode) { 125062306a36Sopenharmony_ci /* 125162306a36Sopenharmony_ci * We need to wait for node_write to avoid block allocation during 125262306a36Sopenharmony_ci * checkpoint. This can only happen to quota writes which can cause 125362306a36Sopenharmony_ci * the below discard race condition. 125462306a36Sopenharmony_ci */ 125562306a36Sopenharmony_ci f2fs_down_read(&sbi->node_write); 125662306a36Sopenharmony_ci } else if (!f2fs_trylock_op(sbi)) { 125762306a36Sopenharmony_ci goto out_free; 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci set_new_dnode(&dn, cc->inode, NULL, NULL, 0); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci err = f2fs_get_dnode_of_data(&dn, start_idx, LOOKUP_NODE); 126362306a36Sopenharmony_ci if (err) 126462306a36Sopenharmony_ci goto out_unlock_op; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 126762306a36Sopenharmony_ci if (data_blkaddr(dn.inode, dn.node_page, 126862306a36Sopenharmony_ci dn.ofs_in_node + i) == NULL_ADDR) 126962306a36Sopenharmony_ci goto out_put_dnode; 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci psize = (loff_t)(cc->rpages[last_index]->index + 1) << PAGE_SHIFT; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci err = f2fs_get_node_info(fio.sbi, dn.nid, &ni, false); 127562306a36Sopenharmony_ci if (err) 127662306a36Sopenharmony_ci goto out_put_dnode; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci fio.version = ni.version; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci cic = f2fs_kmem_cache_alloc(cic_entry_slab, GFP_F2FS_ZERO, false, sbi); 128162306a36Sopenharmony_ci if (!cic) 128262306a36Sopenharmony_ci goto out_put_dnode; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci cic->magic = F2FS_COMPRESSED_PAGE_MAGIC; 128562306a36Sopenharmony_ci cic->inode = inode; 128662306a36Sopenharmony_ci atomic_set(&cic->pending_pages, cc->valid_nr_cpages); 128762306a36Sopenharmony_ci cic->rpages = page_array_alloc(cc->inode, cc->cluster_size); 128862306a36Sopenharmony_ci if (!cic->rpages) 128962306a36Sopenharmony_ci goto out_put_cic; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci cic->nr_rpages = cc->cluster_size; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci for (i = 0; i < cc->valid_nr_cpages; i++) { 129462306a36Sopenharmony_ci f2fs_set_compressed_page(cc->cpages[i], inode, 129562306a36Sopenharmony_ci cc->rpages[i + 1]->index, cic); 129662306a36Sopenharmony_ci fio.compressed_page = cc->cpages[i]; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci fio.old_blkaddr = data_blkaddr(dn.inode, dn.node_page, 129962306a36Sopenharmony_ci dn.ofs_in_node + i + 1); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci /* wait for GCed page writeback via META_MAPPING */ 130262306a36Sopenharmony_ci f2fs_wait_on_block_writeback(inode, fio.old_blkaddr); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (fio.encrypted) { 130562306a36Sopenharmony_ci fio.page = cc->rpages[i + 1]; 130662306a36Sopenharmony_ci err = f2fs_encrypt_one_page(&fio); 130762306a36Sopenharmony_ci if (err) 130862306a36Sopenharmony_ci goto out_destroy_crypt; 130962306a36Sopenharmony_ci cc->cpages[i] = fio.encrypted_page; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci set_cluster_writeback(cc); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) 131662306a36Sopenharmony_ci cic->rpages[i] = cc->rpages[i]; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++, dn.ofs_in_node++) { 131962306a36Sopenharmony_ci block_t blkaddr; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci blkaddr = f2fs_data_blkaddr(&dn); 132262306a36Sopenharmony_ci fio.page = cc->rpages[i]; 132362306a36Sopenharmony_ci fio.old_blkaddr = blkaddr; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci /* cluster header */ 132662306a36Sopenharmony_ci if (i == 0) { 132762306a36Sopenharmony_ci if (blkaddr == COMPRESS_ADDR) 132862306a36Sopenharmony_ci fio.compr_blocks++; 132962306a36Sopenharmony_ci if (__is_valid_data_blkaddr(blkaddr)) 133062306a36Sopenharmony_ci f2fs_invalidate_blocks(sbi, blkaddr); 133162306a36Sopenharmony_ci f2fs_update_data_blkaddr(&dn, COMPRESS_ADDR); 133262306a36Sopenharmony_ci goto unlock_continue; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (fio.compr_blocks && __is_valid_data_blkaddr(blkaddr)) 133662306a36Sopenharmony_ci fio.compr_blocks++; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci if (i > cc->valid_nr_cpages) { 133962306a36Sopenharmony_ci if (__is_valid_data_blkaddr(blkaddr)) { 134062306a36Sopenharmony_ci f2fs_invalidate_blocks(sbi, blkaddr); 134162306a36Sopenharmony_ci f2fs_update_data_blkaddr(&dn, NEW_ADDR); 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci goto unlock_continue; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci f2fs_bug_on(fio.sbi, blkaddr == NULL_ADDR); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci if (fio.encrypted) 134962306a36Sopenharmony_ci fio.encrypted_page = cc->cpages[i - 1]; 135062306a36Sopenharmony_ci else 135162306a36Sopenharmony_ci fio.compressed_page = cc->cpages[i - 1]; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci cc->cpages[i - 1] = NULL; 135462306a36Sopenharmony_ci f2fs_outplace_write_data(&dn, &fio); 135562306a36Sopenharmony_ci (*submitted)++; 135662306a36Sopenharmony_ciunlock_continue: 135762306a36Sopenharmony_ci inode_dec_dirty_pages(cc->inode); 135862306a36Sopenharmony_ci unlock_page(fio.page); 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci if (fio.compr_blocks) 136262306a36Sopenharmony_ci f2fs_i_compr_blocks_update(inode, fio.compr_blocks - 1, false); 136362306a36Sopenharmony_ci f2fs_i_compr_blocks_update(inode, cc->valid_nr_cpages, true); 136462306a36Sopenharmony_ci add_compr_block_stat(inode, cc->valid_nr_cpages); 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci set_inode_flag(cc->inode, FI_APPEND_WRITE); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci f2fs_put_dnode(&dn); 136962306a36Sopenharmony_ci if (quota_inode) 137062306a36Sopenharmony_ci f2fs_up_read(&sbi->node_write); 137162306a36Sopenharmony_ci else 137262306a36Sopenharmony_ci f2fs_unlock_op(sbi); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci spin_lock(&fi->i_size_lock); 137562306a36Sopenharmony_ci if (fi->last_disk_size < psize) 137662306a36Sopenharmony_ci fi->last_disk_size = psize; 137762306a36Sopenharmony_ci spin_unlock(&fi->i_size_lock); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci f2fs_put_rpages(cc); 138062306a36Sopenharmony_ci page_array_free(cc->inode, cc->cpages, cc->nr_cpages); 138162306a36Sopenharmony_ci cc->cpages = NULL; 138262306a36Sopenharmony_ci f2fs_destroy_compress_ctx(cc, false); 138362306a36Sopenharmony_ci return 0; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ciout_destroy_crypt: 138662306a36Sopenharmony_ci page_array_free(cc->inode, cic->rpages, cc->cluster_size); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci for (--i; i >= 0; i--) 138962306a36Sopenharmony_ci fscrypt_finalize_bounce_page(&cc->cpages[i]); 139062306a36Sopenharmony_ciout_put_cic: 139162306a36Sopenharmony_ci kmem_cache_free(cic_entry_slab, cic); 139262306a36Sopenharmony_ciout_put_dnode: 139362306a36Sopenharmony_ci f2fs_put_dnode(&dn); 139462306a36Sopenharmony_ciout_unlock_op: 139562306a36Sopenharmony_ci if (quota_inode) 139662306a36Sopenharmony_ci f2fs_up_read(&sbi->node_write); 139762306a36Sopenharmony_ci else 139862306a36Sopenharmony_ci f2fs_unlock_op(sbi); 139962306a36Sopenharmony_ciout_free: 140062306a36Sopenharmony_ci for (i = 0; i < cc->valid_nr_cpages; i++) { 140162306a36Sopenharmony_ci f2fs_compress_free_page(cc->cpages[i]); 140262306a36Sopenharmony_ci cc->cpages[i] = NULL; 140362306a36Sopenharmony_ci } 140462306a36Sopenharmony_ci page_array_free(cc->inode, cc->cpages, cc->nr_cpages); 140562306a36Sopenharmony_ci cc->cpages = NULL; 140662306a36Sopenharmony_ci return -EAGAIN; 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_civoid f2fs_compress_write_end_io(struct bio *bio, struct page *page) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci struct f2fs_sb_info *sbi = bio->bi_private; 141262306a36Sopenharmony_ci struct compress_io_ctx *cic = 141362306a36Sopenharmony_ci (struct compress_io_ctx *)page_private(page); 141462306a36Sopenharmony_ci enum count_type type = WB_DATA_TYPE(page, 141562306a36Sopenharmony_ci f2fs_is_compressed_page(page)); 141662306a36Sopenharmony_ci int i; 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci if (unlikely(bio->bi_status)) 141962306a36Sopenharmony_ci mapping_set_error(cic->inode->i_mapping, -EIO); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci f2fs_compress_free_page(page); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci dec_page_count(sbi, type); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci if (atomic_dec_return(&cic->pending_pages)) 142662306a36Sopenharmony_ci return; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci for (i = 0; i < cic->nr_rpages; i++) { 142962306a36Sopenharmony_ci WARN_ON(!cic->rpages[i]); 143062306a36Sopenharmony_ci clear_page_private_gcing(cic->rpages[i]); 143162306a36Sopenharmony_ci end_page_writeback(cic->rpages[i]); 143262306a36Sopenharmony_ci } 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci page_array_free(cic->inode, cic->rpages, cic->nr_rpages); 143562306a36Sopenharmony_ci kmem_cache_free(cic_entry_slab, cic); 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic int f2fs_write_raw_pages(struct compress_ctx *cc, 143962306a36Sopenharmony_ci int *submitted_p, 144062306a36Sopenharmony_ci struct writeback_control *wbc, 144162306a36Sopenharmony_ci enum iostat_type io_type) 144262306a36Sopenharmony_ci{ 144362306a36Sopenharmony_ci struct address_space *mapping = cc->inode->i_mapping; 144462306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_M_SB(mapping); 144562306a36Sopenharmony_ci int submitted, compr_blocks, i; 144662306a36Sopenharmony_ci int ret = 0; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci compr_blocks = f2fs_compressed_blocks(cc); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 145162306a36Sopenharmony_ci if (!cc->rpages[i]) 145262306a36Sopenharmony_ci continue; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci redirty_page_for_writepage(wbc, cc->rpages[i]); 145562306a36Sopenharmony_ci unlock_page(cc->rpages[i]); 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci if (compr_blocks < 0) 145962306a36Sopenharmony_ci return compr_blocks; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci /* overwrite compressed cluster w/ normal cluster */ 146262306a36Sopenharmony_ci if (compr_blocks > 0) 146362306a36Sopenharmony_ci f2fs_lock_op(sbi); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci for (i = 0; i < cc->cluster_size; i++) { 146662306a36Sopenharmony_ci if (!cc->rpages[i]) 146762306a36Sopenharmony_ci continue; 146862306a36Sopenharmony_ciretry_write: 146962306a36Sopenharmony_ci lock_page(cc->rpages[i]); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci if (cc->rpages[i]->mapping != mapping) { 147262306a36Sopenharmony_cicontinue_unlock: 147362306a36Sopenharmony_ci unlock_page(cc->rpages[i]); 147462306a36Sopenharmony_ci continue; 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci if (!PageDirty(cc->rpages[i])) 147862306a36Sopenharmony_ci goto continue_unlock; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci if (PageWriteback(cc->rpages[i])) { 148162306a36Sopenharmony_ci if (wbc->sync_mode == WB_SYNC_NONE) 148262306a36Sopenharmony_ci goto continue_unlock; 148362306a36Sopenharmony_ci f2fs_wait_on_page_writeback(cc->rpages[i], DATA, true, true); 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci if (!clear_page_dirty_for_io(cc->rpages[i])) 148762306a36Sopenharmony_ci goto continue_unlock; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci ret = f2fs_write_single_data_page(cc->rpages[i], &submitted, 149062306a36Sopenharmony_ci NULL, NULL, wbc, io_type, 149162306a36Sopenharmony_ci compr_blocks, false); 149262306a36Sopenharmony_ci if (ret) { 149362306a36Sopenharmony_ci if (ret == AOP_WRITEPAGE_ACTIVATE) { 149462306a36Sopenharmony_ci unlock_page(cc->rpages[i]); 149562306a36Sopenharmony_ci ret = 0; 149662306a36Sopenharmony_ci } else if (ret == -EAGAIN) { 149762306a36Sopenharmony_ci ret = 0; 149862306a36Sopenharmony_ci /* 149962306a36Sopenharmony_ci * for quota file, just redirty left pages to 150062306a36Sopenharmony_ci * avoid deadlock caused by cluster update race 150162306a36Sopenharmony_ci * from foreground operation. 150262306a36Sopenharmony_ci */ 150362306a36Sopenharmony_ci if (IS_NOQUOTA(cc->inode)) 150462306a36Sopenharmony_ci goto out; 150562306a36Sopenharmony_ci f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT); 150662306a36Sopenharmony_ci goto retry_write; 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci goto out; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci *submitted_p += submitted; 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ciout: 151562306a36Sopenharmony_ci if (compr_blocks > 0) 151662306a36Sopenharmony_ci f2fs_unlock_op(sbi); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci f2fs_balance_fs(sbi, true); 151962306a36Sopenharmony_ci return ret; 152062306a36Sopenharmony_ci} 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ciint f2fs_write_multi_pages(struct compress_ctx *cc, 152362306a36Sopenharmony_ci int *submitted, 152462306a36Sopenharmony_ci struct writeback_control *wbc, 152562306a36Sopenharmony_ci enum iostat_type io_type) 152662306a36Sopenharmony_ci{ 152762306a36Sopenharmony_ci int err; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci *submitted = 0; 153062306a36Sopenharmony_ci if (cluster_may_compress(cc)) { 153162306a36Sopenharmony_ci err = f2fs_compress_pages(cc); 153262306a36Sopenharmony_ci if (err == -EAGAIN) { 153362306a36Sopenharmony_ci add_compr_block_stat(cc->inode, cc->cluster_size); 153462306a36Sopenharmony_ci goto write; 153562306a36Sopenharmony_ci } else if (err) { 153662306a36Sopenharmony_ci f2fs_put_rpages_wbc(cc, wbc, true, 1); 153762306a36Sopenharmony_ci goto destroy_out; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci err = f2fs_write_compressed_pages(cc, submitted, 154162306a36Sopenharmony_ci wbc, io_type); 154262306a36Sopenharmony_ci if (!err) 154362306a36Sopenharmony_ci return 0; 154462306a36Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(cc->inode), err != -EAGAIN); 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ciwrite: 154762306a36Sopenharmony_ci f2fs_bug_on(F2FS_I_SB(cc->inode), *submitted); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci err = f2fs_write_raw_pages(cc, submitted, wbc, io_type); 155062306a36Sopenharmony_ci f2fs_put_rpages_wbc(cc, wbc, false, 0); 155162306a36Sopenharmony_cidestroy_out: 155262306a36Sopenharmony_ci f2fs_destroy_compress_ctx(cc, false); 155362306a36Sopenharmony_ci return err; 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic inline bool allow_memalloc_for_decomp(struct f2fs_sb_info *sbi, 155762306a36Sopenharmony_ci bool pre_alloc) 155862306a36Sopenharmony_ci{ 155962306a36Sopenharmony_ci return pre_alloc ^ f2fs_low_mem_mode(sbi); 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_cistatic int f2fs_prepare_decomp_mem(struct decompress_io_ctx *dic, 156362306a36Sopenharmony_ci bool pre_alloc) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci const struct f2fs_compress_ops *cops = 156662306a36Sopenharmony_ci f2fs_cops[F2FS_I(dic->inode)->i_compress_algorithm]; 156762306a36Sopenharmony_ci int i; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci if (!allow_memalloc_for_decomp(F2FS_I_SB(dic->inode), pre_alloc)) 157062306a36Sopenharmony_ci return 0; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci dic->tpages = page_array_alloc(dic->inode, dic->cluster_size); 157362306a36Sopenharmony_ci if (!dic->tpages) 157462306a36Sopenharmony_ci return -ENOMEM; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci for (i = 0; i < dic->cluster_size; i++) { 157762306a36Sopenharmony_ci if (dic->rpages[i]) { 157862306a36Sopenharmony_ci dic->tpages[i] = dic->rpages[i]; 157962306a36Sopenharmony_ci continue; 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci dic->tpages[i] = f2fs_compress_alloc_page(); 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci dic->rbuf = f2fs_vmap(dic->tpages, dic->cluster_size); 158662306a36Sopenharmony_ci if (!dic->rbuf) 158762306a36Sopenharmony_ci return -ENOMEM; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci dic->cbuf = f2fs_vmap(dic->cpages, dic->nr_cpages); 159062306a36Sopenharmony_ci if (!dic->cbuf) 159162306a36Sopenharmony_ci return -ENOMEM; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci if (cops->init_decompress_ctx) 159462306a36Sopenharmony_ci return cops->init_decompress_ctx(dic); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci return 0; 159762306a36Sopenharmony_ci} 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_cistatic void f2fs_release_decomp_mem(struct decompress_io_ctx *dic, 160062306a36Sopenharmony_ci bool bypass_destroy_callback, bool pre_alloc) 160162306a36Sopenharmony_ci{ 160262306a36Sopenharmony_ci const struct f2fs_compress_ops *cops = 160362306a36Sopenharmony_ci f2fs_cops[F2FS_I(dic->inode)->i_compress_algorithm]; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci if (!allow_memalloc_for_decomp(F2FS_I_SB(dic->inode), pre_alloc)) 160662306a36Sopenharmony_ci return; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci if (!bypass_destroy_callback && cops->destroy_decompress_ctx) 160962306a36Sopenharmony_ci cops->destroy_decompress_ctx(dic); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci if (dic->cbuf) 161262306a36Sopenharmony_ci vm_unmap_ram(dic->cbuf, dic->nr_cpages); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci if (dic->rbuf) 161562306a36Sopenharmony_ci vm_unmap_ram(dic->rbuf, dic->cluster_size); 161662306a36Sopenharmony_ci} 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_cistatic void f2fs_free_dic(struct decompress_io_ctx *dic, 161962306a36Sopenharmony_ci bool bypass_destroy_callback); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_cistruct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci struct decompress_io_ctx *dic; 162462306a36Sopenharmony_ci pgoff_t start_idx = start_idx_of_cluster(cc); 162562306a36Sopenharmony_ci struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); 162662306a36Sopenharmony_ci int i, ret; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci dic = f2fs_kmem_cache_alloc(dic_entry_slab, GFP_F2FS_ZERO, false, sbi); 162962306a36Sopenharmony_ci if (!dic) 163062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci dic->rpages = page_array_alloc(cc->inode, cc->cluster_size); 163362306a36Sopenharmony_ci if (!dic->rpages) { 163462306a36Sopenharmony_ci kmem_cache_free(dic_entry_slab, dic); 163562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci dic->magic = F2FS_COMPRESSED_PAGE_MAGIC; 163962306a36Sopenharmony_ci dic->inode = cc->inode; 164062306a36Sopenharmony_ci atomic_set(&dic->remaining_pages, cc->nr_cpages); 164162306a36Sopenharmony_ci dic->cluster_idx = cc->cluster_idx; 164262306a36Sopenharmony_ci dic->cluster_size = cc->cluster_size; 164362306a36Sopenharmony_ci dic->log_cluster_size = cc->log_cluster_size; 164462306a36Sopenharmony_ci dic->nr_cpages = cc->nr_cpages; 164562306a36Sopenharmony_ci refcount_set(&dic->refcnt, 1); 164662306a36Sopenharmony_ci dic->failed = false; 164762306a36Sopenharmony_ci dic->need_verity = f2fs_need_verity(cc->inode, start_idx); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci for (i = 0; i < dic->cluster_size; i++) 165062306a36Sopenharmony_ci dic->rpages[i] = cc->rpages[i]; 165162306a36Sopenharmony_ci dic->nr_rpages = cc->cluster_size; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci dic->cpages = page_array_alloc(dic->inode, dic->nr_cpages); 165462306a36Sopenharmony_ci if (!dic->cpages) { 165562306a36Sopenharmony_ci ret = -ENOMEM; 165662306a36Sopenharmony_ci goto out_free; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci for (i = 0; i < dic->nr_cpages; i++) { 166062306a36Sopenharmony_ci struct page *page; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci page = f2fs_compress_alloc_page(); 166362306a36Sopenharmony_ci f2fs_set_compressed_page(page, cc->inode, 166462306a36Sopenharmony_ci start_idx + i + 1, dic); 166562306a36Sopenharmony_ci dic->cpages[i] = page; 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci ret = f2fs_prepare_decomp_mem(dic, true); 166962306a36Sopenharmony_ci if (ret) 167062306a36Sopenharmony_ci goto out_free; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci return dic; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ciout_free: 167562306a36Sopenharmony_ci f2fs_free_dic(dic, true); 167662306a36Sopenharmony_ci return ERR_PTR(ret); 167762306a36Sopenharmony_ci} 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_cistatic void f2fs_free_dic(struct decompress_io_ctx *dic, 168062306a36Sopenharmony_ci bool bypass_destroy_callback) 168162306a36Sopenharmony_ci{ 168262306a36Sopenharmony_ci int i; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci f2fs_release_decomp_mem(dic, bypass_destroy_callback, true); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci if (dic->tpages) { 168762306a36Sopenharmony_ci for (i = 0; i < dic->cluster_size; i++) { 168862306a36Sopenharmony_ci if (dic->rpages[i]) 168962306a36Sopenharmony_ci continue; 169062306a36Sopenharmony_ci if (!dic->tpages[i]) 169162306a36Sopenharmony_ci continue; 169262306a36Sopenharmony_ci f2fs_compress_free_page(dic->tpages[i]); 169362306a36Sopenharmony_ci } 169462306a36Sopenharmony_ci page_array_free(dic->inode, dic->tpages, dic->cluster_size); 169562306a36Sopenharmony_ci } 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci if (dic->cpages) { 169862306a36Sopenharmony_ci for (i = 0; i < dic->nr_cpages; i++) { 169962306a36Sopenharmony_ci if (!dic->cpages[i]) 170062306a36Sopenharmony_ci continue; 170162306a36Sopenharmony_ci f2fs_compress_free_page(dic->cpages[i]); 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci page_array_free(dic->inode, dic->cpages, dic->nr_cpages); 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci page_array_free(dic->inode, dic->rpages, dic->nr_rpages); 170762306a36Sopenharmony_ci kmem_cache_free(dic_entry_slab, dic); 170862306a36Sopenharmony_ci} 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_cistatic void f2fs_late_free_dic(struct work_struct *work) 171162306a36Sopenharmony_ci{ 171262306a36Sopenharmony_ci struct decompress_io_ctx *dic = 171362306a36Sopenharmony_ci container_of(work, struct decompress_io_ctx, free_work); 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci f2fs_free_dic(dic, false); 171662306a36Sopenharmony_ci} 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_cistatic void f2fs_put_dic(struct decompress_io_ctx *dic, bool in_task) 171962306a36Sopenharmony_ci{ 172062306a36Sopenharmony_ci if (refcount_dec_and_test(&dic->refcnt)) { 172162306a36Sopenharmony_ci if (in_task) { 172262306a36Sopenharmony_ci f2fs_free_dic(dic, false); 172362306a36Sopenharmony_ci } else { 172462306a36Sopenharmony_ci INIT_WORK(&dic->free_work, f2fs_late_free_dic); 172562306a36Sopenharmony_ci queue_work(F2FS_I_SB(dic->inode)->post_read_wq, 172662306a36Sopenharmony_ci &dic->free_work); 172762306a36Sopenharmony_ci } 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci} 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_cistatic void f2fs_verify_cluster(struct work_struct *work) 173262306a36Sopenharmony_ci{ 173362306a36Sopenharmony_ci struct decompress_io_ctx *dic = 173462306a36Sopenharmony_ci container_of(work, struct decompress_io_ctx, verity_work); 173562306a36Sopenharmony_ci int i; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci /* Verify, update, and unlock the decompressed pages. */ 173862306a36Sopenharmony_ci for (i = 0; i < dic->cluster_size; i++) { 173962306a36Sopenharmony_ci struct page *rpage = dic->rpages[i]; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci if (!rpage) 174262306a36Sopenharmony_ci continue; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci if (fsverity_verify_page(rpage)) 174562306a36Sopenharmony_ci SetPageUptodate(rpage); 174662306a36Sopenharmony_ci else 174762306a36Sopenharmony_ci ClearPageUptodate(rpage); 174862306a36Sopenharmony_ci unlock_page(rpage); 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci f2fs_put_dic(dic, true); 175262306a36Sopenharmony_ci} 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci/* 175562306a36Sopenharmony_ci * This is called when a compressed cluster has been decompressed 175662306a36Sopenharmony_ci * (or failed to be read and/or decompressed). 175762306a36Sopenharmony_ci */ 175862306a36Sopenharmony_civoid f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed, 175962306a36Sopenharmony_ci bool in_task) 176062306a36Sopenharmony_ci{ 176162306a36Sopenharmony_ci int i; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci if (!failed && dic->need_verity) { 176462306a36Sopenharmony_ci /* 176562306a36Sopenharmony_ci * Note that to avoid deadlocks, the verity work can't be done 176662306a36Sopenharmony_ci * on the decompression workqueue. This is because verifying 176762306a36Sopenharmony_ci * the data pages can involve reading metadata pages from the 176862306a36Sopenharmony_ci * file, and these metadata pages may be compressed. 176962306a36Sopenharmony_ci */ 177062306a36Sopenharmony_ci INIT_WORK(&dic->verity_work, f2fs_verify_cluster); 177162306a36Sopenharmony_ci fsverity_enqueue_verify_work(&dic->verity_work); 177262306a36Sopenharmony_ci return; 177362306a36Sopenharmony_ci } 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci /* Update and unlock the cluster's pagecache pages. */ 177662306a36Sopenharmony_ci for (i = 0; i < dic->cluster_size; i++) { 177762306a36Sopenharmony_ci struct page *rpage = dic->rpages[i]; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci if (!rpage) 178062306a36Sopenharmony_ci continue; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci if (failed) 178362306a36Sopenharmony_ci ClearPageUptodate(rpage); 178462306a36Sopenharmony_ci else 178562306a36Sopenharmony_ci SetPageUptodate(rpage); 178662306a36Sopenharmony_ci unlock_page(rpage); 178762306a36Sopenharmony_ci } 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci /* 179062306a36Sopenharmony_ci * Release the reference to the decompress_io_ctx that was being held 179162306a36Sopenharmony_ci * for I/O completion. 179262306a36Sopenharmony_ci */ 179362306a36Sopenharmony_ci f2fs_put_dic(dic, in_task); 179462306a36Sopenharmony_ci} 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci/* 179762306a36Sopenharmony_ci * Put a reference to a compressed page's decompress_io_ctx. 179862306a36Sopenharmony_ci * 179962306a36Sopenharmony_ci * This is called when the page is no longer needed and can be freed. 180062306a36Sopenharmony_ci */ 180162306a36Sopenharmony_civoid f2fs_put_page_dic(struct page *page, bool in_task) 180262306a36Sopenharmony_ci{ 180362306a36Sopenharmony_ci struct decompress_io_ctx *dic = 180462306a36Sopenharmony_ci (struct decompress_io_ctx *)page_private(page); 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci f2fs_put_dic(dic, in_task); 180762306a36Sopenharmony_ci} 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci/* 181062306a36Sopenharmony_ci * check whether cluster blocks are contiguous, and add extent cache entry 181162306a36Sopenharmony_ci * only if cluster blocks are logically and physically contiguous. 181262306a36Sopenharmony_ci */ 181362306a36Sopenharmony_ciunsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn, 181462306a36Sopenharmony_ci unsigned int ofs_in_node) 181562306a36Sopenharmony_ci{ 181662306a36Sopenharmony_ci bool compressed = data_blkaddr(dn->inode, dn->node_page, 181762306a36Sopenharmony_ci ofs_in_node) == COMPRESS_ADDR; 181862306a36Sopenharmony_ci int i = compressed ? 1 : 0; 181962306a36Sopenharmony_ci block_t first_blkaddr = data_blkaddr(dn->inode, dn->node_page, 182062306a36Sopenharmony_ci ofs_in_node + i); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci for (i += 1; i < F2FS_I(dn->inode)->i_cluster_size; i++) { 182362306a36Sopenharmony_ci block_t blkaddr = data_blkaddr(dn->inode, dn->node_page, 182462306a36Sopenharmony_ci ofs_in_node + i); 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci if (!__is_valid_data_blkaddr(blkaddr)) 182762306a36Sopenharmony_ci break; 182862306a36Sopenharmony_ci if (first_blkaddr + i - (compressed ? 1 : 0) != blkaddr) 182962306a36Sopenharmony_ci return 0; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci return compressed ? i - 1 : i; 183362306a36Sopenharmony_ci} 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ciconst struct address_space_operations f2fs_compress_aops = { 183662306a36Sopenharmony_ci .release_folio = f2fs_release_folio, 183762306a36Sopenharmony_ci .invalidate_folio = f2fs_invalidate_folio, 183862306a36Sopenharmony_ci .migrate_folio = filemap_migrate_folio, 183962306a36Sopenharmony_ci}; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_cistruct address_space *COMPRESS_MAPPING(struct f2fs_sb_info *sbi) 184262306a36Sopenharmony_ci{ 184362306a36Sopenharmony_ci return sbi->compress_inode->i_mapping; 184462306a36Sopenharmony_ci} 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_civoid f2fs_invalidate_compress_page(struct f2fs_sb_info *sbi, block_t blkaddr) 184762306a36Sopenharmony_ci{ 184862306a36Sopenharmony_ci if (!sbi->compress_inode) 184962306a36Sopenharmony_ci return; 185062306a36Sopenharmony_ci invalidate_mapping_pages(COMPRESS_MAPPING(sbi), blkaddr, blkaddr); 185162306a36Sopenharmony_ci} 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_civoid f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, struct page *page, 185462306a36Sopenharmony_ci nid_t ino, block_t blkaddr) 185562306a36Sopenharmony_ci{ 185662306a36Sopenharmony_ci struct page *cpage; 185762306a36Sopenharmony_ci int ret; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci if (!test_opt(sbi, COMPRESS_CACHE)) 186062306a36Sopenharmony_ci return; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE_READ)) 186362306a36Sopenharmony_ci return; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci if (!f2fs_available_free_memory(sbi, COMPRESS_PAGE)) 186662306a36Sopenharmony_ci return; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci cpage = find_get_page(COMPRESS_MAPPING(sbi), blkaddr); 186962306a36Sopenharmony_ci if (cpage) { 187062306a36Sopenharmony_ci f2fs_put_page(cpage, 0); 187162306a36Sopenharmony_ci return; 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci cpage = alloc_page(__GFP_NOWARN | __GFP_IO); 187562306a36Sopenharmony_ci if (!cpage) 187662306a36Sopenharmony_ci return; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci ret = add_to_page_cache_lru(cpage, COMPRESS_MAPPING(sbi), 187962306a36Sopenharmony_ci blkaddr, GFP_NOFS); 188062306a36Sopenharmony_ci if (ret) { 188162306a36Sopenharmony_ci f2fs_put_page(cpage, 0); 188262306a36Sopenharmony_ci return; 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci set_page_private_data(cpage, ino); 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE_READ)) 188862306a36Sopenharmony_ci goto out; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci memcpy(page_address(cpage), page_address(page), PAGE_SIZE); 189162306a36Sopenharmony_ci SetPageUptodate(cpage); 189262306a36Sopenharmony_ciout: 189362306a36Sopenharmony_ci f2fs_put_page(cpage, 1); 189462306a36Sopenharmony_ci} 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_cibool f2fs_load_compressed_page(struct f2fs_sb_info *sbi, struct page *page, 189762306a36Sopenharmony_ci block_t blkaddr) 189862306a36Sopenharmony_ci{ 189962306a36Sopenharmony_ci struct page *cpage; 190062306a36Sopenharmony_ci bool hitted = false; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci if (!test_opt(sbi, COMPRESS_CACHE)) 190362306a36Sopenharmony_ci return false; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci cpage = f2fs_pagecache_get_page(COMPRESS_MAPPING(sbi), 190662306a36Sopenharmony_ci blkaddr, FGP_LOCK | FGP_NOWAIT, GFP_NOFS); 190762306a36Sopenharmony_ci if (cpage) { 190862306a36Sopenharmony_ci if (PageUptodate(cpage)) { 190962306a36Sopenharmony_ci atomic_inc(&sbi->compress_page_hit); 191062306a36Sopenharmony_ci memcpy(page_address(page), 191162306a36Sopenharmony_ci page_address(cpage), PAGE_SIZE); 191262306a36Sopenharmony_ci hitted = true; 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci f2fs_put_page(cpage, 1); 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci return hitted; 191862306a36Sopenharmony_ci} 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_civoid f2fs_invalidate_compress_pages(struct f2fs_sb_info *sbi, nid_t ino) 192162306a36Sopenharmony_ci{ 192262306a36Sopenharmony_ci struct address_space *mapping = COMPRESS_MAPPING(sbi); 192362306a36Sopenharmony_ci struct folio_batch fbatch; 192462306a36Sopenharmony_ci pgoff_t index = 0; 192562306a36Sopenharmony_ci pgoff_t end = MAX_BLKADDR(sbi); 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci if (!mapping->nrpages) 192862306a36Sopenharmony_ci return; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci folio_batch_init(&fbatch); 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci do { 193362306a36Sopenharmony_ci unsigned int nr, i; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci nr = filemap_get_folios(mapping, &index, end - 1, &fbatch); 193662306a36Sopenharmony_ci if (!nr) 193762306a36Sopenharmony_ci break; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 194062306a36Sopenharmony_ci struct folio *folio = fbatch.folios[i]; 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci folio_lock(folio); 194362306a36Sopenharmony_ci if (folio->mapping != mapping) { 194462306a36Sopenharmony_ci folio_unlock(folio); 194562306a36Sopenharmony_ci continue; 194662306a36Sopenharmony_ci } 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci if (ino != get_page_private_data(&folio->page)) { 194962306a36Sopenharmony_ci folio_unlock(folio); 195062306a36Sopenharmony_ci continue; 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci generic_error_remove_page(mapping, &folio->page); 195462306a36Sopenharmony_ci folio_unlock(folio); 195562306a36Sopenharmony_ci } 195662306a36Sopenharmony_ci folio_batch_release(&fbatch); 195762306a36Sopenharmony_ci cond_resched(); 195862306a36Sopenharmony_ci } while (index < end); 195962306a36Sopenharmony_ci} 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ciint f2fs_init_compress_inode(struct f2fs_sb_info *sbi) 196262306a36Sopenharmony_ci{ 196362306a36Sopenharmony_ci struct inode *inode; 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci if (!test_opt(sbi, COMPRESS_CACHE)) 196662306a36Sopenharmony_ci return 0; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci inode = f2fs_iget(sbi->sb, F2FS_COMPRESS_INO(sbi)); 196962306a36Sopenharmony_ci if (IS_ERR(inode)) 197062306a36Sopenharmony_ci return PTR_ERR(inode); 197162306a36Sopenharmony_ci sbi->compress_inode = inode; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci sbi->compress_percent = COMPRESS_PERCENT; 197462306a36Sopenharmony_ci sbi->compress_watermark = COMPRESS_WATERMARK; 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci atomic_set(&sbi->compress_page_hit, 0); 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci return 0; 197962306a36Sopenharmony_ci} 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_civoid f2fs_destroy_compress_inode(struct f2fs_sb_info *sbi) 198262306a36Sopenharmony_ci{ 198362306a36Sopenharmony_ci if (!sbi->compress_inode) 198462306a36Sopenharmony_ci return; 198562306a36Sopenharmony_ci iput(sbi->compress_inode); 198662306a36Sopenharmony_ci sbi->compress_inode = NULL; 198762306a36Sopenharmony_ci} 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ciint f2fs_init_page_array_cache(struct f2fs_sb_info *sbi) 199062306a36Sopenharmony_ci{ 199162306a36Sopenharmony_ci dev_t dev = sbi->sb->s_bdev->bd_dev; 199262306a36Sopenharmony_ci char slab_name[35]; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci if (!f2fs_sb_has_compression(sbi)) 199562306a36Sopenharmony_ci return 0; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci sprintf(slab_name, "f2fs_page_array_entry-%u:%u", MAJOR(dev), MINOR(dev)); 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci sbi->page_array_slab_size = sizeof(struct page *) << 200062306a36Sopenharmony_ci F2FS_OPTION(sbi).compress_log_size; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci sbi->page_array_slab = f2fs_kmem_cache_create(slab_name, 200362306a36Sopenharmony_ci sbi->page_array_slab_size); 200462306a36Sopenharmony_ci return sbi->page_array_slab ? 0 : -ENOMEM; 200562306a36Sopenharmony_ci} 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_civoid f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi) 200862306a36Sopenharmony_ci{ 200962306a36Sopenharmony_ci kmem_cache_destroy(sbi->page_array_slab); 201062306a36Sopenharmony_ci} 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ciint __init f2fs_init_compress_cache(void) 201362306a36Sopenharmony_ci{ 201462306a36Sopenharmony_ci cic_entry_slab = f2fs_kmem_cache_create("f2fs_cic_entry", 201562306a36Sopenharmony_ci sizeof(struct compress_io_ctx)); 201662306a36Sopenharmony_ci if (!cic_entry_slab) 201762306a36Sopenharmony_ci return -ENOMEM; 201862306a36Sopenharmony_ci dic_entry_slab = f2fs_kmem_cache_create("f2fs_dic_entry", 201962306a36Sopenharmony_ci sizeof(struct decompress_io_ctx)); 202062306a36Sopenharmony_ci if (!dic_entry_slab) 202162306a36Sopenharmony_ci goto free_cic; 202262306a36Sopenharmony_ci return 0; 202362306a36Sopenharmony_cifree_cic: 202462306a36Sopenharmony_ci kmem_cache_destroy(cic_entry_slab); 202562306a36Sopenharmony_ci return -ENOMEM; 202662306a36Sopenharmony_ci} 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_civoid f2fs_destroy_compress_cache(void) 202962306a36Sopenharmony_ci{ 203062306a36Sopenharmony_ci kmem_cache_destroy(dic_entry_slab); 203162306a36Sopenharmony_ci kmem_cache_destroy(cic_entry_slab); 203262306a36Sopenharmony_ci} 2033