18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2008 Oracle.  All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#ifndef BTRFS_COMPRESSION_H
78c2ecf20Sopenharmony_ci#define BTRFS_COMPRESSION_H
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/sizes.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistruct btrfs_inode;
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci * We want to make sure that amount of RAM required to uncompress an extent is
158c2ecf20Sopenharmony_ci * reasonable, so we limit the total size in ram of a compressed extent to
168c2ecf20Sopenharmony_ci * 128k.  This is a crucial number because it also controls how easily we can
178c2ecf20Sopenharmony_ci * spread reads across cpus for decompression.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * We also want to make sure the amount of IO required to do a random read is
208c2ecf20Sopenharmony_ci * reasonably small, so we limit the size of a compressed extent to 128k.
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* Maximum length of compressed data stored on disk */
248c2ecf20Sopenharmony_ci#define BTRFS_MAX_COMPRESSED		(SZ_128K)
258c2ecf20Sopenharmony_ci/* Maximum size of data before compression */
268c2ecf20Sopenharmony_ci#define BTRFS_MAX_UNCOMPRESSED		(SZ_128K)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define	BTRFS_ZLIB_DEFAULT_LEVEL		3
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct compressed_bio {
318c2ecf20Sopenharmony_ci	/* number of bios pending for this compressed extent */
328c2ecf20Sopenharmony_ci	refcount_t pending_bios;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	/* the pages with the compressed data on them */
358c2ecf20Sopenharmony_ci	struct page **compressed_pages;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	/* inode that owns this data */
388c2ecf20Sopenharmony_ci	struct inode *inode;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* starting offset in the inode for our pages */
418c2ecf20Sopenharmony_ci	u64 start;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	/* number of bytes in the inode we're working on */
448c2ecf20Sopenharmony_ci	unsigned long len;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	/* number of bytes on disk */
478c2ecf20Sopenharmony_ci	unsigned long compressed_len;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	/* the compression algorithm for this bio */
508c2ecf20Sopenharmony_ci	int compress_type;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	/* number of compressed pages in the array */
538c2ecf20Sopenharmony_ci	unsigned long nr_pages;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	/* IO errors */
568c2ecf20Sopenharmony_ci	int errors;
578c2ecf20Sopenharmony_ci	int mirror_num;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* for reads, this is the bio we are copying the data into */
608c2ecf20Sopenharmony_ci	struct bio *orig_bio;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/*
638c2ecf20Sopenharmony_ci	 * the start of a variable length array of checksums only
648c2ecf20Sopenharmony_ci	 * used by reads
658c2ecf20Sopenharmony_ci	 */
668c2ecf20Sopenharmony_ci	u8 sums[];
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic inline unsigned int btrfs_compress_type(unsigned int type_level)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	return (type_level & 0xF);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic inline unsigned int btrfs_compress_level(unsigned int type_level)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	return ((type_level & 0xF0) >> 4);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_civoid __init btrfs_init_compress(void);
808c2ecf20Sopenharmony_civoid __cold btrfs_exit_compress(void);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciint btrfs_compress_pages(unsigned int type_level, struct address_space *mapping,
838c2ecf20Sopenharmony_ci			 u64 start, struct page **pages,
848c2ecf20Sopenharmony_ci			 unsigned long *out_pages,
858c2ecf20Sopenharmony_ci			 unsigned long *total_in,
868c2ecf20Sopenharmony_ci			 unsigned long *total_out);
878c2ecf20Sopenharmony_ciint btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
888c2ecf20Sopenharmony_ci		     unsigned long start_byte, size_t srclen, size_t destlen);
898c2ecf20Sopenharmony_ciint btrfs_decompress_buf2page(const char *buf, unsigned long buf_start,
908c2ecf20Sopenharmony_ci			      unsigned long total_out, u64 disk_start,
918c2ecf20Sopenharmony_ci			      struct bio *bio);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ciblk_status_t btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start,
948c2ecf20Sopenharmony_ci				  unsigned long len, u64 disk_start,
958c2ecf20Sopenharmony_ci				  unsigned long compressed_len,
968c2ecf20Sopenharmony_ci				  struct page **compressed_pages,
978c2ecf20Sopenharmony_ci				  unsigned long nr_pages,
988c2ecf20Sopenharmony_ci				  unsigned int write_flags,
998c2ecf20Sopenharmony_ci				  struct cgroup_subsys_state *blkcg_css);
1008c2ecf20Sopenharmony_ciblk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
1018c2ecf20Sopenharmony_ci				 int mirror_num, unsigned long bio_flags);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ciunsigned int btrfs_compress_str2level(unsigned int type, const char *str);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cienum btrfs_compression_type {
1068c2ecf20Sopenharmony_ci	BTRFS_COMPRESS_NONE  = 0,
1078c2ecf20Sopenharmony_ci	BTRFS_COMPRESS_ZLIB  = 1,
1088c2ecf20Sopenharmony_ci	BTRFS_COMPRESS_LZO   = 2,
1098c2ecf20Sopenharmony_ci	BTRFS_COMPRESS_ZSTD  = 3,
1108c2ecf20Sopenharmony_ci	BTRFS_NR_COMPRESS_TYPES = 4,
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistruct workspace_manager {
1148c2ecf20Sopenharmony_ci	struct list_head idle_ws;
1158c2ecf20Sopenharmony_ci	spinlock_t ws_lock;
1168c2ecf20Sopenharmony_ci	/* Number of free workspaces */
1178c2ecf20Sopenharmony_ci	int free_ws;
1188c2ecf20Sopenharmony_ci	/* Total number of allocated workspaces */
1198c2ecf20Sopenharmony_ci	atomic_t total_ws;
1208c2ecf20Sopenharmony_ci	/* Waiters for a free workspace */
1218c2ecf20Sopenharmony_ci	wait_queue_head_t ws_wait;
1228c2ecf20Sopenharmony_ci};
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistruct list_head *btrfs_get_workspace(int type, unsigned int level);
1258c2ecf20Sopenharmony_civoid btrfs_put_workspace(int type, struct list_head *ws);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistruct btrfs_compress_op {
1288c2ecf20Sopenharmony_ci	struct workspace_manager *workspace_manager;
1298c2ecf20Sopenharmony_ci	/* Maximum level supported by the compression algorithm */
1308c2ecf20Sopenharmony_ci	unsigned int max_level;
1318c2ecf20Sopenharmony_ci	unsigned int default_level;
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci/* The heuristic workspaces are managed via the 0th workspace manager */
1358c2ecf20Sopenharmony_ci#define BTRFS_NR_WORKSPACE_MANAGERS	BTRFS_NR_COMPRESS_TYPES
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ciextern const struct btrfs_compress_op btrfs_heuristic_compress;
1388c2ecf20Sopenharmony_ciextern const struct btrfs_compress_op btrfs_zlib_compress;
1398c2ecf20Sopenharmony_ciextern const struct btrfs_compress_op btrfs_lzo_compress;
1408c2ecf20Sopenharmony_ciextern const struct btrfs_compress_op btrfs_zstd_compress;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ciconst char* btrfs_compress_type2str(enum btrfs_compression_type type);
1438c2ecf20Sopenharmony_cibool btrfs_compress_is_valid_type(const char *str, size_t len);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ciint btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ciint zlib_compress_pages(struct list_head *ws, struct address_space *mapping,
1488c2ecf20Sopenharmony_ci		u64 start, struct page **pages, unsigned long *out_pages,
1498c2ecf20Sopenharmony_ci		unsigned long *total_in, unsigned long *total_out);
1508c2ecf20Sopenharmony_ciint zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
1518c2ecf20Sopenharmony_ciint zlib_decompress(struct list_head *ws, unsigned char *data_in,
1528c2ecf20Sopenharmony_ci		struct page *dest_page, unsigned long start_byte, size_t srclen,
1538c2ecf20Sopenharmony_ci		size_t destlen);
1548c2ecf20Sopenharmony_cistruct list_head *zlib_alloc_workspace(unsigned int level);
1558c2ecf20Sopenharmony_civoid zlib_free_workspace(struct list_head *ws);
1568c2ecf20Sopenharmony_cistruct list_head *zlib_get_workspace(unsigned int level);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ciint lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
1598c2ecf20Sopenharmony_ci		u64 start, struct page **pages, unsigned long *out_pages,
1608c2ecf20Sopenharmony_ci		unsigned long *total_in, unsigned long *total_out);
1618c2ecf20Sopenharmony_ciint lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
1628c2ecf20Sopenharmony_ciint lzo_decompress(struct list_head *ws, unsigned char *data_in,
1638c2ecf20Sopenharmony_ci		struct page *dest_page, unsigned long start_byte, size_t srclen,
1648c2ecf20Sopenharmony_ci		size_t destlen);
1658c2ecf20Sopenharmony_cistruct list_head *lzo_alloc_workspace(unsigned int level);
1668c2ecf20Sopenharmony_civoid lzo_free_workspace(struct list_head *ws);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ciint zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
1698c2ecf20Sopenharmony_ci		u64 start, struct page **pages, unsigned long *out_pages,
1708c2ecf20Sopenharmony_ci		unsigned long *total_in, unsigned long *total_out);
1718c2ecf20Sopenharmony_ciint zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
1728c2ecf20Sopenharmony_ciint zstd_decompress(struct list_head *ws, unsigned char *data_in,
1738c2ecf20Sopenharmony_ci		struct page *dest_page, unsigned long start_byte, size_t srclen,
1748c2ecf20Sopenharmony_ci		size_t destlen);
1758c2ecf20Sopenharmony_civoid zstd_init_workspace_manager(void);
1768c2ecf20Sopenharmony_civoid zstd_cleanup_workspace_manager(void);
1778c2ecf20Sopenharmony_cistruct list_head *zstd_alloc_workspace(unsigned int level);
1788c2ecf20Sopenharmony_civoid zstd_free_workspace(struct list_head *ws);
1798c2ecf20Sopenharmony_cistruct list_head *zstd_get_workspace(unsigned int level);
1808c2ecf20Sopenharmony_civoid zstd_put_workspace(struct list_head *ws);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci#endif
183