Update bcachefs sources to ad72553649 bcachefs: Fix a null ptr deref

This commit is contained in:
Kent Overstreet 2022-04-10 14:41:57 -04:00
parent 8b23ea867a
commit 5ee3f4d7b2
13 changed files with 63 additions and 49 deletions

View File

@ -1 +1 @@
ac53c8857f8bb192ed59c0b3fab853760d56918d
ad72553649c848bb907b294429d136f0069282b6

View File

@ -446,6 +446,13 @@ int bch2_alloc_read(struct bch_fs *c)
for_each_btree_key(&trans, iter, BTREE_ID_alloc, POS_MIN,
BTREE_ITER_PREFETCH, k, ret) {
/*
* Not a fsck error because this is checked/repaired by
* bch2_check_alloc_key() which runs later:
*/
if (!bch2_dev_bucket_exists(c, k.k->p))
continue;
ca = bch_dev_bkey_exists(c, k.k->p.inode);
bch2_alloc_to_v4(k, &a);
@ -614,7 +621,8 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
return ret;
if (fsck_err_on(!bch2_dev_bucket_exists(c, alloc_k.k->p), c,
"alloc key for invalid device or bucket"))
"alloc key for invalid device:bucket %llu:%llu",
alloc_k.k->p.inode, alloc_k.k->p.offset))
return bch2_btree_delete_at(trans, alloc_iter, 0);
ca = bch_dev_bkey_exists(c, alloc_k.k->p.inode);
@ -706,7 +714,6 @@ static int bch2_check_discard_freespace_key(struct btree_trans *trans,
struct bch_alloc_v4 a;
u64 genbits;
struct bpos pos;
struct bkey_i *update;
enum bch_data_type state = iter->btree_id == BTREE_ID_need_discard
? BCH_DATA_need_discard
: BCH_DATA_free;
@ -728,9 +735,8 @@ static int bch2_check_discard_freespace_key(struct btree_trans *trans,
bch2_trans_iter_init(trans, &alloc_iter, BTREE_ID_alloc, pos, 0);
if (fsck_err_on(!bch2_dev_bucket_exists(c, pos), c,
"%llu:%llu set in %s btree but device or bucket does not exist",
pos.inode, pos.offset,
bch2_btree_ids[iter->btree_id]))
"entry in %s btree for nonexistant dev:bucket %llu:%llu",
bch2_btree_ids[iter->btree_id], pos.inode, pos.offset))
goto delete;
k = bch2_btree_iter_peek_slot(&alloc_iter);
@ -756,21 +762,8 @@ fsck_err:
printbuf_exit(&buf);
return ret;
delete:
if (iter->btree_id == BTREE_ID_freespace) {
/* should probably add a helper for deleting extents */
update = bch2_trans_kmalloc(trans, sizeof(*update));
ret = PTR_ERR_OR_ZERO(update);
if (ret)
goto err;
bkey_init(&update->k);
update->k.p = iter->pos;
bch2_key_resize(&update->k, 1);
ret = bch2_trans_update(trans, iter, update, 0);
} else {
ret = bch2_btree_delete_at(trans, iter, 0);
}
ret = bch2_btree_delete_extent_at(trans, iter,
iter->btree_id == BTREE_ID_freespace ? 1 : 0, 0);
goto out;
}

View File

@ -847,10 +847,9 @@ struct bch_dirent {
#define DT_SUBVOL 16
#define BCH_DT_MAX 17
#define BCH_NAME_MAX (U8_MAX * sizeof(u64) - \
#define BCH_NAME_MAX ((unsigned) (U8_MAX * sizeof(u64) - \
sizeof(struct bkey) - \
offsetof(struct bch_dirent, d_name))
offsetof(struct bch_dirent, d_name)))
/* Xattrs */

View File

@ -105,7 +105,8 @@ static inline bool gc_visited(struct bch_fs *c, struct gc_pos pos)
static inline void bch2_do_gc_gens(struct bch_fs *c)
{
atomic_inc(&c->kick_gc);
wake_up_process(c->gc_thread);
if (c->gc_thread)
wake_up_process(c->gc_thread);
}
#endif /* _BCACHEFS_BTREE_GC_H */

View File

