@@ -192,7 +192,8 @@ static inline int bch2_backpointers_maybe_flush(struct btree_trans *trans,
192
192
static int backpointer_target_not_found (struct btree_trans * trans ,
193
193
struct bkey_s_c_backpointer bp ,
194
194
struct bkey_s_c target_k ,
195
- struct bkey_buf * last_flushed )
195
+ struct bkey_buf * last_flushed ,
196
+ bool commit )
196
197
{
197
198
struct bch_fs * c = trans -> c ;
198
199
struct printbuf buf = PRINTBUF ;
@@ -228,18 +229,77 @@ static int backpointer_target_not_found(struct btree_trans *trans,
228
229
}
229
230
230
231
if (fsck_err (trans , backpointer_to_missing_ptr ,
231
- "%s" , buf .buf ))
232
+ "%s" , buf .buf )) {
232
233
ret = bch2_backpointer_del (trans , bp .k -> p );
234
+ if (ret || !commit )
235
+ goto out ;
236
+
237
+ /*
238
+ * Normally, on transaction commit from inside a transaction,
239
+ * we'll return -BCH_ERR_transaction_restart_nested, since a
240
+ * transaction commit invalidates pointers given out by peek().
241
+ *
242
+ * However, since we're updating a write buffer btree, if we
243
+ * return a transaction restart and loop we won't see that the
244
+ * backpointer has been deleted without an additional write
245
+ * buffer flush - and those are expensive.
246
+ *
247
+ * So we're relying on the caller immediately advancing to the
248
+ * next backpointer and starting a new transaction immediately
249
+ * after backpointer_get_key() returns NULL:
250
+ */
251
+ ret = bch2_trans_commit (trans , NULL , NULL , BCH_TRANS_COMMIT_no_enospc );
252
+ }
253
+ out :
233
254
fsck_err :
234
255
printbuf_exit (& buf );
235
256
return ret ;
236
257
}
237
258
238
- struct bkey_s_c bch2_backpointer_get_key (struct btree_trans * trans ,
239
- struct bkey_s_c_backpointer bp ,
240
- struct btree_iter * iter ,
241
- unsigned iter_flags ,
242
- struct bkey_buf * last_flushed )
259
+ static struct btree * __bch2_backpointer_get_node (struct btree_trans * trans ,
260
+ struct bkey_s_c_backpointer bp ,
261
+ struct btree_iter * iter ,
262
+ struct bkey_buf * last_flushed ,
263
+ bool commit )
264
+ {
265
+ struct bch_fs * c = trans -> c ;
266
+
267
+ BUG_ON (!bp .v -> level );
268
+
269
+ bch2_trans_node_iter_init (trans , iter ,
270
+ bp .v -> btree_id ,
271
+ bp .v -> pos ,
272
+ 0 ,
273
+ bp .v -> level - 1 ,
274
+ 0 );
275
+ struct btree * b = bch2_btree_iter_peek_node (trans , iter );
276
+ if (IS_ERR_OR_NULL (b ))
277
+ goto err ;
278
+
279
+ BUG_ON (b -> c .level != bp .v -> level - 1 );
280
+
281
+ if (extent_matches_bp (c , bp .v -> btree_id , bp .v -> level ,
282
+ bkey_i_to_s_c (& b -> key ), bp ))
283
+ return b ;
284
+
285
+ if (btree_node_will_make_reachable (b )) {
286
+ b = ERR_PTR (- BCH_ERR_backpointer_to_overwritten_btree_node );
287
+ } else {
288
+ int ret = backpointer_target_not_found (trans , bp , bkey_i_to_s_c (& b -> key ),
289
+ last_flushed , commit );
290
+ b = ret ? ERR_PTR (ret ) : NULL ;
291
+ }
292
+ err :
293
+ bch2_trans_iter_exit (trans , iter );
294
+ return b ;
295
+ }
296
+
297
+ static struct bkey_s_c __bch2_backpointer_get_key (struct btree_trans * trans ,
298
+ struct bkey_s_c_backpointer bp ,
299
+ struct btree_iter * iter ,
300
+ unsigned iter_flags ,
301
+ struct bkey_buf * last_flushed ,
302
+ bool commit )
243
303
{
244
304
struct bch_fs * c = trans -> c ;
245
305
@@ -277,10 +337,10 @@ struct bkey_s_c bch2_backpointer_get_key(struct btree_trans *trans,
277
337
bch2_trans_iter_exit (trans , iter );
278
338
279
339
if (!bp .v -> level ) {
280
- int ret = backpointer_target_not_found (trans , bp , k , last_flushed );
340
+ int ret = backpointer_target_not_found (trans , bp , k , last_flushed , commit );
281
341
return ret ? bkey_s_c_err (ret ) : bkey_s_c_null ;
282
342
} else {
283
- struct btree * b = bch2_backpointer_get_node (trans , bp , iter , last_flushed );
343
+ struct btree * b = __bch2_backpointer_get_node (trans , bp , iter , last_flushed , commit );
284
344
if (b == ERR_PTR (- BCH_ERR_backpointer_to_overwritten_btree_node ))
285
345
return bkey_s_c_null ;
286
346
if (IS_ERR_OR_NULL (b ))
@@ -295,35 +355,16 @@ struct btree *bch2_backpointer_get_node(struct btree_trans *trans,
295
355
struct btree_iter * iter ,
296
356
struct bkey_buf * last_flushed )
297
357
{
298
- struct bch_fs * c = trans -> c ;
299
-
300
- BUG_ON (!bp .v -> level );
301
-
302
- bch2_trans_node_iter_init (trans , iter ,
303
- bp .v -> btree_id ,
304
- bp .v -> pos ,
305
- 0 ,
306
- bp .v -> level - 1 ,
307
- 0 );
308
- struct btree * b = bch2_btree_iter_peek_node (trans , iter );
309
- if (IS_ERR_OR_NULL (b ))
310
- goto err ;
311
-
312
- BUG_ON (b -> c .level != bp .v -> level - 1 );
313
-
314
- if (extent_matches_bp (c , bp .v -> btree_id , bp .v -> level ,
315
- bkey_i_to_s_c (& b -> key ), bp ))
316
- return b ;
358
+ return __bch2_backpointer_get_node (trans , bp , iter , last_flushed , true);
359
+ }
317
360
318
- if (btree_node_will_make_reachable (b )) {
319
- b = ERR_PTR (- BCH_ERR_backpointer_to_overwritten_btree_node );
320
- } else {
321
- int ret = backpointer_target_not_found (trans , bp , bkey_i_to_s_c (& b -> key ), last_flushed );
322
- b = ret ? ERR_PTR (ret ) : NULL ;
323
- }
324
- err :
325
- bch2_trans_iter_exit (trans , iter );
326
- return b ;
361
+ struct bkey_s_c bch2_backpointer_get_key (struct btree_trans * trans ,
362
+ struct bkey_s_c_backpointer bp ,
363
+ struct btree_iter * iter ,
364
+ unsigned iter_flags ,
365
+ struct bkey_buf * last_flushed )
366
+ {
367
+ return __bch2_backpointer_get_key (trans , bp , iter , iter_flags , last_flushed , true);
327
368
}
328
369
329
370
static int bch2_check_backpointer_has_valid_bucket (struct btree_trans * trans , struct bkey_s_c k ,
@@ -521,7 +562,7 @@ static int check_bp_exists(struct btree_trans *trans,
521
562
struct bkey_s_c_backpointer other_bp = bkey_s_c_to_backpointer (bp_k );
522
563
523
564
struct bkey_s_c other_extent =
524
- bch2_backpointer_get_key (trans , other_bp , & other_extent_iter , 0 , NULL );
565
+ __bch2_backpointer_get_key (trans , other_bp , & other_extent_iter , 0 , NULL , false );
525
566
ret = bkey_err (other_extent );
526
567
if (ret == - BCH_ERR_backpointer_to_overwritten_btree_node )
527
568
ret = 0 ;
0 commit comments