#include "super-io.h"
#include <linux/lz4.h>
-#include <linux/sched/mm.h>
#include <linux/zlib.h>
#include <linux/zstd.h>
{
void *b;
- BUG_ON(size > c->sb.encoded_extent_max << 9);
+ BUG_ON(size > c->opts.encoded_extent_max);
- b = kmalloc(size, GFP_NOIO|__GFP_NOWARN);
+ b = kmalloc(size, GFP_NOFS|__GFP_NOWARN);
if (b)
return (struct bbuf) { .b = b, .type = BB_KMALLOC, .rw = rw };
- b = mempool_alloc(&c->compression_bounce[rw], GFP_NOIO);
+ b = mempool_alloc(&c->compression_bounce[rw], GFP_NOFS);
if (b)
return (struct bbuf) { .b = b, .type = BB_MEMPOOL, .rw = rw };
struct bbuf ret;
struct bio_vec bv;
struct bvec_iter iter;
- unsigned nr_pages = 0, flags;
+ unsigned nr_pages = 0;
struct page *stack_pages[16];
struct page **pages = NULL;
void *data;
- BUG_ON(bvec_iter_sectors(start) > c->sb.encoded_extent_max);
+ BUG_ON(start.bi_size > c->opts.encoded_extent_max);
- if (!IS_ENABLED(CONFIG_HIGHMEM) &&
+ if (!PageHighMem(bio_iter_page(bio, start)) &&
bio_phys_contig(bio, start))
return (struct bbuf) {
.b = page_address(bio_iter_page(bio, start)) +
BUG_ON(DIV_ROUND_UP(start.bi_size, PAGE_SIZE) > nr_pages);
pages = nr_pages > ARRAY_SIZE(stack_pages)
- ? kmalloc_array(nr_pages, sizeof(struct page *), GFP_NOIO)
+ ? kmalloc_array(nr_pages, sizeof(struct page *), GFP_NOFS)
: stack_pages;
if (!pages)
goto bounce;
__bio_for_each_segment(bv, bio, iter, start)
pages[nr_pages++] = bv.bv_page;
- flags = memalloc_nofs_save();
data = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
- memalloc_nofs_restore(flags);
-
if (pages != stack_pages)
kfree(pages);
.avail_out = dst_len,
};
- workspace = mempool_alloc(&c->decompress_workspace, GFP_NOIO);
+ workspace = mempool_alloc(&c->decompress_workspace, GFP_NOFS);
zlib_set_workspace(&strm, workspace);
zlib_inflateInit2(&strm, -MAX_WBITS);
if (real_src_len > src_len - 4)
goto err;
- workspace = mempool_alloc(&c->decompress_workspace, GFP_NOIO);
- ctx = ZSTD_initDCtx(workspace, ZSTD_DCtxWorkspaceBound());
+ workspace = mempool_alloc(&c->decompress_workspace, GFP_NOFS);
+ ctx = zstd_init_dctx(workspace, zstd_dctx_workspace_bound());
- ret = ZSTD_decompressDCtx(ctx,
+ ret = zstd_decompress_dctx(ctx,
dst_data, dst_len,
src_data.b + 4, real_src_len);
BUG_ON(!bio->bi_vcnt);
BUG_ON(DIV_ROUND_UP(crc->live_size, PAGE_SECTORS) > bio->bi_max_vecs);
- if (crc->uncompressed_size > c->sb.encoded_extent_max ||
- crc->compressed_size > c->sb.encoded_extent_max) {
+ if (crc->uncompressed_size << 9 > c->opts.encoded_extent_max ||
+ crc->compressed_size << 9 > c->opts.encoded_extent_max) {
bch_err(c, "error rewriting existing data: extent too big");
return -EIO;
}
{
struct bbuf dst_data = { NULL };
size_t dst_len = crc.uncompressed_size << 9;
- int ret = -ENOMEM;
+ int ret;
- if (crc.uncompressed_size > c->sb.encoded_extent_max ||
- crc.compressed_size > c->sb.encoded_extent_max)
+ if (crc.uncompressed_size << 9 > c->opts.encoded_extent_max ||
+ crc.compressed_size << 9 > c->opts.encoded_extent_max)
return -EIO;
dst_data = dst_len == dst_iter.bi_size
return strm.total_out;
}
case BCH_COMPRESSION_TYPE_zstd: {
- ZSTD_CCtx *ctx = ZSTD_initCCtx(workspace,
- ZSTD_CCtxWorkspaceBound(c->zstd_params.cParams));
+ ZSTD_CCtx *ctx = zstd_init_cctx(workspace,
+ zstd_cctx_workspace_bound(&c->zstd_params.cParams));
- size_t len = ZSTD_compressCCtx(ctx,
- dst + 4, dst_len - 4,
+ /*
+ * ZSTD requires that when we decompress we pass in the exact
+ * compressed size - rounding it up to the nearest sector
+ * doesn't work, so we use the first 4 bytes of the buffer for
+ * that.
+ *
+ * Additionally, the ZSTD code seems to have a bug where it will
+ * write just past the end of the buffer - so subtract a fudge
+ * factor (7 bytes) from the dst buffer size to account for
+ * that.
+ */
+ size_t len = zstd_compress_cctx(ctx,
+ dst + 4, dst_len - 4 - 7,
src, src_len,
- c->zstd_params);
- if (ZSTD_isError(len))
+ &c->zstd_params);
+ if (zstd_is_error(len))
return 0;
*((__le32 *) dst) = cpu_to_le32(len);
BUG_ON(!mempool_initialized(&c->compress_workspace[compression_type]));
/* If it's only one block, don't bother trying to compress: */
- if (bio_sectors(src) <= c->opts.block_size)
- return 0;
+ if (src->bi_iter.bi_size <= c->opts.block_size)
+ return BCH_COMPRESSION_TYPE_incompressible;
dst_data = bio_map_or_bounce(c, dst, WRITE);
src_data = bio_map_or_bounce(c, src, READ);
- workspace = mempool_alloc(&c->compress_workspace[compression_type], GFP_NOIO);
+ workspace = mempool_alloc(&c->compress_workspace[compression_type], GFP_NOFS);
*src_len = src->bi_iter.bi_size;
*dst_len = dst->bi_iter.bi_size;
/* Don't consume more than BCH_ENCODED_EXTENT_MAX from @src: */
src->bi_iter.bi_size = min_t(unsigned, src->bi_iter.bi_size,
- c->sb.encoded_extent_max << 9);
+ c->opts.encoded_extent_max);
/* Don't generate a bigger output than input: */
dst->bi_iter.bi_size = min(dst->bi_iter.bi_size, src->bi_iter.bi_size);
mempool_exit(&c->compression_bounce[READ]);
}
-static int __bch2_fs_compress_init(struct bch_fs *c, u64 features)
+static int _bch2_fs_compress_init(struct bch_fs *c, u64 features)
{
- size_t max_extent = c->sb.encoded_extent_max << 9;
size_t decompress_workspace_size = 0;
bool decompress_workspace_needed;
- ZSTD_parameters params = ZSTD_getParams(0, max_extent, 0);
+ ZSTD_parameters params = zstd_get_params(0, c->opts.encoded_extent_max);
struct {
unsigned feature;
unsigned type;
zlib_deflate_workspacesize(MAX_WBITS, DEF_MEM_LEVEL),
zlib_inflate_workspacesize(), },
{ BCH_FEATURE_zstd, BCH_COMPRESSION_TYPE_zstd,
- ZSTD_CCtxWorkspaceBound(params.cParams),
- ZSTD_DCtxWorkspaceBound() },
+ zstd_cctx_workspace_bound(¶ms.cParams),
+ zstd_dctx_workspace_bound() },
}, *i;
- int ret = 0;
-
- pr_verbose_init(c->opts, "");
+ bool have_compressed = false;
c->zstd_params = params;
for (i = compression_types;
i < compression_types + ARRAY_SIZE(compression_types);
i++)
- if (features & (1 << i->feature))
- goto have_compressed;
+ have_compressed |= (features & (1 << i->feature)) != 0;
- goto out;
-have_compressed:
+ if (!have_compressed)
+ return 0;
- if (!mempool_initialized(&c->compression_bounce[READ])) {
- ret = mempool_init_kvpmalloc_pool(&c->compression_bounce[READ],
- 1, max_extent);
- if (ret)
- goto out;
- }
+ if (!mempool_initialized(&c->compression_bounce[READ]) &&
+ mempool_init_kvpmalloc_pool(&c->compression_bounce[READ],
+ 1, c->opts.encoded_extent_max))
+ return -BCH_ERR_ENOMEM_compression_bounce_read_init;
- if (!mempool_initialized(&c->compression_bounce[WRITE])) {
- ret = mempool_init_kvpmalloc_pool(&c->compression_bounce[WRITE],
- 1, max_extent);
- if (ret)
- goto out;
- }
+ if (!mempool_initialized(&c->compression_bounce[WRITE]) &&
+ mempool_init_kvpmalloc_pool(&c->compression_bounce[WRITE],
+ 1, c->opts.encoded_extent_max))
+ return -BCH_ERR_ENOMEM_compression_bounce_write_init;
for (i = compression_types;
i < compression_types + ARRAY_SIZE(compression_types);
if (mempool_initialized(&c->compress_workspace[i->type]))
continue;
- ret = mempool_init_kvpmalloc_pool(
+ if (mempool_init_kvpmalloc_pool(
&c->compress_workspace[i->type],
- 1, i->compress_workspace);
- if (ret)
- goto out;
+ 1, i->compress_workspace))
+ return -BCH_ERR_ENOMEM_compression_workspace_init;
}
- if (!mempool_initialized(&c->decompress_workspace)) {
- ret = mempool_init_kvpmalloc_pool(
- &c->decompress_workspace,
- 1, decompress_workspace_size);
- if (ret)
- goto out;
- }
-out:
+ if (!mempool_initialized(&c->decompress_workspace) &&
+ mempool_init_kvpmalloc_pool(&c->decompress_workspace,
+ 1, decompress_workspace_size))
+ return -BCH_ERR_ENOMEM_decompression_workspace_init;
+
+ return 0;
+}
+
+static int __bch2_fs_compress_init(struct bch_fs *c, u64 features)
+{
+ int ret;
+
+ pr_verbose_init(c->opts, "");
+ ret = _bch2_fs_compress_init(c, features);
pr_verbose_init(c->opts, "ret %i", ret);
+
return ret;
}