Skip to content

Commit bba9596

Browse files
adam900710kdave
authored andcommitted
btrfs: zstd: introduce zstd_compress_bio() helper
The new helper has the following enhancements against the existing zstd_compress_folios() - Much smaller parameter list No more shared IN/OUT members, no need to pre-allocate a compressed_folios[] array. Just a workspace and compressed_bio pointer, everything we need can be extracted from that @cb pointer. - Ready-to-be-submitted compressed bio Although the caller still needs to do some common works like rounding up and zeroing the tailing part of the last fs block. Overall the workflow is the same as zstd_compress_folios(), but with some minor changes: - @start/@len is now constant For the current input file offset, use @start + @tot_in instead. The original change of @start and @len makes it pretty hard to know what value we're really comparing to. - No more @cur_len It's only utilized when switching input buffer. Directly use btrfs_calc_input_length() instead. Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Qu Wenruo <wqu@suse.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 3be8a78 commit bba9596

2 files changed

Lines changed: 187 additions & 0 deletions

File tree

fs/btrfs/compression.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ void lzo_free_workspace(struct list_head *ws);
172172
int zstd_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
173173
u64 start, struct folio **folios, unsigned long *out_folios,
174174
unsigned long *total_in, unsigned long *total_out);
175+
int zstd_compress_bio(struct list_head *ws, struct compressed_bio *cb);
175176
int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
176177
int zstd_decompress(struct list_head *ws, const u8 *data_in,
177178
struct folio *dest_folio, unsigned long dest_pgoff, size_t srclen,

fs/btrfs/zstd.c

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,192 @@ int zstd_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
585585
return ret;
586586
}
587587

