@@ -334,6 +334,200 @@ int zlib_compress_folios(struct list_head *ws, struct btrfs_inode *inode,
334334 return ret ;
335335}
336336
337+ int zlib_compress_bio (struct list_head * ws , struct compressed_bio * cb )
338+ {
339+ struct btrfs_inode * inode = cb -> bbio .inode ;
340+ struct btrfs_fs_info * fs_info = inode -> root -> fs_info ;
341+ struct workspace * workspace = list_entry (ws , struct workspace , list );
342+ struct address_space * mapping = inode -> vfs_inode .i_mapping ;
343+ struct bio * bio = & cb -> bbio .bio ;
344+ u64 start = cb -> start ;
345+ u32 len = cb -> len ;
346+ const u32 min_folio_size = btrfs_min_folio_size (fs_info );
347+ int ret ;
348+ char * data_in = NULL ;
349+ char * cfolio_out ;
350+ struct folio * in_folio = NULL ;
351+ struct folio * out_folio = NULL ;
352+ const u32 blocksize = fs_info -> sectorsize ;
353+ const u64 orig_end = start + len ;
354+
355+ ret = zlib_deflateInit (& workspace -> strm , workspace -> level );
356+ if (unlikely (ret != Z_OK )) {
357+ btrfs_err (fs_info ,
358+ "zlib compression init failed, error %d root %llu inode %llu offset %llu" ,
359+ ret , btrfs_root_id (inode -> root ), btrfs_ino (inode ), start );
360+ ret = - EIO ;
361+ goto out ;
362+ }
363+
364+ workspace -> strm .total_in = 0 ;
365+ workspace -> strm .total_out = 0 ;
366+
367+ out_folio = btrfs_alloc_compr_folio (fs_info );
368+ if (out_folio == NULL ) {
369+ ret = - ENOMEM ;
370+ goto out ;
371+ }
372+ cfolio_out = folio_address (out_folio );
373+
374+ workspace -> strm .next_in = workspace -> buf ;
375+ workspace -> strm .avail_in = 0 ;
376+ workspace -> strm .next_out = cfolio_out ;
377+ workspace -> strm .avail_out = min_folio_size ;
378+
379+ while (workspace -> strm .total_in < len ) {
380+ /*
381+ * Get next input pages and copy the contents to the workspace
382+ * buffer if required.
383+ */
384+ if (workspace -> strm .avail_in == 0 ) {
385+ unsigned long bytes_left = len - workspace -> strm .total_in ;
386+ unsigned int copy_length = min (bytes_left , workspace -> buf_size );
387+
388+ /*
389+ * For s390 hardware accelerated zlib, and our folio is smaller
390+ * than the copy_length, we need to fill the buffer so that
391+ * we can take full advantage of hardware acceleration.
392+ */
393+ if (need_special_buffer (fs_info )) {
394+ ret = copy_data_into_buffer (mapping , workspace ,
395+ start , copy_length );
396+ if (ret < 0 )
397+ goto out ;
398+ start += copy_length ;
399+ workspace -> strm .next_in = workspace -> buf ;
400+ workspace -> strm .avail_in = copy_length ;
401+ } else {
402+ unsigned int cur_len ;
403+
404+ if (data_in ) {
405+ kunmap_local (data_in );
406+ folio_put (in_folio );
407+ data_in = NULL ;
408+ }
409+ ret = btrfs_compress_filemap_get_folio (mapping ,
410+ start , & in_folio );
411+ if (ret < 0 )
412+ goto out ;
413+ cur_len = btrfs_calc_input_length (in_folio , orig_end , start );
414+ data_in = kmap_local_folio (in_folio ,
415+ offset_in_folio (in_folio , start ));
416+ start += cur_len ;
417+ workspace -> strm .next_in = data_in ;
418+ workspace -> strm .avail_in = cur_len ;
419+ }
420+ }
421+
422+ ret = zlib_deflate (& workspace -> strm , Z_SYNC_FLUSH );
423+ if (unlikely (ret != Z_OK )) {
424+ btrfs_warn (fs_info ,
425+ "zlib compression failed, error %d root %llu inode %llu offset %llu" ,
426+ ret , btrfs_root_id (inode -> root ), btrfs_ino (inode ),
427+ start );
428+ zlib_deflateEnd (& workspace -> strm );
429+ ret = - EIO ;
430+ goto out ;
431+ }
432+
433+ /* We're making it bigger, give up. */
434+ if (workspace -> strm .total_in > blocksize * 2 &&
435+ workspace -> strm .total_in < workspace -> strm .total_out ) {
436+ ret = - E2BIG ;
437+ goto out ;
438+ }
439+ if (workspace -> strm .total_out >= len ) {
440+ ret = - E2BIG ;
441+ goto out ;
442+ }
443+ /* Queue the full folio and allocate a new one. */
444+ if (workspace -> strm .avail_out == 0 ) {
445+ if (!bio_add_folio (bio , out_folio , folio_size (out_folio ), 0 )) {
446+ ret = - E2BIG ;
447+ goto out ;
448+ }
449+
450+ out_folio = btrfs_alloc_compr_folio (fs_info );
451+ if (out_folio == NULL ) {
452+ ret = - ENOMEM ;
453+ goto out ;
454+ }
455+ cfolio_out = folio_address (out_folio );
456+ workspace -> strm .avail_out = min_folio_size ;
457+ workspace -> strm .next_out = cfolio_out ;
458+ }
459+ /* We're all done. */
460+ if (workspace -> strm .total_in >= len )
461+ break ;
462+ }
463+
464+ workspace -> strm .avail_in = 0 ;
465+
466+ /*
467+ * Call deflate with Z_FINISH flush parameter providing more output
468+ * space but no more input data, until it returns with Z_STREAM_END.
469+ */
470+ while (ret != Z_STREAM_END ) {
471+ ret = zlib_deflate (& workspace -> strm , Z_FINISH );
472+ if (ret == Z_STREAM_END )
473+ break ;
474+ if (unlikely (ret != Z_OK && ret != Z_BUF_ERROR )) {
475+ zlib_deflateEnd (& workspace -> strm );
476+ ret = - EIO ;
477+ goto out ;
478+ } else if (workspace -> strm .avail_out == 0 ) {
479+ if (workspace -> strm .total_out >= len ) {
480+ ret = - E2BIG ;
481+ goto out ;
482+ }
483+ if (!bio_add_folio (bio , out_folio , folio_size (out_folio ), 0 )) {
484+ ret = - E2BIG ;
485+ goto out ;
486+ }
487+ /* Get another folio for the stream end. */
488+ out_folio = btrfs_alloc_compr_folio (fs_info );
489+ if (out_folio == NULL ) {
490+ ret = - ENOMEM ;
491+ goto out ;
492+ }
493+ cfolio_out = folio_address (out_folio );
494+ workspace -> strm .avail_out = min_folio_size ;
495+ workspace -> strm .next_out = cfolio_out ;
496+ }
497+ }
498+ /* Queue the remaining part of the folio. */
499+ if (workspace -> strm .total_out > bio -> bi_iter .bi_size ) {
500+ u32 cur_len = offset_in_folio (out_folio , workspace -> strm .total_out );
501+
502+ if (!bio_add_folio (bio , out_folio , cur_len , 0 )) {
503+ ret = - E2BIG ;
504+ goto out ;
505+ }
506+ } else {
507+ /* The last folio hasn't' been utilized. */
508+ btrfs_free_compr_folio (out_folio );
509+ }
510+ out_folio = NULL ;
511+ ASSERT (bio -> bi_iter .bi_size == workspace -> strm .total_out );
512+ zlib_deflateEnd (& workspace -> strm );
513+
514+ if (workspace -> strm .total_out >= workspace -> strm .total_in ) {
515+ ret = - E2BIG ;
516+ goto out ;
517+ }
518+
519+ ret = 0 ;
520+ out :
521+ if (out_folio )
522+ btrfs_free_compr_folio (out_folio );
523+ if (data_in ) {
524+ kunmap_local (data_in );
525+ folio_put (in_folio );
526+ }
527+
528+ return ret ;
529+ }
530+
337531int zlib_decompress_bio (struct list_head * ws , struct compressed_bio * cb )
338532{
339533 struct btrfs_fs_info * fs_info = cb_to_fs_info (cb );
0 commit comments