@@ -23,20 +23,26 @@ static bool extent_matches_bp(struct bch_fs *c,
23
23
const union bch_extent_entry * entry ;
24
24
struct extent_ptr_decoded p ;
25
25
26
+ rcu_read_lock ();
26
27
bkey_for_each_ptr_decode (k .k , ptrs , p , entry ) {
27
28
struct bpos bucket2 ;
28
29
struct bch_backpointer bp2 ;
29
30
30
31
if (p .ptr .cached )
31
32
continue ;
32
33
33
- struct bch_dev * ca = bch2_dev_bkey_exists (c , p .ptr .dev );
34
+ struct bch_dev * ca = bch2_dev_rcu (c , p .ptr .dev );
35
+ if (!ca )
36
+ continue ;
34
37
35
38
bch2_extent_ptr_to_bp (c , ca , btree_id , level , k , p , entry , & bucket2 , & bp2 );
36
39
if (bpos_eq (bucket , bucket2 ) &&
37
- !memcmp (& bp , & bp2 , sizeof (bp )))
40
+ !memcmp (& bp , & bp2 , sizeof (bp ))) {
41
+ rcu_read_unlock ();
38
42
return true;
43
+ }
39
44
}
45
+ rcu_read_unlock ();
40
46
41
47
return false;
42
48
}
@@ -47,16 +53,21 @@ int bch2_backpointer_invalid(struct bch_fs *c, struct bkey_s_c k,
47
53
{
48
54
struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer (k );
49
55
50
- /* these will be caught by fsck */
51
- if (!bch2_dev_exists (c , bp .k -> p .inode ))
56
+ rcu_read_lock ();
57
+ struct bch_dev * ca = bch2_dev_rcu (c , bp .k -> p .inode );
58
+ if (!ca ) {
59
+ /* these will be caught by fsck */
60
+ rcu_read_unlock ();
52
61
return 0 ;
62
+ }
53
63
54
- struct bch_dev * ca = bch2_dev_bkey_exists (c , bp .k -> p .inode );
55
- struct bpos bucket = bp_pos_to_bucket (c , bp .k -> p );
64
+ struct bpos bucket = bp_pos_to_bucket (ca , bp .k -> p );
65
+ struct bpos bp_pos = bucket_pos_to_bp_noerror (ca , bucket , bp .v -> bucket_offset );
66
+ rcu_read_unlock ();
56
67
int ret = 0 ;
57
68
58
69
bkey_fsck_err_on ((bp .v -> bucket_offset >> MAX_EXTENT_COMPRESS_RATIO_SHIFT ) >= ca -> mi .bucket_size ||
59
- !bpos_eq (bp .k -> p , bucket_pos_to_bp_noerror ( ca , bucket , bp . v -> bucket_offset ) ),
70
+ !bpos_eq (bp .k -> p , bp_pos ),
60
71
c , err ,
61
72
backpointer_bucket_offset_wrong ,
62
73
"backpointer bucket_offset wrong" );
@@ -77,10 +88,16 @@ void bch2_backpointer_to_text(struct printbuf *out, const struct bch_backpointer
77
88
78
89
void bch2_backpointer_k_to_text (struct printbuf * out , struct bch_fs * c , struct bkey_s_c k )
79
90
{
80
- if (bch2_dev_exists (c , k .k -> p .inode )) {
91
+ rcu_read_lock ();
92
+ struct bch_dev * ca = bch2_dev_rcu (c , k .k -> p .inode );
93
+ if (ca ) {
94
+ struct bpos bucket = bp_pos_to_bucket (ca , k .k -> p );
95
+ rcu_read_unlock ();
81
96
prt_str (out , "bucket=" );
82
- bch2_bpos_to_text (out , bp_pos_to_bucket ( c , k . k -> p ) );
97
+ bch2_bpos_to_text (out , bucket );
83
98
prt_str (out , " " );
99
+ } else {
100
+ rcu_read_unlock ();
84
101
}
85
102
86
103
bch2_backpointer_to_text (out , bkey_s_c_to_backpointer (k ).v );
@@ -146,6 +163,7 @@ static noinline int backpointer_mod_err(struct btree_trans *trans,
146
163
}
147
164
148
165
int bch2_bucket_backpointer_mod_nowritebuffer (struct btree_trans * trans ,
166
+ struct bch_dev * ca ,
149
167
struct bpos bucket ,
150
168
struct bch_backpointer bp ,
151
169
struct bkey_s_c orig_k ,
@@ -162,7 +180,7 @@ int bch2_bucket_backpointer_mod_nowritebuffer(struct btree_trans *trans,
162
180
return ret ;
163
181
164
182
bkey_backpointer_init (& bp_k -> k_i );
165
- bp_k -> k .p = bucket_pos_to_bp (trans -> c , bucket , bp .bucket_offset );
183
+ bp_k -> k .p = bucket_pos_to_bp (ca , bucket , bp .bucket_offset );
166
184
bp_k -> v = bp ;
167
185
168
186
if (!insert ) {
@@ -198,13 +216,13 @@ int bch2_bucket_backpointer_mod_nowritebuffer(struct btree_trans *trans,
198
216
* Find the next backpointer >= *bp_offset:
199
217
*/
200
218
int bch2_get_next_backpointer (struct btree_trans * trans ,
219
+ struct bch_dev * ca ,
201
220
struct bpos bucket , int gen ,
202
221
struct bpos * bp_pos ,
203
222
struct bch_backpointer * bp ,
204
223
unsigned iter_flags )
205
224
{
206
- struct bch_fs * c = trans -> c ;
207
- struct bpos bp_end_pos = bucket_pos_to_bp (c , bpos_nosnap_successor (bucket ), 0 );
225
+ struct bpos bp_end_pos = bucket_pos_to_bp (ca , bpos_nosnap_successor (bucket ), 0 );
208
226
struct btree_iter alloc_iter = { NULL }, bp_iter = { NULL };
209
227
struct bkey_s_c k ;
210
228
int ret = 0 ;
@@ -224,7 +242,7 @@ int bch2_get_next_backpointer(struct btree_trans *trans,
224
242
goto done ;
225
243
}
226
244
227
- * bp_pos = bpos_max (* bp_pos , bucket_pos_to_bp (c , bucket , 0 ));
245
+ * bp_pos = bpos_max (* bp_pos , bucket_pos_to_bp (ca , bucket , 0 ));
228
246
229
247
for_each_btree_key_norestart (trans , bp_iter , BTREE_ID_backpointers ,
230
248
* bp_pos , iter_flags , k , ret ) {
@@ -250,7 +268,6 @@ static void backpointer_not_found(struct btree_trans *trans,
250
268
{
251
269
struct bch_fs * c = trans -> c ;
252
270
struct printbuf buf = PRINTBUF ;
253
- struct bpos bucket = bp_pos_to_bucket (c , bp_pos );
254
271
255
272
/*
256
273
* If we're using the btree write buffer, the backpointer we were
@@ -260,6 +277,10 @@ static void backpointer_not_found(struct btree_trans *trans,
260
277
if (likely (!bch2_backpointers_no_use_write_buffer ))
261
278
return ;
262
279
280
+ struct bpos bucket ;
281
+ if (!bp_pos_to_bucket_nodev (c , bp_pos , & bucket ))
282
+ return ;
283
+
263
284
prt_printf (& buf , "backpointer doesn't match %s it points to:\n " ,
264
285
bp .level ? "btree node" : "extent" );
265
286
prt_printf (& buf , "bucket: " );
@@ -289,15 +310,17 @@ struct bkey_s_c bch2_backpointer_get_key(struct btree_trans *trans,
289
310
{
290
311
if (likely (!bp .level )) {
291
312
struct bch_fs * c = trans -> c ;
292
- struct bpos bucket = bp_pos_to_bucket (c , bp_pos );
293
- struct bkey_s_c k ;
313
+
314
+ struct bpos bucket ;
315
+ if (!bp_pos_to_bucket_nodev (c , bp_pos , & bucket ))
316
+ return bkey_s_c_err (- EIO );
294
317
295
318
bch2_trans_node_iter_init (trans , iter ,
296
319
bp .btree_id ,
297
320
bp .pos ,
298
321
0 , 0 ,
299
322
iter_flags );
300
- k = bch2_btree_iter_peek_slot (iter );
323
+ struct bkey_s_c k = bch2_btree_iter_peek_slot (iter );
301
324
if (bkey_err (k )) {
302
325
bch2_trans_iter_exit (trans , iter );
303
326
return k ;
@@ -326,18 +349,20 @@ struct btree *bch2_backpointer_get_node(struct btree_trans *trans,
326
349
struct bch_backpointer bp )
327
350
{
328
351
struct bch_fs * c = trans -> c ;
329
- struct bpos bucket = bp_pos_to_bucket (c , bp_pos );
330
- struct btree * b ;
331
352
332
353
BUG_ON (!bp .level );
333
354
355
+ struct bpos bucket ;
356
+ if (!bp_pos_to_bucket_nodev (c , bp_pos , & bucket ))
357
+ return ERR_PTR (- EIO );
358
+
334
359
bch2_trans_node_iter_init (trans , iter ,
335
360
bp .btree_id ,
336
361
bp .pos ,
337
362
0 ,
338
363
bp .level - 1 ,
339
364
0 );
340
- b = bch2_btree_iter_peek_node (iter );
365
+ struct btree * b = bch2_btree_iter_peek_node (iter );
341
366
if (IS_ERR_OR_NULL (b ))
342
367
goto err ;
343
368
@@ -368,16 +393,16 @@ static int bch2_check_btree_backpointer(struct btree_trans *trans, struct btree_
368
393
struct printbuf buf = PRINTBUF ;
369
394
int ret = 0 ;
370
395
371
- if (fsck_err_on (!bch2_dev_exists (c , k .k -> p .inode ), c ,
372
- backpointer_to_missing_device ,
373
- "backpointer for missing device:\n%s" ,
374
- (bch2_bkey_val_to_text (& buf , c , k ), buf .buf ))) {
375
- ret = bch2_btree_delete_at (trans , bp_iter , 0 );
396
+ struct bpos bucket ;
397
+ if (!bp_pos_to_bucket_nodev_noerror (c , k .k -> p , & bucket )) {
398
+ if (fsck_err (c , backpointer_to_missing_device ,
399
+ "backpointer for missing device:\n%s" ,
400
+ (bch2_bkey_val_to_text (& buf , c , k ), buf .buf )))
401
+ ret = bch2_btree_delete_at (trans , bp_iter , 0 );
376
402
goto out ;
377
403
}
378
404
379
- alloc_k = bch2_bkey_get_iter (trans , & alloc_iter , BTREE_ID_alloc ,
380
- bp_pos_to_bucket (c , k .k -> p ), 0 );
405
+ alloc_k = bch2_bkey_get_iter (trans , & alloc_iter , BTREE_ID_alloc , bucket , 0 );
381
406
ret = bkey_err (alloc_k );
382
407
if (ret )
383
408
goto out ;
@@ -512,25 +537,27 @@ static int check_bp_exists(struct btree_trans *trans,
512
537
struct printbuf buf = PRINTBUF ;
513
538
struct bkey_s_c bp_k ;
514
539
struct bkey_buf tmp ;
515
- int ret ;
540
+ int ret = 0 ;
516
541
517
542
bch2_bkey_buf_init (& tmp );
518
543
519
- if (!bch2_dev_bucket_exists (c , bucket )) {
544
+ struct bch_dev * ca = bch2_dev_bucket_tryget (c , bucket );
545
+ if (!ca ) {
520
546
prt_str (& buf , "extent for nonexistent device:bucket " );
521
547
bch2_bpos_to_text (& buf , bucket );
522
548
prt_str (& buf , "\n " );
523
549
bch2_bkey_val_to_text (& buf , c , orig_k );
524
550
bch_err (c , "%s" , buf .buf );
525
- return - BCH_ERR_fsck_repair_unimplemented ;
551
+ ret = - BCH_ERR_fsck_repair_unimplemented ;
552
+ goto err ;
526
553
}
527
554
528
555
if (bpos_lt (bucket , s -> bucket_start ) ||
529
556
bpos_gt (bucket , s -> bucket_end ))
530
- return 0 ;
557
+ goto out ;
531
558
532
559
bp_k = bch2_bkey_get_iter (trans , & bp_iter , BTREE_ID_backpointers ,
533
- bucket_pos_to_bp (c , bucket , bp .bucket_offset ),
560
+ bucket_pos_to_bp (ca , bucket , bp .bucket_offset ),
534
561
0 );
535
562
ret = bkey_err (bp_k );
536
563
if (ret )
@@ -563,6 +590,7 @@ static int check_bp_exists(struct btree_trans *trans,
563
590
bch2_trans_iter_exit (trans , & other_extent_iter );
564
591
bch2_trans_iter_exit (trans , & bp_iter );
565
592
bch2_bkey_buf_exit (& tmp , c );
593
+ bch2_dev_put (ca );
566
594
printbuf_exit (& buf );
567
595
return ret ;
568
596
check_existing_bp :
@@ -638,13 +666,13 @@ static int check_bp_exists(struct btree_trans *trans,
638
666
639
667
struct bkey_i_backpointer n_bp_k ;
640
668
bkey_backpointer_init (& n_bp_k .k_i );
641
- n_bp_k .k .p = bucket_pos_to_bp (trans -> c , bucket , bp .bucket_offset );
669
+ n_bp_k .k .p = bucket_pos_to_bp (ca , bucket , bp .bucket_offset );
642
670
n_bp_k .v = bp ;
643
671
prt_printf (& buf , "\n want: " );
644
672
bch2_bkey_val_to_text (& buf , c , bkey_i_to_s_c (& n_bp_k .k_i ));
645
673
646
674
if (fsck_err (c , ptr_to_missing_backpointer , "%s" , buf .buf ))
647
- ret = bch2_bucket_backpointer_mod (trans , bucket , bp , orig_k , true);
675
+ ret = bch2_bucket_backpointer_mod (trans , ca , bucket , bp , orig_k , true);
648
676
649
677
goto out ;
650
678
}
@@ -668,8 +696,14 @@ static int check_extent_to_backpointers(struct btree_trans *trans,
668
696
if (p .ptr .cached )
669
697
continue ;
670
698
671
- struct bch_dev * ca = bch2_dev_bkey_exists (c , p .ptr .dev );
672
- bch2_extent_ptr_to_bp (c , ca , btree , level , k , p , entry , & bucket_pos , & bp );
699
+ rcu_read_lock ();
700
+ struct bch_dev * ca = bch2_dev_rcu (c , p .ptr .dev );
701
+ if (ca )
702
+ bch2_extent_ptr_to_bp (c , ca , btree , level , k , p , entry , & bucket_pos , & bp );
703
+ rcu_read_unlock ();
704
+
705
+ if (!ca )
706
+ continue ;
673
707
674
708
ret = check_bp_exists (trans , s , bucket_pos , bp , k );
675
709
if (ret )
0 commit comments