@@ -51,6 +51,52 @@ xfs_btree_magic(
5151 return magic ;
5252}
5353
54+ static xfs_failaddr_t
55+ xfs_btree_check_lblock_siblings (
56+ struct xfs_mount * mp ,
57+ struct xfs_btree_cur * cur ,
58+ int level ,
59+ xfs_fsblock_t fsb ,
60+ xfs_fsblock_t sibling )
61+ {
62+ if (sibling == NULLFSBLOCK )
63+ return NULL ;
64+ if (sibling == fsb )
65+ return __this_address ;
66+ if (level >= 0 ) {
67+ if (!xfs_btree_check_lptr (cur , sibling , level + 1 ))
68+ return __this_address ;
69+ } else {
70+ if (!xfs_verify_fsbno (mp , sibling ))
71+ return __this_address ;
72+ }
73+
74+ return NULL ;
75+ }
76+
77+ static xfs_failaddr_t
78+ xfs_btree_check_sblock_siblings (
79+ struct xfs_mount * mp ,
80+ struct xfs_btree_cur * cur ,
81+ int level ,
82+ xfs_agnumber_t agno ,
83+ xfs_agblock_t agbno ,
84+ xfs_agblock_t sibling )
85+ {
86+ if (sibling == NULLAGBLOCK )
87+ return NULL ;
88+ if (sibling == agbno )
89+ return __this_address ;
90+ if (level >= 0 ) {
91+ if (!xfs_btree_check_sptr (cur , sibling , level + 1 ))
92+ return __this_address ;
93+ } else {
94+ if (!xfs_verify_agbno (mp , agno , sibling ))
95+ return __this_address ;
96+ }
97+ return NULL ;
98+ }
99+
54100/*
55101 * Check a long btree block header. Return the address of the failing check,
56102 * or NULL if everything is ok.
@@ -65,6 +111,8 @@ __xfs_btree_check_lblock(
65111 struct xfs_mount * mp = cur -> bc_mp ;
66112 xfs_btnum_t btnum = cur -> bc_btnum ;
67113 int crc = xfs_has_crc (mp );
114+ xfs_failaddr_t fa ;
115+ xfs_fsblock_t fsb = NULLFSBLOCK ;
68116
69117 if (crc ) {
70118 if (!uuid_equal (& block -> bb_u .l .bb_uuid , & mp -> m_sb .sb_meta_uuid ))
@@ -83,16 +131,16 @@ __xfs_btree_check_lblock(
83131 if (be16_to_cpu (block -> bb_numrecs ) >
84132 cur -> bc_ops -> get_maxrecs (cur , level ))
85133 return __this_address ;
86- if (block -> bb_u .l .bb_leftsib != cpu_to_be64 (NULLFSBLOCK ) &&
87- !xfs_btree_check_lptr (cur , be64_to_cpu (block -> bb_u .l .bb_leftsib ),
88- level + 1 ))
89- return __this_address ;
90- if (block -> bb_u .l .bb_rightsib != cpu_to_be64 (NULLFSBLOCK ) &&
91- !xfs_btree_check_lptr (cur , be64_to_cpu (block -> bb_u .l .bb_rightsib ),
92- level + 1 ))
93- return __this_address ;
94134
95- return NULL ;
135+ if (bp )
136+ fsb = XFS_DADDR_TO_FSB (mp , xfs_buf_daddr (bp ));
137+
138+ fa = xfs_btree_check_lblock_siblings (mp , cur , level , fsb ,
139+ be64_to_cpu (block -> bb_u .l .bb_leftsib ));
140+ if (!fa )
141+ fa = xfs_btree_check_lblock_siblings (mp , cur , level , fsb ,
142+ be64_to_cpu (block -> bb_u .l .bb_rightsib ));
143+ return fa ;
96144}
97145
98146/* Check a long btree block header. */
@@ -130,6 +178,9 @@ __xfs_btree_check_sblock(
130178 struct xfs_mount * mp = cur -> bc_mp ;
131179 xfs_btnum_t btnum = cur -> bc_btnum ;
132180 int crc = xfs_has_crc (mp );
181+ xfs_failaddr_t fa ;
182+ xfs_agblock_t agbno = NULLAGBLOCK ;
183+ xfs_agnumber_t agno = NULLAGNUMBER ;
133184
134185 if (crc ) {
135186 if (!uuid_equal (& block -> bb_u .s .bb_uuid , & mp -> m_sb .sb_meta_uuid ))
@@ -146,16 +197,18 @@ __xfs_btree_check_sblock(
146197 if (be16_to_cpu (block -> bb_numrecs ) >
147198 cur -> bc_ops -> get_maxrecs (cur , level ))
148199 return __this_address ;
149- if (block -> bb_u .s .bb_leftsib != cpu_to_be32 (NULLAGBLOCK ) &&
150- !xfs_btree_check_sptr (cur , be32_to_cpu (block -> bb_u .s .bb_leftsib ),
151- level + 1 ))
152- return __this_address ;
153- if (block -> bb_u .s .bb_rightsib != cpu_to_be32 (NULLAGBLOCK ) &&
154- !xfs_btree_check_sptr (cur , be32_to_cpu (block -> bb_u .s .bb_rightsib ),
155- level + 1 ))
156- return __this_address ;
157200
158- return NULL ;
201+ if (bp ) {
202+ agbno = xfs_daddr_to_agbno (mp , xfs_buf_daddr (bp ));
203+ agno = xfs_daddr_to_agno (mp , xfs_buf_daddr (bp ));
204+ }
205+
206+ fa = xfs_btree_check_sblock_siblings (mp , cur , level , agno , agbno ,
207+ be32_to_cpu (block -> bb_u .s .bb_leftsib ));
208+ if (!fa )
209+ fa = xfs_btree_check_sblock_siblings (mp , cur , level , agno ,
210+ agbno , be32_to_cpu (block -> bb_u .s .bb_rightsib ));
211+ return fa ;
159212}
160213
161214/* Check a short btree block header. */
@@ -4271,6 +4324,21 @@ xfs_btree_visit_block(
42714324 if (xfs_btree_ptr_is_null (cur , & rptr ))
42724325 return - ENOENT ;
42734326
4327+ /*
4328+ * We only visit blocks once in this walk, so we have to avoid the
4329+ * internal xfs_btree_lookup_get_block() optimisation where it will
4330+ * return the same block without checking if the right sibling points
4331+ * back to us and creates a cyclic reference in the btree.
4332+ */
4333+ if (cur -> bc_flags & XFS_BTREE_LONG_PTRS ) {
4334+ if (be64_to_cpu (rptr .l ) == XFS_DADDR_TO_FSB (cur -> bc_mp ,
4335+ xfs_buf_daddr (bp )))
4336+ return - EFSCORRUPTED ;
4337+ } else {
4338+ if (be32_to_cpu (rptr .s ) == xfs_daddr_to_agbno (cur -> bc_mp ,
4339+ xfs_buf_daddr (bp )))
4340+ return - EFSCORRUPTED ;
4341+ }
42744342 return xfs_btree_lookup_get_block (cur , level , & rptr , & block );
42754343}
42764344
@@ -4445,20 +4513,21 @@ xfs_btree_lblock_verify(
44454513{
44464514 struct xfs_mount * mp = bp -> b_mount ;
44474515 struct xfs_btree_block * block = XFS_BUF_TO_BLOCK (bp );
4516+ xfs_fsblock_t fsb ;
4517+ xfs_failaddr_t fa ;
44484518
44494519 /* numrecs verification */
44504520 if (be16_to_cpu (block -> bb_numrecs ) > max_recs )
44514521 return __this_address ;
44524522
44534523 /* sibling pointer verification */
4454- if (block -> bb_u .l .bb_leftsib != cpu_to_be64 (NULLFSBLOCK ) &&
4455- !xfs_verify_fsbno (mp , be64_to_cpu (block -> bb_u .l .bb_leftsib )))
4456- return __this_address ;
4457- if (block -> bb_u .l .bb_rightsib != cpu_to_be64 (NULLFSBLOCK ) &&
4458- !xfs_verify_fsbno (mp , be64_to_cpu (block -> bb_u .l .bb_rightsib )))
4459- return __this_address ;
4460-
4461- return NULL ;
4524+ fsb = XFS_DADDR_TO_FSB (mp , xfs_buf_daddr (bp ));
4525+ fa = xfs_btree_check_lblock_siblings (mp , NULL , -1 , fsb ,
4526+ be64_to_cpu (block -> bb_u .l .bb_leftsib ));
4527+ if (!fa )
4528+ fa = xfs_btree_check_lblock_siblings (mp , NULL , -1 , fsb ,
4529+ be64_to_cpu (block -> bb_u .l .bb_rightsib ));
4530+ return fa ;
44624531}
44634532
44644533/**
@@ -4499,22 +4568,23 @@ xfs_btree_sblock_verify(
44994568{
45004569 struct xfs_mount * mp = bp -> b_mount ;
45014570 struct xfs_btree_block * block = XFS_BUF_TO_BLOCK (bp );
4502- xfs_agblock_t agno ;
4571+ xfs_agnumber_t agno ;
4572+ xfs_agblock_t agbno ;
4573+ xfs_failaddr_t fa ;
45034574
45044575 /* numrecs verification */
45054576 if (be16_to_cpu (block -> bb_numrecs ) > max_recs )
45064577 return __this_address ;
45074578
45084579 /* sibling pointer verification */
45094580 agno = xfs_daddr_to_agno (mp , xfs_buf_daddr (bp ));
4510- if (block -> bb_u .s .bb_leftsib != cpu_to_be32 (NULLAGBLOCK ) &&
4511- !xfs_verify_agbno (mp , agno , be32_to_cpu (block -> bb_u .s .bb_leftsib )))
4512- return __this_address ;
4513- if (block -> bb_u .s .bb_rightsib != cpu_to_be32 (NULLAGBLOCK ) &&
4514- !xfs_verify_agbno (mp , agno , be32_to_cpu (block -> bb_u .s .bb_rightsib )))
4515- return __this_address ;
4516-
4517- return NULL ;
4581+ agbno = xfs_daddr_to_agbno (mp , xfs_buf_daddr (bp ));
4582+ fa = xfs_btree_check_sblock_siblings (mp , NULL , -1 , agno , agbno ,
4583+ be32_to_cpu (block -> bb_u .s .bb_leftsib ));
4584+ if (!fa )
4585+ fa = xfs_btree_check_sblock_siblings (mp , NULL , -1 , agno , agbno ,
4586+ be32_to_cpu (block -> bb_u .s .bb_rightsib ));
4587+ return fa ;
45184588}
45194589
45204590/*
0 commit comments