162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2008 Oracle. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#ifndef BTRFS_COMPRESSION_H 762306a36Sopenharmony_ci#define BTRFS_COMPRESSION_H 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/sizes.h> 1062306a36Sopenharmony_ci#include "bio.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistruct btrfs_inode; 1362306a36Sopenharmony_cistruct btrfs_ordered_extent; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * We want to make sure that amount of RAM required to uncompress an extent is 1762306a36Sopenharmony_ci * reasonable, so we limit the total size in ram of a compressed extent to 1862306a36Sopenharmony_ci * 128k. This is a crucial number because it also controls how easily we can 1962306a36Sopenharmony_ci * spread reads across cpus for decompression. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * We also want to make sure the amount of IO required to do a random read is 2262306a36Sopenharmony_ci * reasonably small, so we limit the size of a compressed extent to 128k. 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* Maximum length of compressed data stored on disk */ 2662306a36Sopenharmony_ci#define BTRFS_MAX_COMPRESSED (SZ_128K) 2762306a36Sopenharmony_ci#define BTRFS_MAX_COMPRESSED_PAGES (BTRFS_MAX_COMPRESSED / PAGE_SIZE) 2862306a36Sopenharmony_cistatic_assert((BTRFS_MAX_COMPRESSED % PAGE_SIZE) == 0); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* Maximum size of data before compression */ 3162306a36Sopenharmony_ci#define BTRFS_MAX_UNCOMPRESSED (SZ_128K) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define BTRFS_ZLIB_DEFAULT_LEVEL 3 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistruct compressed_bio { 3662306a36Sopenharmony_ci /* Number of compressed pages in the array */ 3762306a36Sopenharmony_ci unsigned int nr_pages; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* the pages with the compressed data on them */ 4062306a36Sopenharmony_ci struct page **compressed_pages; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci /* starting offset in the inode for our pages */ 4362306a36Sopenharmony_ci u64 start; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* Number of bytes in the inode we're working on */ 4662306a36Sopenharmony_ci unsigned int len; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Number of bytes on disk */ 4962306a36Sopenharmony_ci unsigned int compressed_len; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* The compression algorithm for this bio */ 5262306a36Sopenharmony_ci u8 compress_type; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* Whether this is a write for writeback. */ 5562306a36Sopenharmony_ci bool writeback; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci union { 5862306a36Sopenharmony_ci /* For reads, this is the bio we are copying the data into */ 5962306a36Sopenharmony_ci struct btrfs_bio *orig_bbio; 6062306a36Sopenharmony_ci struct work_struct write_end_work; 6162306a36Sopenharmony_ci }; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Must be last. */ 6462306a36Sopenharmony_ci struct btrfs_bio bbio; 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic inline unsigned int btrfs_compress_type(unsigned int type_level) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return (type_level & 0xF); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic inline unsigned int btrfs_compress_level(unsigned int type_level) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci return ((type_level & 0xF0) >> 4); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciint __init btrfs_init_compress(void); 7862306a36Sopenharmony_civoid __cold btrfs_exit_compress(void); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ciint btrfs_compress_pages(unsigned int type_level, struct address_space *mapping, 8162306a36Sopenharmony_ci u64 start, struct page **pages, 8262306a36Sopenharmony_ci unsigned long *out_pages, 8362306a36Sopenharmony_ci unsigned long *total_in, 8462306a36Sopenharmony_ci unsigned long *total_out); 8562306a36Sopenharmony_ciint btrfs_decompress(int type, const u8 *data_in, struct page *dest_page, 8662306a36Sopenharmony_ci unsigned long start_byte, size_t srclen, size_t destlen); 8762306a36Sopenharmony_ciint btrfs_decompress_buf2page(const char *buf, u32 buf_len, 8862306a36Sopenharmony_ci struct compressed_bio *cb, u32 decompressed); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_civoid btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered, 9162306a36Sopenharmony_ci struct page **compressed_pages, 9262306a36Sopenharmony_ci unsigned int nr_pages, 9362306a36Sopenharmony_ci blk_opf_t write_flags, 9462306a36Sopenharmony_ci bool writeback); 9562306a36Sopenharmony_civoid btrfs_submit_compressed_read(struct btrfs_bio *bbio); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciunsigned int btrfs_compress_str2level(unsigned int type, const char *str); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cienum btrfs_compression_type { 10062306a36Sopenharmony_ci BTRFS_COMPRESS_NONE = 0, 10162306a36Sopenharmony_ci BTRFS_COMPRESS_ZLIB = 1, 10262306a36Sopenharmony_ci BTRFS_COMPRESS_LZO = 2, 10362306a36Sopenharmony_ci BTRFS_COMPRESS_ZSTD = 3, 10462306a36Sopenharmony_ci BTRFS_NR_COMPRESS_TYPES = 4, 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistruct workspace_manager { 10862306a36Sopenharmony_ci struct list_head idle_ws; 10962306a36Sopenharmony_ci spinlock_t ws_lock; 11062306a36Sopenharmony_ci /* Number of free workspaces */ 11162306a36Sopenharmony_ci int free_ws; 11262306a36Sopenharmony_ci /* Total number of allocated workspaces */ 11362306a36Sopenharmony_ci atomic_t total_ws; 11462306a36Sopenharmony_ci /* Waiters for a free workspace */ 11562306a36Sopenharmony_ci wait_queue_head_t ws_wait; 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistruct list_head *btrfs_get_workspace(int type, unsigned int level); 11962306a36Sopenharmony_civoid btrfs_put_workspace(int type, struct list_head *ws); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistruct btrfs_compress_op { 12262306a36Sopenharmony_ci struct workspace_manager *workspace_manager; 12362306a36Sopenharmony_ci /* Maximum level supported by the compression algorithm */ 12462306a36Sopenharmony_ci unsigned int max_level; 12562306a36Sopenharmony_ci unsigned int default_level; 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* The heuristic workspaces are managed via the 0th workspace manager */ 12962306a36Sopenharmony_ci#define BTRFS_NR_WORKSPACE_MANAGERS BTRFS_NR_COMPRESS_TYPES 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciextern const struct btrfs_compress_op btrfs_heuristic_compress; 13262306a36Sopenharmony_ciextern const struct btrfs_compress_op btrfs_zlib_compress; 13362306a36Sopenharmony_ciextern const struct btrfs_compress_op btrfs_lzo_compress; 13462306a36Sopenharmony_ciextern const struct btrfs_compress_op btrfs_zstd_compress; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ciconst char* btrfs_compress_type2str(enum btrfs_compression_type type); 13762306a36Sopenharmony_cibool btrfs_compress_is_valid_type(const char *str, size_t len); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ciint btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciint zlib_compress_pages(struct list_head *ws, struct address_space *mapping, 14262306a36Sopenharmony_ci u64 start, struct page **pages, unsigned long *out_pages, 14362306a36Sopenharmony_ci unsigned long *total_in, unsigned long *total_out); 14462306a36Sopenharmony_ciint zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb); 14562306a36Sopenharmony_ciint zlib_decompress(struct list_head *ws, const u8 *data_in, 14662306a36Sopenharmony_ci struct page *dest_page, unsigned long start_byte, size_t srclen, 14762306a36Sopenharmony_ci size_t destlen); 14862306a36Sopenharmony_cistruct list_head *zlib_alloc_workspace(unsigned int level); 14962306a36Sopenharmony_civoid zlib_free_workspace(struct list_head *ws); 15062306a36Sopenharmony_cistruct list_head *zlib_get_workspace(unsigned int level); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ciint lzo_compress_pages(struct list_head *ws, struct address_space *mapping, 15362306a36Sopenharmony_ci u64 start, struct page **pages, unsigned long *out_pages, 15462306a36Sopenharmony_ci unsigned long *total_in, unsigned long *total_out); 15562306a36Sopenharmony_ciint lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb); 15662306a36Sopenharmony_ciint lzo_decompress(struct list_head *ws, const u8 *data_in, 15762306a36Sopenharmony_ci struct page *dest_page, unsigned long start_byte, size_t srclen, 15862306a36Sopenharmony_ci size_t destlen); 15962306a36Sopenharmony_cistruct list_head *lzo_alloc_workspace(unsigned int level); 16062306a36Sopenharmony_civoid lzo_free_workspace(struct list_head *ws); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ciint zstd_compress_pages(struct list_head *ws, struct address_space *mapping, 16362306a36Sopenharmony_ci u64 start, struct page **pages, unsigned long *out_pages, 16462306a36Sopenharmony_ci unsigned long *total_in, unsigned long *total_out); 16562306a36Sopenharmony_ciint zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb); 16662306a36Sopenharmony_ciint zstd_decompress(struct list_head *ws, const u8 *data_in, 16762306a36Sopenharmony_ci struct page *dest_page, unsigned long start_byte, size_t srclen, 16862306a36Sopenharmony_ci size_t destlen); 16962306a36Sopenharmony_civoid zstd_init_workspace_manager(void); 17062306a36Sopenharmony_civoid zstd_cleanup_workspace_manager(void); 17162306a36Sopenharmony_cistruct list_head *zstd_alloc_workspace(unsigned int level); 17262306a36Sopenharmony_civoid zstd_free_workspace(struct list_head *ws); 17362306a36Sopenharmony_cistruct list_head *zstd_get_workspace(unsigned int level); 17462306a36Sopenharmony_civoid zstd_put_workspace(struct list_head *ws); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci#endif 177