mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-11-08 10:31:43 +01:00
ll_rw_block() function has been deprecated in favor of BIO which appears to come with large performance improvements. This patch decreases boot time by close to 40% when using squashfs for the root file-system. This is observed at least in the context of starting an Android VM on Chrome OS using crosvm. The patch was tested on 4.19 as well as master. This patch is largely based on Adrien Schildknecht's patch that was originally sent as https://lkml.org/lkml/2017/9/22/814 though with some significant changes and simplifications while also taking Phillip Lougher's feedback into account, around preserving support for FILE_CACHE in particular. [[email protected]: fix build error reported by Randy] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Philippe Liard <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Cc: Adrien Schildknecht <[email protected]> Cc: Phillip Lougher <[email protected]> Cc: Guenter Roeck <[email protected]> Cc: Daniel Rosenberg <[email protected]> Link: https://chromium.googlesource.com/chromiumos/platform/crosvm Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Linus Torvalds <[email protected]>
145 lines
3.0 KiB
C
145 lines
3.0 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Squashfs - a compressed read only filesystem for Linux
|
|
*
|
|
* Copyright (c) 2016-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* zstd_wrapper.c
|
|
*/
|
|
|
|
#include <linux/mutex.h>
|
|
#include <linux/bio.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/zstd.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include "squashfs_fs.h"
|
|
#include "squashfs_fs_sb.h"
|
|
#include "squashfs.h"
|
|
#include "decompressor.h"
|
|
#include "page_actor.h"
|
|
|
|
struct workspace {
|
|
void *mem;
|
|
size_t mem_size;
|
|
size_t window_size;
|
|
};
|
|
|
|
static void *zstd_init(struct squashfs_sb_info *msblk, void *buff)
|
|
{
|
|
struct workspace *wksp = kmalloc(sizeof(*wksp), GFP_KERNEL);
|
|
|
|
if (wksp == NULL)
|
|
goto failed;
|
|
wksp->window_size = max_t(size_t,
|
|
msblk->block_size, SQUASHFS_METADATA_SIZE);
|
|
wksp->mem_size = ZSTD_DStreamWorkspaceBound(wksp->window_size);
|
|
wksp->mem = vmalloc(wksp->mem_size);
|
|
if (wksp->mem == NULL)
|
|
goto failed;
|
|
|
|
return wksp;
|
|
|
|
failed:
|
|
ERROR("Failed to allocate zstd workspace\n");
|
|
kfree(wksp);
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
|
|
|
|
static void zstd_free(void *strm)
|
|
{
|
|
struct workspace *wksp = strm;
|
|
|
|
if (wksp)
|
|
vfree(wksp->mem);
|
|
kfree(wksp);
|
|
}
|
|
|
|
|
|
static int zstd_uncompress(struct squashfs_sb_info *msblk, void *strm,
|
|
struct bio *bio, int offset, int length,
|
|
struct squashfs_page_actor *output)
|
|
{
|
|
struct workspace *wksp = strm;
|
|
ZSTD_DStream *stream;
|
|
size_t total_out = 0;
|
|
int error = 0;
|
|
ZSTD_inBuffer in_buf = { NULL, 0, 0 };
|
|
ZSTD_outBuffer out_buf = { NULL, 0, 0 };
|
|
struct bvec_iter_all iter_all = {};
|
|
struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
|
|
|
|
stream = ZSTD_initDStream(wksp->window_size, wksp->mem, wksp->mem_size);
|
|
|
|
if (!stream) {
|
|
ERROR("Failed to initialize zstd decompressor\n");
|
|
return -EIO;
|
|
}
|
|
|
|
out_buf.size = PAGE_SIZE;
|
|
out_buf.dst = squashfs_first_page(output);
|
|
|
|
for (;;) {
|
|
size_t zstd_err;
|
|
|
|
if (in_buf.pos == in_buf.size) {
|
|
const void *data;
|
|
int avail;
|
|
|
|
if (!bio_next_segment(bio, &iter_all)) {
|
|
error = -EIO;
|
|
break;
|
|
}
|
|
|
|
avail = min(length, ((int)bvec->bv_len) - offset);
|
|
data = page_address(bvec->bv_page) + bvec->bv_offset;
|
|
length -= avail;
|
|
in_buf.src = data + offset;
|
|
in_buf.size = avail;
|
|
in_buf.pos = 0;
|
|
offset = 0;
|
|
}
|
|
|
|
if (out_buf.pos == out_buf.size) {
|
|
out_buf.dst = squashfs_next_page(output);
|
|
if (out_buf.dst == NULL) {
|
|
/* Shouldn't run out of pages
|
|
* before stream is done.
|
|
*/
|
|
error = -EIO;
|
|
break;
|
|
}
|
|
out_buf.pos = 0;
|
|
out_buf.size = PAGE_SIZE;
|
|
}
|
|
|
|
total_out -= out_buf.pos;
|
|
zstd_err = ZSTD_decompressStream(stream, &out_buf, &in_buf);
|
|
total_out += out_buf.pos; /* add the additional data produced */
|
|
if (zstd_err == 0)
|
|
break;
|
|
|
|
if (ZSTD_isError(zstd_err)) {
|
|
ERROR("zstd decompression error: %d\n",
|
|
(int)ZSTD_getErrorCode(zstd_err));
|
|
error = -EIO;
|
|
break;
|
|
}
|
|
}
|
|
|
|
squashfs_finish_page(output);
|
|
|
|
return error ? error : total_out;
|
|
}
|
|
|
|
const struct squashfs_decompressor squashfs_zstd_comp_ops = {
|
|
.init = zstd_init,
|
|
.free = zstd_free,
|
|
.decompress = zstd_uncompress,
|
|
.id = ZSTD_COMPRESSION,
|
|
.name = "zstd",
|
|
.supported = 1
|
|
};
|