mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-23 00:00:02 +03:00
Update bcachefs sources to 7bfc741f64 bcachefs: Fix a null ptr deref during journal replay
This commit is contained in:
parent
c452666fb3
commit
a62d8713f8
@ -1 +1 @@
|
||||
a897b0f199b2fb888f5885f115306759199094dd
|
||||
7bfc741f64204731ceeabf3061c0470613c67e86
|
||||
|
@ -1912,13 +1912,14 @@ static struct btree_iter *btree_trans_iter_alloc(struct btree_trans *trans)
|
||||
struct btree_iter *iter;
|
||||
|
||||
trans_for_each_iter(trans, iter) {
|
||||
pr_err("iter: btree %s pos %llu:%llu%s%s%s",
|
||||
pr_err("iter: btree %s pos %llu:%llu%s%s%s %pf",
|
||||
bch2_btree_ids[iter->btree_id],
|
||||
iter->pos.inode,
|
||||
iter->pos.offset,
|
||||
(trans->iters_live & (1ULL << iter->idx)) ? " live" : "",
|
||||
(trans->iters_touched & (1ULL << iter->idx)) ? " touched" : "",
|
||||
iter->flags & BTREE_ITER_KEEP_UNTIL_COMMIT ? " keep" : "");
|
||||
iter->flags & BTREE_ITER_KEEP_UNTIL_COMMIT ? " keep" : "",
|
||||
(void *) iter->ip_allocated);
|
||||
}
|
||||
|
||||
panic("trans iter oveflow\n");
|
||||
@ -2025,9 +2026,9 @@ static struct btree_iter *__btree_trans_get_iter(struct btree_trans *trans,
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct btree_iter *bch2_trans_get_iter(struct btree_trans *trans,
|
||||
enum btree_id btree_id,
|
||||
struct bpos pos, unsigned flags)
|
||||
struct btree_iter *__bch2_trans_get_iter(struct btree_trans *trans,
|
||||
enum btree_id btree_id,
|
||||
struct bpos pos, unsigned flags)
|
||||
{
|
||||
struct btree_iter *iter =
|
||||
__btree_trans_get_iter(trans, btree_id, pos, flags);
|
||||
@ -2064,7 +2065,7 @@ struct btree_iter *bch2_trans_get_node_iter(struct btree_trans *trans,
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct btree_iter *bch2_trans_copy_iter(struct btree_trans *trans,
|
||||
struct btree_iter *__bch2_trans_copy_iter(struct btree_trans *trans,
|
||||
struct btree_iter *src)
|
||||
{
|
||||
struct btree_iter *iter;
|
||||
|
@ -257,10 +257,35 @@ int bch2_trans_iter_free(struct btree_trans *, struct btree_iter *);
|
||||
|
||||
void bch2_trans_unlink_iters(struct btree_trans *);
|
||||
|
||||
struct btree_iter *bch2_trans_get_iter(struct btree_trans *, enum btree_id,
|
||||
struct bpos, unsigned);
|
||||
struct btree_iter *bch2_trans_copy_iter(struct btree_trans *,
|
||||
struct btree_iter *__bch2_trans_get_iter(struct btree_trans *, enum btree_id,
|
||||
struct bpos, unsigned);
|
||||
|
||||
static inline struct btree_iter *
|
||||
bch2_trans_get_iter(struct btree_trans *trans, enum btree_id btree_id,
|
||||
struct bpos pos, unsigned flags)
|
||||
{
|
||||
struct btree_iter *iter =
|
||||
__bch2_trans_get_iter(trans, btree_id, pos, flags);
|
||||
|
||||
if (!IS_ERR(iter))
|
||||
iter->ip_allocated = _THIS_IP_;
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct btree_iter *__bch2_trans_copy_iter(struct btree_trans *,
|
||||
struct btree_iter *);
|
||||
static inline struct btree_iter *
|
||||
bch2_trans_copy_iter(struct btree_trans *trans, struct btree_iter *src)
|
||||
{
|
||||
struct btree_iter *iter =
|
||||
__bch2_trans_copy_iter(trans, src);
|
||||
|
||||
if (!IS_ERR(iter))
|
||||
iter->ip_allocated = _THIS_IP_;
|
||||
return iter;
|
||||
|
||||
}
|
||||
|
||||
struct btree_iter *bch2_trans_get_node_iter(struct btree_trans *,
|
||||
enum btree_id, struct bpos,
|
||||
unsigned, unsigned, unsigned);
|
||||
|
@ -253,6 +253,7 @@ struct btree_iter {
|
||||
* bch2_btree_iter_next_slot() can correctly advance pos.
|
||||
*/
|
||||
struct bkey k;
|
||||
unsigned long ip_allocated;
|
||||
};
|
||||
|
||||
static inline enum btree_iter_type btree_iter_type(struct btree_iter *iter)
|
||||
|
@ -27,43 +27,37 @@ static void btree_update_drop_new_node(struct bch_fs *, struct btree *);
|
||||
|
||||
/* Debug code: */
|
||||
|
||||
/*
|
||||
* Verify that child nodes correctly span parent node's range:
|
||||
*/
|
||||
static void btree_node_interior_verify(struct btree *b)
|
||||
{
|
||||
#ifdef CONFIG_BCACHEFS_DEBUG
|
||||
struct bpos next_node = b->data->min_key;
|
||||
struct btree_node_iter iter;
|
||||
struct bkey_packed *k;
|
||||
struct bkey_s_c k;
|
||||
struct bkey_s_c_btree_ptr_v2 bp;
|
||||
struct bkey unpacked;
|
||||
|
||||
BUG_ON(!b->level);
|
||||
|
||||
bch2_btree_node_iter_init(&iter, b, &b->key.k.p);
|
||||
#if 1
|
||||
BUG_ON(!(k = bch2_btree_node_iter_peek(&iter, b)) ||
|
||||
bkey_cmp_left_packed(b, k, &b->key.k.p));
|
||||
bch2_btree_node_iter_init_from_start(&iter, b);
|
||||
|
||||
BUG_ON((bch2_btree_node_iter_advance(&iter, b),
|
||||
!bch2_btree_node_iter_end(&iter)));
|
||||
#else
|
||||
const char *msg;
|
||||
while (1) {
|
||||
k = bch2_btree_node_iter_peek_unpack(&iter, b, &unpacked);
|
||||
bp = bkey_s_c_to_btree_ptr_v2(k);
|
||||
|
||||
msg = "not found";
|
||||
k = bch2_btree_node_iter_peek(&iter, b);
|
||||
if (!k)
|
||||
goto err;
|
||||
BUG_ON(bkey_cmp(next_node, bp.v->min_key));
|
||||
|
||||
msg = "isn't what it should be";
|
||||
if (bkey_cmp_left_packed(b, k, &b->key.k.p))
|
||||
goto err;
|
||||
bch2_btree_node_iter_advance(&iter, b);
|
||||
|
||||
bch2_btree_node_iter_advance(&iter, b);
|
||||
if (bch2_btree_node_iter_end(&iter)) {
|
||||
BUG_ON(bkey_cmp(k.k->p, b->key.k.p));
|
||||
break;
|
||||
}
|
||||
|
||||
msg = "isn't last key";
|
||||
if (!bch2_btree_node_iter_end(&iter))
|
||||
goto err;
|
||||
return;
|
||||
err:
|
||||
bch2_dump_btree_node(b);
|
||||
printk(KERN_ERR "last key %llu:%llu %s\n", b->key.k.p.inode,
|
||||
b->key.k.p.offset, msg);
|
||||
BUG();
|
||||
next_node = bkey_successor(k.k->p);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -644,8 +638,6 @@ static void btree_update_nodes_written(struct closure *cl)
|
||||
struct bch_fs *c = as->c;
|
||||
struct btree *b;
|
||||
struct bset *i;
|
||||
struct bkey_i *k;
|
||||
unsigned journal_u64s = 0;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
@ -674,13 +666,7 @@ again:
|
||||
|
||||
list_del(&as->unwritten_list);
|
||||
|
||||
journal_u64s = 0;
|
||||
|
||||
if (as->mode != BTREE_INTERIOR_UPDATING_ROOT)
|
||||
for_each_keylist_key(&as->parent_keys, k)
|
||||
journal_u64s += jset_u64s(k->k.u64s);
|
||||
|
||||
ret = bch2_journal_res_get(&c->journal, &res, journal_u64s,
|
||||
ret = bch2_journal_res_get(&c->journal, &res, as->journal_u64s,
|
||||
JOURNAL_RES_GET_RESERVED);
|
||||
if (ret) {
|
||||
BUG_ON(!bch2_journal_error(&c->journal));
|
||||
@ -688,13 +674,14 @@ again:
|
||||
goto free_update;
|
||||
}
|
||||
|
||||
if (as->mode != BTREE_INTERIOR_UPDATING_ROOT)
|
||||
for_each_keylist_key(&as->parent_keys, k)
|
||||
bch2_journal_add_entry(&c->journal, &res,
|
||||
BCH_JSET_ENTRY_btree_keys,
|
||||
as->btree_id,
|
||||
as->level,
|
||||
k, k->k.u64s);
|
||||
{
|
||||
struct journal_buf *buf = &c->journal.buf[res.idx];
|
||||
struct jset_entry *entry = vstruct_idx(buf->data, res.offset);
|
||||
|
||||
res.offset += as->journal_u64s;
|
||||
res.u64s -= as->journal_u64s;
|
||||
memcpy_u64s(entry, as->journal_entries, as->journal_u64s);
|
||||
}
|
||||
|
||||
switch (as->mode) {
|
||||
case BTREE_INTERIOR_NO_UPDATE:
|
||||
@ -983,7 +970,7 @@ bch2_btree_update_start(struct bch_fs *c, enum btree_id id,
|
||||
bch2_keylist_init(&as->parent_keys, as->inline_keys);
|
||||
|
||||
ret = bch2_journal_preres_get(&c->journal, &as->journal_preres,
|
||||
jset_u64s(BKEY_BTREE_PTR_U64s_MAX) * 3, 0);
|
||||
ARRAY_SIZE(as->journal_entries), 0);
|
||||
if (ret) {
|
||||
bch2_btree_reserve_put(c, reserve);
|
||||
closure_debug_destroy(&as->cl);
|
||||
@ -1103,10 +1090,21 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as, struct btree *b
|
||||
{
|
||||
struct bch_fs *c = as->c;
|
||||
struct bch_fs_usage *fs_usage;
|
||||
struct jset_entry *entry;
|
||||
struct bkey_packed *k;
|
||||
struct bkey tmp;
|
||||
|
||||
BUG_ON(insert->k.u64s > bch_btree_keys_u64s_remaining(c, b));
|
||||
BUG_ON(as->journal_u64s + jset_u64s(insert->k.u64s) >
|
||||
ARRAY_SIZE(as->journal_entries));
|
||||
|
||||
entry = (void *) &as->journal_entries[as->journal_u64s];
|
||||
memset(entry, 0, sizeof(*entry));
|
||||
entry->u64s = cpu_to_le16(insert->k.u64s);
|
||||
entry->type = BCH_JSET_ENTRY_btree_keys;
|
||||
entry->btree_id = b->btree_id;
|
||||
entry->level = b->level;
|
||||
memcpy_u64s_small(entry->_data, insert, insert->k.u64s);
|
||||
as->journal_u64s += jset_u64s(insert->k.u64s);
|
||||
|
||||
mutex_lock(&c->btree_interior_update_lock);
|
||||
percpu_down_read(&c->mark_lock);
|
||||
@ -1255,6 +1253,14 @@ static void btree_split_insert_keys(struct btree_update *as, struct btree *b,
|
||||
struct bkey_packed *src, *dst, *n;
|
||||
struct bset *i;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
*
|
||||
* these updates must be journalled
|
||||
*
|
||||
* oops
|
||||
*/
|
||||
|
||||
BUG_ON(btree_node_type(b) != BKEY_TYPE_BTREE);
|
||||
|
||||
bch2_btree_node_iter_init(&node_iter, b, &k->k.p);
|
||||
@ -1262,11 +1268,6 @@ static void btree_split_insert_keys(struct btree_update *as, struct btree *b,
|
||||
while (!bch2_keylist_empty(keys)) {
|
||||
k = bch2_keylist_front(keys);
|
||||
|
||||
BUG_ON(bch_keylist_u64s(keys) >
|
||||
bch_btree_keys_u64s_remaining(as->c, b));
|
||||
BUG_ON(bkey_cmp(k->k.p, b->data->min_key) < 0);
|
||||
BUG_ON(bkey_cmp(k->k.p, b->data->max_key) > 0);
|
||||
|
||||
bch2_insert_fixup_btree_ptr(as, b, iter, k, &node_iter);
|
||||
bch2_keylist_pop_front(keys);
|
||||
}
|
||||
|
@ -104,6 +104,10 @@ struct btree_update {
|
||||
struct btree *new_nodes[BTREE_MAX_DEPTH * 2 + GC_MERGE_NODES];
|
||||
unsigned nr_new_nodes;
|
||||
|
||||
unsigned journal_u64s;
|
||||
u64 journal_entries[
|
||||
(BKEY_BTREE_PTR_U64s_MAX + 1) * (BTREE_MAX_DEPTH - 1) * 2];
|
||||
|
||||
/* Only here to reduce stack usage on recursive splits: */
|
||||
struct keylist parent_keys;
|
||||
/*
|
||||
|
@ -309,7 +309,7 @@ btree_key_can_insert(struct btree_trans *trans,
|
||||
if (unlikely(btree_node_old_extent_overwrite(b)))
|
||||
return BTREE_INSERT_BTREE_NODE_FULL;
|
||||
|
||||
ret = !btree_node_is_extents(b)
|
||||
ret = !(iter->flags & BTREE_ITER_IS_EXTENTS)
|
||||
? BTREE_INSERT_OK
|
||||
: bch2_extent_can_insert(trans, iter, insert);
|
||||
if (ret)
|
||||
|
@ -215,6 +215,21 @@ void bch2_btree_ptr_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
bch2_bkey_ptrs_to_text(out, c, k);
|
||||
}
|
||||
|
||||
void bch2_btree_ptr_v2_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
struct bkey_s_c k)
|
||||
{
|
||||
struct bkey_s_c_btree_ptr_v2 bp = bkey_s_c_to_btree_ptr_v2(k);
|
||||
|
||||
pr_buf(out, "seq %llu sectors %u written %u min_key ",
|
||||
le64_to_cpu(bp.v->seq),
|
||||
le16_to_cpu(bp.v->sectors),
|
||||
le16_to_cpu(bp.v->sectors_written));
|
||||
|
||||
bch2_bpos_to_text(out, bp.v->min_key);
|
||||
pr_buf(out, " ");
|
||||
bch2_bkey_ptrs_to_text(out, c, k);
|
||||
}
|
||||
|
||||
void bch2_btree_ptr_v2_compat(enum btree_id btree_id, unsigned version,
|
||||
unsigned big_endian, int write,
|
||||
struct bkey_s k)
|
||||
|
@ -371,6 +371,9 @@ const char *bch2_btree_ptr_invalid(const struct bch_fs *, struct bkey_s_c);
|
||||
void bch2_btree_ptr_debugcheck(struct bch_fs *, struct bkey_s_c);
|
||||
void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
|
||||
void bch2_btree_ptr_v2_to_text(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
void bch2_btree_ptr_v2_compat(enum btree_id, unsigned, unsigned,
|
||||
int, struct bkey_s);
|
||||
|
||||
@ -384,7 +387,7 @@ void bch2_btree_ptr_v2_compat(enum btree_id, unsigned, unsigned,
|
||||
#define bch2_bkey_ops_btree_ptr_v2 (struct bkey_ops) { \
|
||||
.key_invalid = bch2_btree_ptr_invalid, \
|
||||
.key_debugcheck = bch2_btree_ptr_debugcheck, \
|
||||
.val_to_text = bch2_btree_ptr_to_text, \
|
||||
.val_to_text = bch2_btree_ptr_v2_to_text, \
|
||||
.swab = bch2_ptr_swab, \
|
||||
.compat = bch2_btree_ptr_v2_compat, \
|
||||
}
|
||||
|
@ -2512,10 +2512,8 @@ reassemble:
|
||||
bkey_on_stack_reassemble(©, c, k);
|
||||
|
||||
if (insert &&
|
||||
bkey_cmp(bkey_start_pos(k.k), move_pos) < 0) {
|
||||
bkey_cmp(bkey_start_pos(k.k), move_pos) < 0)
|
||||
bch2_cut_front(move_pos, copy.k);
|
||||
bch2_btree_iter_set_pos(src, bkey_start_pos(©.k->k));
|
||||
}
|
||||
|
||||
copy.k->k.p.offset += shift >> 9;
|
||||
bch2_btree_iter_set_pos(dst, bkey_start_pos(©.k->k));
|
||||
@ -2535,8 +2533,9 @@ reassemble:
|
||||
}
|
||||
|
||||
bkey_init(&delete.k);
|
||||
delete.k.p = src->pos;
|
||||
bch2_key_resize(&delete.k, copy.k->k.size);
|
||||
delete.k.p = copy.k->k.p;
|
||||
delete.k.size = copy.k->k.size;
|
||||
delete.k.p.offset -= shift >> 9;
|
||||
|
||||
next_pos = insert ? bkey_start_pos(&delete.k) : delete.k.p;
|
||||
|
||||
@ -2557,6 +2556,8 @@ reassemble:
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
bch2_btree_iter_set_pos(src, bkey_start_pos(&delete.k));
|
||||
|
||||
ret = bch2_trans_update(&trans, src, &delete, trigger_flags) ?:
|
||||
bch2_trans_update(&trans, dst, copy.k, trigger_flags) ?:
|
||||
bch2_trans_commit(&trans, &disk_res,
|
||||
|
@ -142,8 +142,6 @@ retry:
|
||||
&inode->ei_journal_seq,
|
||||
BTREE_INSERT_NOUNLOCK|
|
||||
BTREE_INSERT_NOFAIL);
|
||||
if (ret == -EINTR)
|
||||
goto retry;
|
||||
|
||||
/*
|
||||
* the btree node lock protects inode->ei_inode, not ei_update_lock;
|
||||
@ -152,6 +150,11 @@ retry:
|
||||
if (!ret)
|
||||
bch2_inode_update_after_write(c, inode, &inode_u, fields);
|
||||
|
||||
bch2_trans_iter_put(&trans, iter);
|
||||
|
||||
if (ret == -EINTR)
|
||||
goto retry;
|
||||
|
||||
bch2_trans_exit(&trans);
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
@ -183,17 +183,12 @@ void bch2_btree_and_journal_iter_init_node_iter(struct btree_and_journal_iter *i
|
||||
struct journal_keys *journal_keys,
|
||||
struct btree *b)
|
||||
{
|
||||
struct bpos start = b->data->min_key;
|
||||
|
||||
if (btree_node_type_is_extents(b->btree_id))
|
||||
start = bkey_successor(start);
|
||||
|
||||
memset(iter, 0, sizeof(*iter));
|
||||
|
||||
iter->b = b;
|
||||
bch2_btree_node_iter_init_from_start(&iter->node_iter, iter->b);
|
||||
bch2_journal_iter_init(&iter->journal, journal_keys,
|
||||
b->btree_id, b->level, start);
|
||||
b->btree_id, b->level, b->data->min_key);
|
||||
}
|
||||
|
||||
/* sort and dedup all keys in the journal: */
|
||||
|
Loading…
Reference in New Issue
Block a user