// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2008 Oracle. All rights reserved.
*/
#include <linux/kernel.h>
#include <linux/bio.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
#include <linux/highmem.h>
#include <linux/kthread.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/backing-dev.h>
#include <linux/writeback.h>
#include <linux/psi.h>
#include <linux/slab.h>
#include <linux/sched/mm.h>
#include <linux/log2.h>
#include <linux/shrinker.h>
#include <crypto/hash.h>
#include "misc.h"
#include "ctree.h"
#include "fs.h"
#include "btrfs_inode.h"
#include "bio.h"
#include "ordered-data.h"
#include "compression.h"
#include "extent_io.h"
#include "extent_map.h"
#include "subpage.h"
#include "messages.h"
#include "super.h"
static struct bio_set btrfs_compressed_bioset;
static const char* const btrfs_compress_types[] = { "", "zlib", "lzo", "zstd" };
const char* btrfs_compress_type2str(enum btrfs_compression_type type)
{
switch (type) {
case BTRFS_COMPRESS_ZLIB:
case BTRFS_COMPRESS_LZO:
case BTRFS_COMPRESS_ZSTD:
case BTRFS_COMPRESS_NONE:
return btrfs_compress_types[type];
default:
break;
}
return NULL;
}
static inline struct compressed_bio *to_compressed_bio(struct btrfs_bio *bbio)
{
return container_of(bbio, struct compressed_bio, bbio);
}
static struct compressed_bio *alloc_compressed_bio(struct btrfs_inode *inode,
u64 start, blk_opf_t op,
btrfs_bio_end_io_t end_io)
{
struct btrfs_bio *bbio;
bbio = btrfs_bio(bio_alloc_bioset(NULL, BTRFS_MAX_COMPRESSED_PAGES, op,
GFP_NOFS, &btrfs_compressed_bioset));
btrfs_bio_init(bbio, inode->root->fs_info, end_io, NULL);
bbio->inode = inode;
bbio->file_offset = start;
return to_compressed_bio(bbio);
}
bool btrfs_compress_is_valid_type(const char *str, size_t len)
{
int i;
for (i = 1; i < ARRAY_SIZE(btrfs_compress_types); i++) {
size_t comp_len = strlen(btrfs_compress_types[i]);
if (len < comp_len)
continue;
if (!strncmp(btrfs_compress_types[i], str, comp_len))
return true;
}
return false;
}
static int compression_compress_pages(int type, struct list_head *ws,
struct address_space *mapping, u64 start,
struct folio **folios, unsigned long *out_folios,
unsigned long *total_in, unsigned long *total_out)
{
switch (type) {
case BTRFS_COMPRESS_ZLIB:
return zlib_compress_folios(ws, mapping, start, folios,
out_folios, total_in, total_out);
case BTRFS_COMPRESS_LZO:
return lzo_compress_folios(ws, mapping, start, folios,
out_folios, total_in, total_out);
case BTRFS_COMPRESS_ZSTD:
return zstd_compress_folios(ws, mapping, start, folios,
out_folios, total_in, total_out);
case BTRFS_COMPRESS_NONE:
default:
/*
* This can happen when compression races with remount setting
* it to 'no compress', while caller doesn't call
* inode_need_compress() to check if we really need to
* compress.
*
* Not a big deal, just need to inform caller that we
* haven't allocated any pages yet.
*/
*out_folios = 0;
return -E2BIG;
}
}
static int compression_decompress_bio(struct list_head *ws,
struct compressed_bio *cb)
{
switch (cb->compress_type) {
case BTRFS_COMPRESS_ZLIB: return zlib_decompress_bio(ws, cb);
case BTRFS_COMPRESS_LZO: return lzo_decompress_bio(ws, cb);
case BTRFS_COMPRESS_ZSTD: return zstd_decompress_bio(ws, cb);
case BTRFS_COMPRESS_NONE:
default:
/*
* This can't happen, the type is validated several times
* before we get here.
*/
BUG();
}
}
static int compression_decompress(int type, struct list_head *ws,
const u8 *data_in, struct folio *dest_folio,
unsigned long dest_pgoff, size_t srclen, size_t destlen)
{
switch (type) {
case BTRFS_COMPRESS_ZLIB: return zlib_decompres
|