Commit f9035b0c authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: Fix refcount leak in check_fix_ptrs()



fsck_err() does a goto fsck_err on error; factor out check_fix_ptr() so
that our error label can drop our device ref.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent bf2b356a
Loading
Loading
Loading
Loading
+133 −116
Original line number Diff line number Diff line
@@ -465,21 +465,16 @@ int bch2_update_cached_sectors_list(struct btree_trans *trans, unsigned dev, s64
	return bch2_update_replicas_list(trans, &r.e, sectors);
}

int bch2_check_fix_ptrs(struct btree_trans *trans,
			enum btree_id btree, unsigned level, struct bkey_s_c k,
			enum btree_iter_update_trigger_flags flags)
static int bch2_check_fix_ptr(struct btree_trans *trans,
			      struct bkey_s_c k,
			      struct extent_ptr_decoded p,
			      const union bch_extent_entry *entry,
			      bool *do_update)
{
	struct bch_fs *c = trans->c;
	struct bkey_ptrs_c ptrs_c = bch2_bkey_ptrs_c(k);
	const union bch_extent_entry *entry_c;
	struct extent_ptr_decoded p = { 0 };
	bool do_update = false;
	struct printbuf buf = PRINTBUF;
	int ret = 0;

	percpu_down_read(&c->mark_lock);

	bkey_for_each_ptr_decode(k.k, ptrs_c, p, entry_c) {
	struct bch_dev *ca = bch2_dev_tryget(c, p.ptr.dev);
	if (!ca) {
		if (fsck_err(c, ptr_to_invalid_device,
@@ -488,12 +483,12 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
			     p.ptr.dev,
			     (printbuf_reset(&buf),
			      bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
				do_update = true;
			continue;
			*do_update = true;
		return 0;
	}

	struct bucket *g = PTR_GC_BUCKET(ca, &p.ptr);
		enum bch_data_type data_type = bch2_bkey_ptr_data_type(k, p, entry_c);
	enum bch_data_type data_type = bch2_bkey_ptr_data_type(k, p, entry);

	if (fsck_err_on(!g->gen_valid,
			c, ptr_to_missing_alloc_key,
@@ -508,7 +503,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
			g->gen_valid		= true;
			g->gen			= p.ptr.gen;
		} else {
				do_update = true;
			*do_update = true;
		}
	}

@@ -530,7 +525,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
			g->dirty_sectors	= 0;
			g->cached_sectors	= 0;
		} else {
				do_update = true;
			*do_update = true;
		}
	}

@@ -543,7 +538,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
			p.ptr.gen,
			(printbuf_reset(&buf),
			 bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
			do_update = true;
		*do_update = true;

	if (fsck_err_on(!p.ptr.cached && gen_cmp(p.ptr.gen, g->gen) < 0,
			c, stale_dirty_ptr,
@@ -554,10 +549,10 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
			p.ptr.gen, g->gen,
			(printbuf_reset(&buf),
			 bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
			do_update = true;
		*do_update = true;

	if (data_type != BCH_DATA_btree && p.ptr.gen != g->gen)
			goto next;
		goto out;

	if (fsck_err_on(bucket_data_type_mismatch(g->data_type, data_type),
			c, ptr_bucket_data_type_mismatch,
@@ -575,7 +570,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
			g->dirty_sectors	= 0;
			g->cached_sectors	= 0;
		} else {
				do_update = true;
			*do_update = true;
		}
	}

@@ -589,7 +584,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
				(u64) p.ec.idx,
				(printbuf_reset(&buf),
				 bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
				do_update = true;
			*do_update = true;

		if (fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p), c,
				ptr_to_incorrect_stripe,
@@ -598,10 +593,33 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
				(u64) p.ec.idx,
				(printbuf_reset(&buf),
				 bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
				do_update = true;
			*do_update = true;
	}
next:
out:
fsck_err:
	bch2_dev_put(ca);
	printbuf_exit(&buf);
	return ret;
}

int bch2_check_fix_ptrs(struct btree_trans *trans,
			enum btree_id btree, unsigned level, struct bkey_s_c k,
			enum btree_iter_update_trigger_flags flags)
{
	struct bch_fs *c = trans->c;
	struct bkey_ptrs_c ptrs_c = bch2_bkey_ptrs_c(k);
	const union bch_extent_entry *entry_c;
	struct extent_ptr_decoded p = { 0 };
	bool do_update = false;
	struct printbuf buf = PRINTBUF;
	int ret = 0;

	percpu_down_read(&c->mark_lock);

	bkey_for_each_ptr_decode(k.k, ptrs_c, p, entry_c) {
		ret = bch2_check_fix_ptr(trans, k, p, entry_c, &do_update);
		if (ret)
			goto err;
	}

	if (do_update) {
@@ -716,7 +734,6 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
			bch2_btree_node_update_key_early(trans, btree, level - 1, k, new);
	}
err:
fsck_err:
	percpu_up_read(&c->mark_lock);
	printbuf_exit(&buf);
	return ret;