32
32
#include <zstd_errors.h>
33
33
#endif
34
34
#include <zlib.h>
35
+ #if COMPRESSION_LZO
36
+ #include <lzo/lzo1x.h>
37
+ #endif
35
38
#include "kernel-lib/sizes.h"
36
39
#include "kernel-shared/accessors.h"
37
40
#include "kernel-shared/uapi/btrfs_tree.h"
57
60
#define ZSTD_BTRFS_DEFAULT_LEVEL 3
58
61
#define ZSTD_BTRFS_MAX_LEVEL 15
59
62
63
+ #define LZO_LEN 4
64
+
60
65
static u32 fs_block_size ;
61
66
62
67
/*
@@ -526,6 +531,67 @@ static ssize_t zlib_compress_extent(bool first_sector, u32 sectorsize,
526
531
return - E2BIG ;
527
532
}
528
533
534
+ #if COMPRESSION_LZO
535
+ /*
536
+ * Returns the size of the compressed data if successful, -E2BIG if it is
537
+ * incompressible, or an error code.
538
+ */
539
+ static ssize_t lzo_compress_extent (u32 sectorsize , const void * in_buf ,
540
+ size_t in_size , void * out_buf , char * wrkmem )
541
+ {
542
+ int ret ;
543
+ unsigned int sectors ;
544
+ u32 total_size , out_pos ;
545
+
546
+ out_pos = LZO_LEN ;
547
+ total_size = LZO_LEN ;
548
+ sectors = DIV_ROUND_UP (in_size , sectorsize );
549
+
550
+ for (unsigned int i = 0 ; i < sectors ; i ++ ) {
551
+ lzo_uint in_len , out_len ;
552
+ size_t new_pos ;
553
+ u32 padding ;
554
+
555
+ in_len = min ((size_t )sectorsize , in_size - (i * sectorsize ));
556
+
557
+ ret = lzo1x_1_compress (in_buf + (i * sectorsize ), in_len ,
558
+ out_buf + out_pos + LZO_LEN , & out_len ,
559
+ wrkmem );
560
+ if (ret ) {
561
+ error ("lzo1x_1_compress returned %i" , ret );
562
+ return - EINVAL ;
563
+ }
564
+
565
+ put_unaligned_le32 (out_len , out_buf + out_pos );
566
+
567
+ new_pos = out_pos + LZO_LEN + out_len ;
568
+
569
+ /* Make sure that our header doesn't cross a sector boundary. */
570
+ if (new_pos / sectorsize != (new_pos + LZO_LEN - 1 ) / sectorsize )
571
+ padding = round_up (new_pos , LZO_LEN ) - new_pos ;
572
+ else
573
+ padding = 0 ;
574
+
575
+ out_pos += out_len + LZO_LEN + padding ;
576
+ total_size += out_len + LZO_LEN + padding ;
577
+
578
+ /*
579
+ * Follow kernel in trying to compress the first three sectors,
580
+ * then giving up if the output isn't any smaller.
581
+ */
582
+ if (i >= 3 && total_size > i * sectorsize )
583
+ return - E2BIG ;
584
+ }
585
+
586
+ if (total_size > in_size )
587
+ return - E2BIG ;
588
+
589
+ put_unaligned_le32 (total_size , out_buf );
590
+
591
+ return total_size ;
592
+ }
593
+ #endif
594
+
529
595
#if COMPRESSION_ZSTD
530
596
/*
531
597
* Returns the size of the compressed data if successful, -E2BIG if it is
@@ -629,6 +695,7 @@ struct source_descriptor {
629
695
u64 size ;
630
696
const char * path_name ;
631
697
char * comp_buf ;
698
+ char * wrkmem ;
632
699
};
633
700
634
701
static int add_file_item_extent (struct btrfs_trans_handle * trans ,
@@ -684,6 +751,14 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
684
751
source -> buf , bytes_read ,
685
752
source -> comp_buf );
686
753
break ;
754
+ #if COMPRESSION_LZO
755
+ case BTRFS_COMPRESS_LZO :
756
+ comp_ret = lzo_compress_extent (sectorsize , source -> buf ,
757
+ bytes_read ,
758
+ source -> comp_buf ,
759
+ source -> wrkmem );
760
+ break ;
761
+ #endif
687
762
#if COMPRESSION_ZSTD
688
763
case BTRFS_COMPRESS_ZSTD :
689
764
comp_ret = zstd_compress_extent (first_sector , sectorsize ,
@@ -748,6 +823,11 @@ static int add_file_item_extent(struct btrfs_trans_handle *trans,
748
823
features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD ;
749
824
btrfs_set_super_incompat_flags (trans -> fs_info -> super_copy ,
750
825
features );
826
+ } else if (g_compression == BTRFS_COMPRESS_LZO ) {
827
+ features = btrfs_super_incompat_flags (trans -> fs_info -> super_copy );
828
+ features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO ;
829
+ btrfs_set_super_incompat_flags (trans -> fs_info -> super_copy ,
830
+ features );
751
831
}
752
832
} else {
753
833
to_write = round_up (to_read , sectorsize );
@@ -849,6 +929,63 @@ static ssize_t zlib_compress_inline_extent(char *buf, u64 size, char **comp_buf)
849
929
return ret ;
850
930
}
851
931
932
+ #if COMPRESSION_LZO
933
+ static u32 lzo_max_outlen (u32 inlen ) {
934
+ /*
935
+ * Return the worst-case output length for LZO. Formula comes from
936
+ * LZO.FAQ.
937
+ */
938
+ return inlen + (inlen / 16 ) + 64 + 3 ;
939
+ }
940
+
941
+ /*
942
+ * Returns the size of the compressed data if successful, -E2BIG if it is
943
+ * incompressible, or an error code.
944
+ */
945
+ static ssize_t lzo_compress_inline_extent (void * buf , u64 size , char * * comp_buf ,
946
+ char * wrkmem )
947
+ {
948
+ ssize_t ret ;
949
+ lzo_uint out_len ;
950
+ size_t out_size ;
951
+ void * out = NULL ;
952
+
953
+ out_size = LZO_LEN + LZO_LEN + lzo_max_outlen (size );
954
+
955
+ out = malloc (out_size );
956
+ if (!out ) {
957
+ error_msg (ERROR_MSG_MEMORY , NULL );
958
+ ret = - ENOMEM ;
959
+ goto out ;
960
+ }
961
+
962
+ ret = lzo1x_1_compress (buf , size , out + LZO_LEN + LZO_LEN , & out_len ,
963
+ wrkmem );
964
+ if (ret ) {
965
+ error ("lzo1x_1_compress returned %zi" , ret );
966
+ ret = - EINVAL ;
967
+ goto out ;
968
+ }
969
+
970
+ if (out_len + LZO_LEN + LZO_LEN >= size ) {
971
+ ret = - E2BIG ;
972
+ goto out ;
973
+ }
974
+
975
+ put_unaligned_le32 (out_len + LZO_LEN + LZO_LEN , out );
976
+ put_unaligned_le32 (out_len , out + LZO_LEN );
977
+
978
+ * comp_buf = out ;
979
+ ret = out_len + LZO_LEN + LZO_LEN ;
980
+
981
+ out :
982
+ if (ret < 0 )
983
+ free (out );
984
+
985
+ return ret ;
986
+ }
987
+ #endif
988
+
852
989
#if COMPRESSION_ZSTD
853
990
/*
854
991
* Returns the size of the compressed data if successful, -E2BIG if it is
@@ -937,7 +1074,7 @@ static int add_file_items(struct btrfs_trans_handle *trans,
937
1074
ssize_t ret_read ;
938
1075
u32 sectorsize = fs_info -> sectorsize ;
939
1076
u64 file_pos = 0 ;
940
- char * buf = NULL , * comp_buf = NULL ;
1077
+ char * buf = NULL , * comp_buf = NULL , * wrkmem = NULL ;
941
1078
struct source_descriptor source ;
942
1079
int fd ;
943
1080
@@ -950,6 +1087,20 @@ static int add_file_items(struct btrfs_trans_handle *trans,
950
1087
return ret ;
951
1088
}
952
1089
1090
+ if (g_compression == BTRFS_COMPRESS_LZO ) {
1091
+ #if COMPRESSION_LZO
1092
+ wrkmem = malloc (LZO1X_1_MEM_COMPRESS );
1093
+ if (!wrkmem ) {
1094
+ ret = - ENOMEM ;
1095
+ goto end ;
1096
+ }
1097
+ #else
1098
+ error ("lzo support not compiled in" );
1099
+ ret = - EINVAL ;
1100
+ goto end ;
1101
+ #endif
1102
+ }
1103
+
953
1104
if (st -> st_size <= BTRFS_MAX_INLINE_DATA_SIZE (fs_info ) &&
954
1105
st -> st_size < sectorsize ) {
955
1106
char * buffer = malloc (st -> st_size );
@@ -972,6 +1123,12 @@ static int add_file_items(struct btrfs_trans_handle *trans,
972
1123
ret = zlib_compress_inline_extent (buffer , st -> st_size ,
973
1124
& comp_buf );
974
1125
break ;
1126
+ #if COMPRESSION_LZO
1127
+ case BTRFS_COMPRESS_LZO :
1128
+ ret = lzo_compress_inline_extent (buffer , st -> st_size ,
1129
+ & comp_buf , wrkmem );
1130
+ break ;
1131
+ #endif
975
1132
#if COMPRESSION_ZSTD
976
1133
case BTRFS_COMPRESS_ZSTD :
977
1134
ret = zstd_compress_inline_extent (buffer , st -> st_size ,
@@ -1007,7 +1164,47 @@ static int add_file_items(struct btrfs_trans_handle *trans,
1007
1164
goto end ;
1008
1165
}
1009
1166
1010
- if (g_compression != BTRFS_COMPRESS_NONE ) {
1167
+ if (g_compression == BTRFS_COMPRESS_LZO ) {
1168
+ #if COMPRESSION_LZO
1169
+ unsigned int sectors ;
1170
+ size_t comp_buf_len ;
1171
+
1172
+ /*
1173
+ * LZO helpfully doesn't provide a way to specify the output
1174
+ * buffer size, so we need to allocate for the worst-case
1175
+ * scenario to avoid buffer overruns.
1176
+ *
1177
+ * 4 bytes for the total size
1178
+ * And for each sector:
1179
+ * - 4 bytes for the compressed sector size
1180
+ * - the worst-case output size
1181
+ * - 3 bytes for possible padding
1182
+ */
1183
+
1184
+ sectors = BTRFS_MAX_COMPRESSED / sectorsize ;
1185
+
1186
+ comp_buf_len = LZO_LEN ;
1187
+ comp_buf_len += (LZO_LEN + lzo_max_outlen (sectorsize ) +
1188
+ LZO_LEN - 1 ) * sectors ;
1189
+
1190
+ comp_buf = malloc (comp_buf_len );
1191
+ if (!comp_buf ) {
1192
+ ret = - ENOMEM ;
1193
+ goto end ;
1194
+ }
1195
+
1196
+ ret = lzo_init ();
1197
+ if (ret ) {
1198
+ error ("lzo_init returned %i" , ret );
1199
+ ret = - EINVAL ;
1200
+ goto end ;
1201
+ }
1202
+ #else
1203
+ error ("lzo support not compiled in" );
1204
+ ret = - EINVAL ;
1205
+ goto end ;
1206
+ #endif
1207
+ } else if (g_compression != BTRFS_COMPRESS_NONE ) {
1011
1208
comp_buf = malloc (BTRFS_MAX_COMPRESSED );
1012
1209
if (!comp_buf ) {
1013
1210
ret = - ENOMEM ;
@@ -1020,6 +1217,7 @@ static int add_file_items(struct btrfs_trans_handle *trans,
1020
1217
source .size = st -> st_size ;
1021
1218
source .path_name = path_name ;
1022
1219
source .comp_buf = comp_buf ;
1220
+ source .wrkmem = wrkmem ;
1023
1221
1024
1222
while (file_pos < st -> st_size ) {
1025
1223
ret = add_file_item_extent (trans , root , btrfs_inode , objectid ,
@@ -1031,6 +1229,7 @@ static int add_file_items(struct btrfs_trans_handle *trans,
1031
1229
}
1032
1230
1033
1231
end :
1232
+ free (wrkmem );
1034
1233
free (comp_buf );
1035
1234
free (buf );
1036
1235
close (fd );
@@ -1451,7 +1650,13 @@ int btrfs_mkfs_fill_dir(struct btrfs_trans_handle *trans, const char *source_dir
1451
1650
1452
1651
switch (compression ) {
1453
1652
case BTRFS_COMPRESS_NONE :
1653
+ case BTRFS_COMPRESS_LZO :
1654
+ #if !COMPRESSION_LZO
1655
+ error ("lzo support not compiled in" );
1656
+ return - EINVAL ;
1657
+ #else
1454
1658
break ;
1659
+ #endif
1455
1660
case BTRFS_COMPRESS_ZLIB :
1456
1661
if (compression_level > ZLIB_BTRFS_MAX_LEVEL )
1457
1662
compression_level = ZLIB_BTRFS_MAX_LEVEL ;
0 commit comments