@@ -51,6 +51,52 @@ xfs_btree_magic(
51
51
return magic ;
52
52
}
53
53
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
+
54
100
/*
55
101
* Check a long btree block header. Return the address of the failing check,
56
102
* or NULL if everything is ok.
@@ -65,6 +111,8 @@ __xfs_btree_check_lblock(
65
111
struct xfs_mount * mp = cur -> bc_mp ;
66
112
xfs_btnum_t btnum = cur -> bc_btnum ;
67
113
int crc = xfs_has_crc (mp );
114
+ xfs_failaddr_t fa ;
115
+ xfs_fsblock_t fsb = NULLFSBLOCK ;
68
116
69
117
if (crc ) {
70
118
if (!uuid_equal (& block -> bb_u .l .bb_uuid , & mp -> m_sb .sb_meta_uuid ))
@@ -83,16 +131,16 @@ __xfs_btree_check_lblock(
83
131
if (be16_to_cpu (block -> bb_numrecs ) >
84
132
cur -> bc_ops -> get_maxrecs (cur , level ))
85
133
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 ;
94
134
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 ;
96
144
}
97
145
98
146
/* Check a long btree block header. */
@@ -130,6 +178,9 @@ __xfs_btree_check_sblock(
130
178
struct xfs_mount * mp = cur -> bc_mp ;
131
179
xfs_btnum_t btnum = cur -> bc_btnum ;
132
180
int crc = xfs_has_crc (mp );
181
+ xfs_failaddr_t fa ;
182
+ xfs_agblock_t agbno = NULLAGBLOCK ;
183
+ xfs_agnumber_t agno = NULLAGNUMBER ;
133
184
134
185
if (crc ) {
135
186
if (!uuid_equal (& block -> bb_u .s .bb_uuid , & mp -> m_sb .sb_meta_uuid ))
@@ -146,16 +197,18 @@ __xfs_btree_check_sblock(
146
197
if (be16_to_cpu (block -> bb_numrecs ) >
147
198
cur -> bc_ops -> get_maxrecs (cur , level ))
148
199
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 ;
157
200
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 ;
159
212
}
160
213
161
214
/* Check a short btree block header. */
@@ -4271,6 +4324,21 @@ xfs_btree_visit_block(
4271
4324
if (xfs_btree_ptr_is_null (cur , & rptr ))
4272
4325
return - ENOENT ;
4273
4326
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
+ }
4274
4342
return xfs_btree_lookup_get_block (cur , level , & rptr , & block );
4275
4343
}
4276
4344
@@ -4445,20 +4513,21 @@ xfs_btree_lblock_verify(
4445
4513
{
4446
4514
struct xfs_mount * mp = bp -> b_mount ;
4447
4515
struct xfs_btree_block * block = XFS_BUF_TO_BLOCK (bp );
4516
+ xfs_fsblock_t fsb ;
4517
+ xfs_failaddr_t fa ;
4448
4518
4449
4519
/* numrecs verification */
4450
4520
if (be16_to_cpu (block -> bb_numrecs ) > max_recs )
4451
4521
return __this_address ;
4452
4522
4453
4523
/* 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 ;
4462
4531
}
4463
4532
4464
4533
/**
@@ -4499,22 +4568,23 @@ xfs_btree_sblock_verify(
4499
4568
{
4500
4569
struct xfs_mount * mp = bp -> b_mount ;
4501
4570
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 ;
4503
4574
4504
4575
/* numrecs verification */
4505
4576
if (be16_to_cpu (block -> bb_numrecs ) > max_recs )
4506
4577
return __this_address ;
4507
4578
4508
4579
/* sibling pointer verification */
4509
4580
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 ;
4518
4588
}
4519
4589
4520
4590
/*
0 commit comments