Commit f9035b0c authored by Kent Overstreet's avatar Kent Overstreet

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
...@@ -465,21 +465,16 @@ int bch2_update_cached_sectors_list(struct btree_trans *trans, unsigned dev, s64 ...@@ -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); return bch2_update_replicas_list(trans, &r.e, sectors);
} }
int bch2_check_fix_ptrs(struct btree_trans *trans, static int bch2_check_fix_ptr(struct btree_trans *trans,
enum btree_id btree, unsigned level, struct bkey_s_c k, struct bkey_s_c k,
enum btree_iter_update_trigger_flags flags) struct extent_ptr_decoded p,
const union bch_extent_entry *entry,
bool *do_update)
{ {
struct bch_fs *c = trans->c; 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; struct printbuf buf = PRINTBUF;
int ret = 0; 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); struct bch_dev *ca = bch2_dev_tryget(c, p.ptr.dev);
if (!ca) { if (!ca) {
if (fsck_err(c, ptr_to_invalid_device, if (fsck_err(c, ptr_to_invalid_device,
...@@ -488,12 +483,12 @@ int bch2_check_fix_ptrs(struct btree_trans *trans, ...@@ -488,12 +483,12 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
p.ptr.dev, p.ptr.dev,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
do_update = true; *do_update = true;
continue; return 0;
} }
struct bucket *g = PTR_GC_BUCKET(ca, &p.ptr); 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, if (fsck_err_on(!g->gen_valid,
c, ptr_to_missing_alloc_key, c, ptr_to_missing_alloc_key,
...@@ -508,7 +503,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans, ...@@ -508,7 +503,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
g->gen_valid = true; g->gen_valid = true;
g->gen = p.ptr.gen; g->gen = p.ptr.gen;
} else { } else {
do_update = true; *do_update = true;
} }
} }
...@@ -530,7 +525,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans, ...@@ -530,7 +525,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
g->dirty_sectors = 0; g->dirty_sectors = 0;
g->cached_sectors = 0; g->cached_sectors = 0;
} else { } else {
do_update = true; *do_update = true;
} }
} }
...@@ -543,7 +538,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans, ...@@ -543,7 +538,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
p.ptr.gen, p.ptr.gen,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.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, if (fsck_err_on(!p.ptr.cached && gen_cmp(p.ptr.gen, g->gen) < 0,
c, stale_dirty_ptr, c, stale_dirty_ptr,
...@@ -554,10 +549,10 @@ int bch2_check_fix_ptrs(struct btree_trans *trans, ...@@ -554,10 +549,10 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
p.ptr.gen, g->gen, p.ptr.gen, g->gen,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.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) 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), if (fsck_err_on(bucket_data_type_mismatch(g->data_type, data_type),
c, ptr_bucket_data_type_mismatch, c, ptr_bucket_data_type_mismatch,
...@@ -575,7 +570,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans, ...@@ -575,7 +570,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
g->dirty_sectors = 0; g->dirty_sectors = 0;
g->cached_sectors = 0; g->cached_sectors = 0;
} else { } else {
do_update = true; *do_update = true;
} }
} }
...@@ -589,7 +584,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans, ...@@ -589,7 +584,7 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
(u64) p.ec.idx, (u64) p.ec.idx,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.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, if (fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p), c,
ptr_to_incorrect_stripe, ptr_to_incorrect_stripe,
...@@ -598,10 +593,33 @@ int bch2_check_fix_ptrs(struct btree_trans *trans, ...@@ -598,10 +593,33 @@ int bch2_check_fix_ptrs(struct btree_trans *trans,
(u64) p.ec.idx, (u64) p.ec.idx,
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.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); 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) { if (do_update) {
...@@ -716,7 +734,6 @@ int bch2_check_fix_ptrs(struct btree_trans *trans, ...@@ -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); bch2_btree_node_update_key_early(trans, btree, level - 1, k, new);
} }
err: err:
fsck_err:
percpu_up_read(&c->mark_lock); percpu_up_read(&c->mark_lock);
printbuf_exit(&buf); printbuf_exit(&buf);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment