@@ -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+
588774int 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