588+
int zstd_compress_bio(struct list_head *ws, struct compressed_bio *cb)
589+
{
590+
struct btrfs_inode *inode = cb->bbio.inode;
591+
struct btrfs_fs_info *fs_info = inode->root->fs_info;
592+
struct workspace *workspace = list_entry(ws, struct workspace, list);
593+
struct address_space *mapping = inode->vfs_inode.i_mapping;
594+
struct bio *bio = &cb->bbio.bio;
595+
zstd_cstream *stream;
596+
int ret = 0;
597+
/* The current folio to read. */
598+
struct folio *in_folio = NULL;
599+
/* The current folio to write to. */
600+
struct folio *out_folio = NULL;
601+
unsigned long tot_in = 0;
602+
unsigned long tot_out = 0;
603+
const u64 start = cb->start;
604+
const u32 len = cb->len;
605+
const u64 end = start + len;
606+
const u32 blocksize = fs_info->sectorsize;
607+
const u32 min_folio_size = btrfs_min_folio_size(fs_info);
608+
609+
workspace->params = zstd_get_btrfs_parameters(workspace->req_level, len);
610+
611+
/* Initialize the stream. */
612+
stream = zstd_init_cstream(&workspace->params, len, workspace->mem, workspace->size);
613+
if (unlikely(!stream)) {
614+
btrfs_err(fs_info,
615+
"zstd compression init level %d failed, root %llu inode %llu offset %llu",
616+
workspace->req_level, btrfs_root_id(inode->root),
617+
btrfs_ino(inode), start);
618+
ret = -EIO;
619+
goto out;
620+
}
621+
622+
/* Map in the first page of input data. */
623+
ret = btrfs_compress_filemap_get_folio(mapping, start, &in_folio);
624+
if (ret < 0)
625+
goto out;
626+
workspace->in_buf.src = kmap_local_folio(in_folio, offset_in_folio(in_folio, start));
627+
workspace->in_buf.pos = 0;
628+
workspace->in_buf.size = btrfs_calc_input_length(in_folio, end, start);
629+
630+
/* Allocate and map in the output buffer. */
631+
out_folio = btrfs_alloc_compr_folio(fs_info);
632+
if (out_folio == NULL) {
633+
ret = -ENOMEM;
634+
goto out;
635+
}
636+
workspace->out_buf.dst = folio_address(out_folio);
637+
workspace->out_buf.pos = 0;
638+
workspace->out_buf.size = min_folio_size;
639+
640+
while (1) {
641+
size_t ret2;
642+
643+
ret2 = zstd_compress_stream(stream, &workspace->out_buf, &workspace->in_buf);
644+
if (unlikely(zstd_is_error(ret2))) {
645+
btrfs_warn(fs_info,
646+
"zstd compression level %d failed, error %d root %llu inode %llu offset %llu",
647+
workspace->req_level, zstd_get_error_code(ret2),
648+
btrfs_root_id(inode->root), btrfs_ino(inode),
649+
start + tot_in);
650+
ret = -EIO;
651+
goto out;
652+
}
653+
654+
/* Check to see if we are making it bigger. */
655+
if (tot_in + workspace->in_buf.pos > blocksize * 2 &&
656+
tot_in + workspace->in_buf.pos < tot_out + workspace->out_buf.pos) {
657+
ret = -E2BIG;
658+
goto out;
659+
}
660+
661+
/* Check if we need more output space. */
662+
if (workspace->out_buf.pos >= workspace->out_buf.size) {
663+
tot_out += min_folio_size;
664+
if (tot_out >= len) {
665+
ret = -E2BIG;
666+
goto out;
667+
}
668+
/* Queue the current foliot into the bio. */
669+
if (!bio_add_folio(bio, out_folio, folio_size(out_folio), 0)) {
670+
ret = -E2BIG;
671+
goto out;
672+
}
673+
674+
out_folio = btrfs_alloc_compr_folio(fs_info);
675+
if (out_folio == NULL) {
676+
ret = -ENOMEM;
677+
goto out;
678+
}
679+
workspace->out_buf.dst = folio_address(out_folio);
680+
workspace->out_buf.pos = 0;
681+
workspace->out_buf.size = min_folio_size;
682+
}
683+
684+
/* We've reached the end of the input. */
685+
if (tot_in + workspace->in_buf.pos >= len) {
686+
tot_in += workspace->in_buf.pos;
687+
break;
688+
}
689+
690+
/* Check if we need more input. */
691+
if (workspace->in_buf.pos >= workspace->in_buf.size) {
692+
u64 cur;
693+
694+
tot_in += workspace->in_buf.size;
695+
cur = start + tot_in;
696+
697+
kunmap_local(workspace->in_buf.src);
698+
workspace->in_buf.src = NULL;
699+
folio_put(in_folio);
700+
701+
ret = btrfs_compress_filemap_get_folio(mapping, cur, &in_folio);
702+
if (ret < 0)
703+
goto out;
704+
workspace->in_buf.src = kmap_local_folio(in_folio,
705+
offset_in_folio(in_folio, cur));
706+
workspace->in_buf.pos = 0;
707+
workspace->in_buf.size = btrfs_calc_input_length(in_folio, end, cur);
708+
}
709+
}
710+
711+
while (1) {
712+
size_t ret2;
713+
714+
ret2 = zstd_end_stream(stream, &workspace->out_buf);
715+
if (unlikely(zstd_is_error(ret2))) {
716+
btrfs_err(fs_info,
717+
"zstd compression end level %d failed, error %d root %llu inode %llu offset %llu",
718+
workspace->req_level, zstd_get_error_code(ret2),
719+
btrfs_root_id(inode->root), btrfs_ino(inode),
720+
start + tot_in);
721+
ret = -EIO;
722+
goto out;
723+
}
724+
/* Queue the remaining part of the output folio into bio. */
725+
if (ret2 == 0) {
726+
tot_out += workspace->out_buf.pos;
727+
if (tot_out >= len) {
728+
ret = -E2BIG;
729+
goto out;
730+
}
731+
if (!bio_add_folio(bio, out_folio, workspace->out_buf.pos, 0)) {
732+
ret = -E2BIG;
733+
goto out;
734+
}
735+
out_folio = NULL;
736+
break;
737+
}
738+
tot_out += min_folio_size;
739+
if (tot_out >= len) {
740+
ret = -E2BIG;
741+
goto out;
742+
}
743+
if (!bio_add_folio(bio, out_folio, folio_size(out_folio), 0)) {
744+
ret = -E2BIG;
745+
goto out;
746+
}
747+
out_folio = btrfs_alloc_compr_folio(fs_info);
748+
if (out_folio == NULL) {
749+
ret = -ENOMEM;
750+
goto out;
751+
}
752+
workspace->out_buf.dst = folio_address(out_folio);
753+
workspace->out_buf.pos = 0;
754+
workspace->out_buf.size = min_folio_size;
755+
}
756+
757+
if (tot_out >= tot_in) {
758+
ret = -E2BIG;
759+
goto out;
760+
}
761+
762+
ret = 0;
763+
ASSERT(tot_out == bio->bi_iter.bi_size);
764+
out:
765+
if (out_folio)
766+
btrfs_free_compr_folio(out_folio);
767+
if (workspace->in_buf.src) {
768+
kunmap_local(workspace->in_buf.src);
769+
folio_put(in_folio);
770+
}
771+
return ret;
772+
}
773+
588774
int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb)
589775
{
590776
struct btrfs_fs_info *fs_info = cb_to_fs_info(cb);

0 commit comments

Comments
 (0)