@ -723,8 +723,8 @@ int bch2_fs_btree_key_cache_init(struct btree_key_cache *c)
void bch2_btree_key_cache_to_text(struct printbuf *out, struct btree_key_cache *c)
{
pr_buf(out, "nr_freed:\t%zu\n", c->nr_freed);
pr_buf(out, "nr_keys:\t%zu\n", atomic_long_read(&c->nr_keys));
pr_buf(out, "nr_dirty:\t%zu\n", atomic_long_read(&c->nr_dirty));
pr_buf(out, "nr_keys:\t%lu\n", atomic_long_read(&c->nr_keys));
pr_buf(out, "nr_dirty:\t%lu\n", atomic_long_read(&c->nr_dirty));
}
void bch2_btree_key_cache_exit(void)

View File

@ -51,6 +51,8 @@ enum btree_insert_flags {
#define BCH_HASH_SET_MUST_CREATE (1 << __BCH_HASH_SET_MUST_CREATE)
#define BCH_HASH_SET_MUST_REPLACE (1 << __BCH_HASH_SET_MUST_REPLACE)
int bch2_btree_delete_extent_at(struct btree_trans *, struct btree_iter *,
unsigned, unsigned);
int bch2_btree_delete_at(struct btree_trans *, struct btree_iter *, unsigned);
int __bch2_btree_insert(struct btree_trans *, enum btree_id, struct bkey_i *);

View File

@ -858,10 +858,11 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans,
struct btree_insert_entry *i;
struct printbuf buf = PRINTBUF;
int ret, u64s_delta = 0;
int rw = (trans->flags & BTREE_INSERT_JOURNAL_REPLAY) ? READ : WRITE;
trans_for_each_update(trans, i) {
if (bch2_bkey_invalid(c, bkey_i_to_s_c(i->k),
i->bkey_type, WRITE, &buf)) {
i->bkey_type, rw, &buf)) {
printbuf_reset(&buf);
pr_buf(&buf, "invalid bkey on insert from %s -> %ps",
trans->fn, (void *) i->ip_allocated);
@ -872,7 +873,7 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans,
pr_newline(&buf);
bch2_bkey_invalid(c, bkey_i_to_s_c(i->k),
i->bkey_type, WRITE, &buf);
i->bkey_type, rw, &buf);
bch2_trans_inconsistent(trans, "%s", buf.buf);
printbuf_exit(&buf);
@ -1641,8 +1642,8 @@ int bch2_btree_insert(struct bch_fs *c, enum btree_id id,
__bch2_btree_insert(&trans, id, k));
}
int bch2_btree_delete_at(struct btree_trans *trans,
struct btree_iter *iter, unsigned update_flags)
int bch2_btree_delete_extent_at(struct btree_trans *trans, struct btree_iter *iter,
unsigned len, unsigned update_flags)
{
struct bkey_i *k;
@ -1652,9 +1653,16 @@ int bch2_btree_delete_at(struct btree_trans *trans,
bkey_init(&k->k);
k->k.p = iter->pos;
bch2_key_resize(&k->k, len);
return bch2_trans_update(trans, iter, k, update_flags);
}
int bch2_btree_delete_at(struct btree_trans *trans,
struct btree_iter *iter, unsigned update_flags)
{
return bch2_btree_delete_extent_at(trans, iter, 0, update_flags);
}
int bch2_btree_delete_range_trans(struct btree_trans *trans, enum btree_id id,
struct bpos start, struct bpos end,
unsigned update_flags,

View File

@ -108,7 +108,7 @@ int bch2_dirent_invalid(const struct bch_fs *c, struct bkey_s_c k,
}
if (len > BCH_NAME_MAX) {
pr_buf(err, "dirent name too big (%u > %lu)",
pr_buf(err, "dirent name too big (%u > %u)",
len, BCH_NAME_MAX);
return -EINVAL;
}

View File

@ -988,7 +988,7 @@ static void bch2_journal_read_device(struct closure *cl)
for (i = 0; i < r->nr_ptrs; i++) {
if (r->ptrs[i].dev == ca->dev_idx &&
sector_to_bucket(ca, r->ptrs[i].sector) == ja->buckets[ja->cur_idx]) {
unsigned wrote = (r->ptrs[i].sector % ca->mi.bucket_size) +
unsigned wrote = bucket_remainder(ca, r->ptrs[i].sector) +
vstruct_sectors(&r->j, c->block_bits);
ja->sectors_free = min(ja->sectors_free,

View File

@ -133,7 +133,7 @@ static int bch2_check_lru_key(struct btree_trans *trans,
struct bch_alloc_v4 a;
struct printbuf buf1 = PRINTBUF;
struct printbuf buf2 = PRINTBUF;
u64 idx;
struct bpos alloc_pos;
int ret;
lru_k = bch2_btree_iter_peek(lru_iter);
@ -144,10 +144,15 @@ static int bch2_check_lru_key(struct btree_trans *trans,
if (ret)
return ret;
idx = le64_to_cpu(bkey_s_c_to_lru(lru_k).v->idx);
alloc_pos = POS(lru_k.k->p.inode,
le64_to_cpu(bkey_s_c_to_lru(lru_k).v->idx));
bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc,
POS(lru_k.k->p.inode, idx), 0);
if (fsck_err_on(!bch2_dev_bucket_exists(c, alloc_pos), c,
"lru key points to nonexistent device:bucket %llu:%llu",
alloc_pos.inode, alloc_pos.offset))
return bch2_btree_delete_at(trans, lru_iter, 0);
bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc, alloc_pos, 0);
k = bch2_btree_iter_peek_slot(&iter);
ret = bkey_err(k);
if (ret)

View File

@ -138,8 +138,8 @@ static int walk_buckets_to_copygc(struct bch_fs *c)
.dev = iter.pos.inode,
.gen = a.gen,
.replicas = 1 + a.stripe_redundancy,
.fragmentation = (u64) a.dirty_sectors * (1ULL << 31)
/ ca->mi.bucket_size,
.fragmentation = div_u64((u64) a.dirty_sectors * (1ULL << 31),
ca->mi.bucket_size),
.sectors = a.dirty_sectors,
.offset = bucket_to_sector(ca, iter.pos.offset),
};

View File

@ -198,7 +198,7 @@ int bch2_journal_key_insert_take(struct bch_fs *c, enum btree_id id,
if (keys->nr == keys->size) {
struct journal_keys new_keys = {
.nr = keys->nr,
.size = max(keys->size, 8UL) * 2,
.size = max_t(size_t, keys->size, 8) * 2,
.journal_seq_base = keys->journal_seq_base,
};

View File

@ -1420,11 +1420,17 @@ static int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca)
struct bpos end = POS(ca->dev_idx, U64_MAX);
int ret;
ret = bch2_btree_delete_range(c, BTREE_ID_alloc, start, end,
/*
* We clear the LRU and need_discard btrees first so that we don't race
* with bch2_do_invalidates() and bch2_do_discards()
*/
ret = bch2_btree_delete_range(c, BTREE_ID_lru, start, end,
BTREE_TRIGGER_NORUN, NULL) ?:
bch2_btree_delete_range(c, BTREE_ID_need_discard, start, end,
BTREE_TRIGGER_NORUN, NULL) ?:
bch2_btree_delete_range(c, BTREE_ID_freespace, start, end,
BTREE_TRIGGER_NORUN, NULL) ?:
bch2_btree_delete_range(c, BTREE_ID_need_discard, start, end,
bch2_btree_delete_range(c, BTREE_ID_alloc, start, end,
BTREE_TRIGGER_NORUN, NULL);
if (ret)
bch_err(c, "error %i removing dev alloc info", ret);
@ -1459,19 +1465,19 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
goto err;
}
ret = bch2_journal_flush_device_pins(&c->journal, ca->dev_idx);
if (ret) {
bch_err(ca, "Remove failed: error %i flushing journal", ret);
goto err;
}
ret = bch2_dev_remove_alloc(c, ca);
if (ret) {
bch_err(ca, "Remove failed, error deleting alloc info");
goto err;
}
ret = bch2_journal_error(&c->journal);
ret = bch2_journal_flush_device_pins(&c->journal, ca->dev_idx);
if (ret) {
bch_err(ca, "Remove failed: error %i flushing journal", ret);
goto err;
}
ret = bch2_journal_flush(&c->journal);
if (ret) {
bch_err(ca, "Remove failed, journal error");
goto err;