@@ -815,11 +815,136 @@ xfs_refcount_find_right_extents(
815
815
/* Is this extent valid? */
816
816
static inline bool
817
817
xfs_refc_valid (
818
- struct xfs_refcount_irec * rc )
818
+ const struct xfs_refcount_irec * rc )
819
819
{
820
820
return rc -> rc_startblock != NULLAGBLOCK ;
821
821
}
822
822
823
+ static inline xfs_nlink_t
824
+ xfs_refc_merge_refcount (
825
+ const struct xfs_refcount_irec * irec ,
826
+ enum xfs_refc_adjust_op adjust )
827
+ {
828
+ /* Once a record hits MAXREFCOUNT, it is pinned there forever */
829
+ if (irec -> rc_refcount == MAXREFCOUNT )
830
+ return MAXREFCOUNT ;
831
+ return irec -> rc_refcount + adjust ;
832
+ }
833
+
834
+ static inline bool
835
+ xfs_refc_want_merge_center (
836
+ const struct xfs_refcount_irec * left ,
837
+ const struct xfs_refcount_irec * cleft ,
838
+ const struct xfs_refcount_irec * cright ,
839
+ const struct xfs_refcount_irec * right ,
840
+ bool cleft_is_cright ,
841
+ enum xfs_refc_adjust_op adjust ,
842
+ unsigned long long * ulenp )
843
+ {
844
+ unsigned long long ulen = left -> rc_blockcount ;
845
+ xfs_nlink_t new_refcount ;
846
+
847
+ /*
848
+ * To merge with a center record, both shoulder records must be
849
+ * adjacent to the record we want to adjust. This is only true if
850
+ * find_left and find_right made all four records valid.
851
+ */
852
+ if (!xfs_refc_valid (left ) || !xfs_refc_valid (right ) ||
853
+ !xfs_refc_valid (cleft ) || !xfs_refc_valid (cright ))
854
+ return false;
855
+
856
+ /* There must only be one record for the entire range. */
857
+ if (!cleft_is_cright )
858
+ return false;
859
+
860
+ /* The shoulder record refcounts must match the new refcount. */
861
+ new_refcount = xfs_refc_merge_refcount (cleft , adjust );
862
+ if (left -> rc_refcount != new_refcount )
863
+ return false;
864
+ if (right -> rc_refcount != new_refcount )
865
+ return false;
866
+
867
+ /*
868
+ * The new record cannot exceed the max length. ulen is a ULL as the
869
+ * individual record block counts can be up to (u32 - 1) in length
870
+ * hence we need to catch u32 addition overflows here.
871
+ */
872
+ ulen += cleft -> rc_blockcount + right -> rc_blockcount ;
873
+ if (ulen >= MAXREFCEXTLEN )
874
+ return false;
875
+
876
+ * ulenp = ulen ;
877
+ return true;
878
+ }
879
+
880
+ static inline bool
881
+ xfs_refc_want_merge_left (
882
+ const struct xfs_refcount_irec * left ,
883
+ const struct xfs_refcount_irec * cleft ,
884
+ enum xfs_refc_adjust_op adjust )
885
+ {
886
+ unsigned long long ulen = left -> rc_blockcount ;
887
+ xfs_nlink_t new_refcount ;
888
+
889
+ /*
890
+ * For a left merge, the left shoulder record must be adjacent to the
891
+ * start of the range. If this is true, find_left made left and cleft
892
+ * contain valid contents.
893
+ */
894
+ if (!xfs_refc_valid (left ) || !xfs_refc_valid (cleft ))
895
+ return false;
896
+
897
+ /* Left shoulder record refcount must match the new refcount. */
898
+ new_refcount = xfs_refc_merge_refcount (cleft , adjust );
899
+ if (left -> rc_refcount != new_refcount )
900
+ return false;
901
+
902
+ /*
903
+ * The new record cannot exceed the max length. ulen is a ULL as the
904
+ * individual record block counts can be up to (u32 - 1) in length
905
+ * hence we need to catch u32 addition overflows here.
906
+ */
907
+ ulen += cleft -> rc_blockcount ;
908
+ if (ulen >= MAXREFCEXTLEN )
909
+ return false;
910
+
911
+ return true;
912
+ }
913
+
914
+ static inline bool
915
+ xfs_refc_want_merge_right (
916
+ const struct xfs_refcount_irec * cright ,
917
+ const struct xfs_refcount_irec * right ,
918
+ enum xfs_refc_adjust_op adjust )
919
+ {
920
+ unsigned long long ulen = right -> rc_blockcount ;
921
+ xfs_nlink_t new_refcount ;
922
+
923
+ /*
924
+ * For a right merge, the right shoulder record must be adjacent to the
925
+ * end of the range. If this is true, find_right made cright and right
926
+ * contain valid contents.
927
+ */
928
+ if (!xfs_refc_valid (right ) || !xfs_refc_valid (cright ))
929
+ return false;
930
+
931
+ /* Right shoulder record refcount must match the new refcount. */
932
+ new_refcount = xfs_refc_merge_refcount (cright , adjust );
933
+ if (right -> rc_refcount != new_refcount )
934
+ return false;
935
+
936
+ /*
937
+ * The new record cannot exceed the max length. ulen is a ULL as the
938
+ * individual record block counts can be up to (u32 - 1) in length
939
+ * hence we need to catch u32 addition overflows here.
940
+ */
941
+ ulen += cright -> rc_blockcount ;
942
+ if (ulen >= MAXREFCEXTLEN )
943
+ return false;
944
+
945
+ return true;
946
+ }
947
+
823
948
/*
824
949
* Try to merge with any extents on the boundaries of the adjustment range.
825
950
*/
@@ -861,23 +986,15 @@ xfs_refcount_merge_extents(
861
986
(cleft .rc_blockcount == cright .rc_blockcount );
862
987
863
988
/* Try to merge left, cleft, and right. cleft must == cright. */
864
- ulen = (unsigned long long )left .rc_blockcount + cleft .rc_blockcount +
865
- right .rc_blockcount ;
866
- if (xfs_refc_valid (& left ) && xfs_refc_valid (& right ) &&
867
- xfs_refc_valid (& cleft ) && xfs_refc_valid (& cright ) && cequal &&
868
- left .rc_refcount == cleft .rc_refcount + adjust &&
869
- right .rc_refcount == cleft .rc_refcount + adjust &&
870
- ulen < MAXREFCEXTLEN ) {
989
+ if (xfs_refc_want_merge_center (& left , & cleft , & cright , & right , cequal ,
990
+ adjust , & ulen )) {
871
991
* shape_changed = true;
872
992
return xfs_refcount_merge_center_extents (cur , & left , & cleft ,
873
993
& right , ulen , aglen );
874
994
}
875
995
876
996
/* Try to merge left and cleft. */
877
- ulen = (unsigned long long )left .rc_blockcount + cleft .rc_blockcount ;
878
- if (xfs_refc_valid (& left ) && xfs_refc_valid (& cleft ) &&
879
- left .rc_refcount == cleft .rc_refcount + adjust &&
880
- ulen < MAXREFCEXTLEN ) {
997
+ if (xfs_refc_want_merge_left (& left , & cleft , adjust )) {
881
998
* shape_changed = true;
882
999
error = xfs_refcount_merge_left_extent (cur , & left , & cleft ,
883
1000
agbno , aglen );
@@ -893,10 +1010,7 @@ xfs_refcount_merge_extents(
893
1010
}
894
1011
895
1012
/* Try to merge cright and right. */
896
- ulen = (unsigned long long )right .rc_blockcount + cright .rc_blockcount ;
897
- if (xfs_refc_valid (& right ) && xfs_refc_valid (& cright ) &&
898
- right .rc_refcount == cright .rc_refcount + adjust &&
899
- ulen < MAXREFCEXTLEN ) {
1013
+ if (xfs_refc_want_merge_right (& cright , & right , adjust )) {
900
1014
* shape_changed = true;
901
1015
return xfs_refcount_merge_right_extent (cur , & right , & cright ,
902
1016
aglen );
0 commit comments