@@ -732,6 +732,9 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
732
732
733
733
if (found_type == BTRFS_FILE_EXTENT_REG ||
734
734
found_type == BTRFS_FILE_EXTENT_PREALLOC ) {
735
+ u64 csum_start ;
736
+ u64 csum_end ;
737
+ LIST_HEAD (ordered_sums );
735
738
u64 offset ;
736
739
unsigned long dest_offset ;
737
740
struct btrfs_key ins ;
@@ -751,6 +754,17 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
751
754
copy_extent_buffer (path -> nodes [0 ], eb , dest_offset ,
752
755
(unsigned long )item , sizeof (* item ));
753
756
757
+ /*
758
+ * We have an explicit hole and NO_HOLES is not enabled. We have
759
+ * added the hole file extent item to the subvolume tree, so we
760
+ * don't have anything else to do other than update the file
761
+ * extent item range and update the inode item.
762
+ */
763
+ if (btrfs_file_extent_disk_bytenr (eb , item ) == 0 ) {
764
+ btrfs_release_path (path );
765
+ goto update_inode ;
766
+ }
767
+
754
768
ins .objectid = btrfs_file_extent_disk_bytenr (eb , item );
755
769
ins .type = BTRFS_EXTENT_ITEM_KEY ;
756
770
ins .offset = btrfs_file_extent_disk_num_bytes (eb , item );
@@ -772,162 +786,139 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
772
786
goto out ;
773
787
}
774
788
775
- if (ins .objectid > 0 ) {
776
- u64 csum_start ;
777
- u64 csum_end ;
778
- LIST_HEAD (ordered_sums );
779
-
780
- /*
781
- * is this extent already allocated in the extent
782
- * allocation tree? If so, just add a reference
783
- */
784
- ret = btrfs_lookup_data_extent (fs_info , ins .objectid ,
785
- ins .offset );
786
- if (ret < 0 ) {
789
+ /*
790
+ * Is this extent already allocated in the extent tree?
791
+ * If so, just add a reference.
792
+ */
793
+ ret = btrfs_lookup_data_extent (fs_info , ins .objectid , ins .offset );
794
+ if (ret < 0 ) {
795
+ btrfs_abort_transaction (trans , ret );
796
+ goto out ;
797
+ } else if (ret == 0 ) {
798
+ struct btrfs_ref ref = {
799
+ .action = BTRFS_ADD_DELAYED_REF ,
800
+ .bytenr = ins .objectid ,
801
+ .num_bytes = ins .offset ,
802
+ .owning_root = btrfs_root_id (root ),
803
+ .ref_root = btrfs_root_id (root ),
804
+ };
805
+
806
+ btrfs_init_data_ref (& ref , key -> objectid , offset , 0 , false);
807
+ ret = btrfs_inc_extent_ref (trans , & ref );
808
+ if (ret ) {
787
809
btrfs_abort_transaction (trans , ret );
788
810
goto out ;
789
- } else if (ret == 0 ) {
790
- struct btrfs_ref ref = {
791
- .action = BTRFS_ADD_DELAYED_REF ,
792
- .bytenr = ins .objectid ,
793
- .num_bytes = ins .offset ,
794
- .owning_root = btrfs_root_id (root ),
795
- .ref_root = btrfs_root_id (root ),
796
- };
797
- btrfs_init_data_ref (& ref , key -> objectid , offset ,
798
- 0 , false);
799
- ret = btrfs_inc_extent_ref (trans , & ref );
800
- if (ret ) {
801
- btrfs_abort_transaction (trans , ret );
802
- goto out ;
803
- }
804
- } else {
805
- /*
806
- * insert the extent pointer in the extent
807
- * allocation tree
808
- */
809
- ret = btrfs_alloc_logged_file_extent (trans ,
810
- btrfs_root_id (root ),
811
- key -> objectid , offset , & ins );
812
- if (ret ) {
813
- btrfs_abort_transaction (trans , ret );
814
- goto out ;
815
- }
816
- }
817
- btrfs_release_path (path );
818
-
819
- if (btrfs_file_extent_compression (eb , item )) {
820
- csum_start = ins .objectid ;
821
- csum_end = csum_start + ins .offset ;
822
- } else {
823
- csum_start = ins .objectid +
824
- btrfs_file_extent_offset (eb , item );
825
- csum_end = csum_start +
826
- btrfs_file_extent_num_bytes (eb , item );
827
811
}
828
-
829
- ret = btrfs_lookup_csums_list ( root -> log_root ,
830
- csum_start , csum_end - 1 ,
831
- & ordered_sums , false );
832
- if (ret < 0 ) {
812
+ } else {
813
+ /* Insert the extent pointer in the extent tree. */
814
+ ret = btrfs_alloc_logged_file_extent ( trans , btrfs_root_id ( root ) ,
815
+ key -> objectid , offset , & ins );
816
+ if (ret ) {
833
817
btrfs_abort_transaction (trans , ret );
834
818
goto out ;
835
819
}
836
- ret = 0 ;
837
- /*
838
- * Now delete all existing cums in the csum root that
839
- * cover our range. We do this because we can have an
840
- * extent that is completely referenced by one file
841
- * extent item and partially referenced by another
842
- * file extent item (like after using the clone or
843
- * extent_same ioctls). In this case if we end up doing
844
- * the replay of the one that partially references the
845
- * extent first, and we do not do the csum deletion
846
- * below, we can get 2 csum items in the csum tree that
847
- * overlap each other. For example, imagine our log has
848
- * the two following file extent items:
849
- *
850
- * key (257 EXTENT_DATA 409600)
851
- * extent data disk byte 12845056 nr 102400
852
- * extent data offset 20480 nr 20480 ram 102400
853
- *
854
- * key (257 EXTENT_DATA 819200)
855
- * extent data disk byte 12845056 nr 102400
856
- * extent data offset 0 nr 102400 ram 102400
857
- *
858
- * Where the second one fully references the 100K extent
859
- * that starts at disk byte 12845056, and the log tree
860
- * has a single csum item that covers the entire range
861
- * of the extent:
862
- *
863
- * key (EXTENT_CSUM EXTENT_CSUM 12845056) itemsize 100
864
- *
865
- * After the first file extent item is replayed, the
866
- * csum tree gets the following csum item:
867
- *
868
- * key (EXTENT_CSUM EXTENT_CSUM 12865536) itemsize 20
869
- *
870
- * Which covers the 20K sub-range starting at offset 20K
871
- * of our extent. Now when we replay the second file
872
- * extent item, if we do not delete existing csum items
873
- * that cover any of its blocks, we end up getting two
874
- * csum items in our csum tree that overlap each other:
875
- *
876
- * key (EXTENT_CSUM EXTENT_CSUM 12845056) itemsize 100
877
- * key (EXTENT_CSUM EXTENT_CSUM 12865536) itemsize 20
878
- *
879
- * Which is a problem, because after this anyone trying
880
- * to lookup up for the checksum of any block of our
881
- * extent starting at an offset of 40K or higher, will
882
- * end up looking at the second csum item only, which
883
- * does not contain the checksum for any block starting
884
- * at offset 40K or higher of our extent.
885
- */
886
- while (!list_empty (& ordered_sums )) {
887
- struct btrfs_ordered_sum * sums ;
888
- struct btrfs_root * csum_root ;
889
-
890
- sums = list_first_entry (& ordered_sums ,
891
- struct btrfs_ordered_sum ,
892
- list );
893
- csum_root = btrfs_csum_root (fs_info ,
894
- sums -> logical );
895
- if (!ret ) {
896
- ret = btrfs_del_csums (trans , csum_root ,
897
- sums -> logical ,
898
- sums -> len );
899
- if (ret )
900
- btrfs_abort_transaction (trans , ret );
901
- }
902
- if (!ret ) {
903
- ret = btrfs_csum_file_blocks (trans ,
904
- csum_root ,
905
- sums );
906
- if (ret )
907
- btrfs_abort_transaction (trans , ret );
908
- }
909
- list_del (& sums -> list );
910
- kfree (sums );
911
- }
912
- if (ret )
913
- goto out ;
820
+ }
821
+
822
+ btrfs_release_path (path );
823
+
824
+ if (btrfs_file_extent_compression (eb , item )) {
825
+ csum_start = ins .objectid ;
826
+ csum_end = csum_start + ins .offset ;
914
827
} else {
915
- btrfs_release_path (path );
828
+ csum_start = ins .objectid + btrfs_file_extent_offset (eb , item );
829
+ csum_end = csum_start + btrfs_file_extent_num_bytes (eb , item );
830
+ }
831
+
832
+ ret = btrfs_lookup_csums_list (root -> log_root , csum_start , csum_end - 1 ,
833
+ & ordered_sums , false);
834
+ if (ret < 0 ) {
835
+ btrfs_abort_transaction (trans , ret );
836
+ goto out ;
916
837
}
838
+ ret = 0 ;
839
+ /*
840
+ * Now delete all existing cums in the csum root that cover our
841
+ * range. We do this because we can have an extent that is
842
+ * completely referenced by one file extent item and partially
843
+ * referenced by another file extent item (like after using the
844
+ * clone or extent_same ioctls). In this case if we end up doing
845
+ * the replay of the one that partially references the extent
846
+ * first, and we do not do the csum deletion below, we can get 2
847
+ * csum items in the csum tree that overlap each other. For
848
+ * example, imagine our log has the two following file extent items:
849
+ *
850
+ * key (257 EXTENT_DATA 409600)
851
+ * extent data disk byte 12845056 nr 102400
852
+ * extent data offset 20480 nr 20480 ram 102400
853
+ *
854
+ * key (257 EXTENT_DATA 819200)
855
+ * extent data disk byte 12845056 nr 102400
856
+ * extent data offset 0 nr 102400 ram 102400
857
+ *
858
+ * Where the second one fully references the 100K extent that
859
+ * starts at disk byte 12845056, and the log tree has a single
860
+ * csum item that covers the entire range of the extent:
861
+ *
862
+ * key (EXTENT_CSUM EXTENT_CSUM 12845056) itemsize 100
863
+ *
864
+ * After the first file extent item is replayed, the csum tree
865
+ * gets the following csum item:
866
+ *
867
+ * key (EXTENT_CSUM EXTENT_CSUM 12865536) itemsize 20
868
+ *
869
+ * Which covers the 20K sub-range starting at offset 20K of our
870
+ * extent. Now when we replay the second file extent item, if we
871
+ * do not delete existing csum items that cover any of its
872
+ * blocks, we end up getting two csum items in our csum tree
873
+ * that overlap each other:
874
+ *
875
+ * key (EXTENT_CSUM EXTENT_CSUM 12845056) itemsize 100
876
+ * key (EXTENT_CSUM EXTENT_CSUM 12865536) itemsize 20
877
+ *
878
+ * Which is a problem, because after this anyone trying to
879
+ * lookup up for the checksum of any block of our extent
880
+ * starting at an offset of 40K or higher, will end up looking
881
+ * at the second csum item only, which does not contain the
882
+ * checksum for any block starting at offset 40K or higher of
883
+ * our extent.
884
+ */
885
+ while (!list_empty (& ordered_sums )) {
886
+ struct btrfs_ordered_sum * sums ;
887
+ struct btrfs_root * csum_root ;
888
+
889
+ sums = list_first_entry (& ordered_sums ,
890
+ struct btrfs_ordered_sum , list );
891
+ csum_root = btrfs_csum_root (fs_info , sums -> logical );
892
+ if (!ret ) {
893
+ ret = btrfs_del_csums (trans , csum_root , sums -> logical ,
894
+ sums -> len );
895
+ if (ret )
896
+ btrfs_abort_transaction (trans , ret );
897
+ }
898
+ if (!ret ) {
899
+ ret = btrfs_csum_file_blocks (trans , csum_root , sums );
900
+ if (ret )
901
+ btrfs_abort_transaction (trans , ret );
902
+ }
903
+ list_del (& sums -> list );
904
+ kfree (sums );
905
+ }
906
+ if (ret )
907
+ goto out ;
917
908
} else if (found_type == BTRFS_FILE_EXTENT_INLINE ) {
918
909
/* inline extents are easy, we just overwrite them */
919
910
ret = overwrite_item (trans , root , path , eb , slot , key );
920
911
if (ret )
921
912
goto out ;
922
913
}
923
914
915
+ update_inode :
924
916
ret = btrfs_inode_set_file_extent_range (inode , start , extent_end - start );
925
917
if (ret ) {
926
918
btrfs_abort_transaction (trans , ret );
927
919
goto out ;
928
920
}
929
921
930
- update_inode :
931
922
btrfs_update_inode_bytes (inode , nbytes , drop_args .bytes_found );
932
923
ret = btrfs_update_inode (trans , inode );
933
924
if (ret )
0 commit comments