@@ -192,7 +192,8 @@ static inline int bch2_backpointers_maybe_flush(struct btree_trans *trans,
192192static int backpointer_target_not_found (struct btree_trans * trans ,
193193 struct bkey_s_c_backpointer bp ,
194194 struct bkey_s_c target_k ,
195- struct bkey_buf * last_flushed )
195+ struct bkey_buf * last_flushed ,
196+ bool commit )
196197{
197198 struct bch_fs * c = trans -> c ;
198199 struct printbuf buf = PRINTBUF ;
@@ -228,18 +229,77 @@ static int backpointer_target_not_found(struct btree_trans *trans,
228229 }
229230
230231 if (fsck_err (trans , backpointer_to_missing_ptr ,
231- "%s" , buf .buf ))
232+ "%s" , buf .buf )) {
232233 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 :
233254fsck_err :
234255 printbuf_exit (& buf );
235256 return ret ;
236257}
237258
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 )
243303{
244304 struct bch_fs * c = trans -> c ;
245305
@@ -277,10 +337,10 @@ struct bkey_s_c bch2_backpointer_get_key(struct btree_trans *trans,
277337 bch2_trans_iter_exit (trans , iter );
278338
279339 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 );
281341 return ret ? bkey_s_c_err (ret ) : bkey_s_c_null ;
282342 } 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 );
284344 if (b == ERR_PTR (- BCH_ERR_backpointer_to_overwritten_btree_node ))
285345 return bkey_s_c_null ;
286346 if (IS_ERR_OR_NULL (b ))
@@ -295,35 +355,16 @@ struct btree *bch2_backpointer_get_node(struct btree_trans *trans,
295355 struct btree_iter * iter ,
296356 struct bkey_buf * last_flushed )
297357{
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+ }
317360
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);
327368}
328369
329370static 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,
521562 struct bkey_s_c_backpointer other_bp = bkey_s_c_to_backpointer (bp_k );
522563
523564 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 );
525566 ret = bkey_err (other_extent );
526567 if (ret == - BCH_ERR_backpointer_to_overwritten_btree_node )
527568 ret = 0 ;
0 commit comments