diff --git a/.bcachefs_revision b/.bcachefs_revision index d9504b5e..10a1ce7d 100644 --- a/.bcachefs_revision +++ b/.bcachefs_revision @@ -1 +1 @@ -ac53c8857f8bb192ed59c0b3fab853760d56918d +ad72553649c848bb907b294429d136f0069282b6 diff --git a/libbcachefs/alloc_background.c b/libbcachefs/alloc_background.c index 03391464..4f208fab 100644 --- a/libbcachefs/alloc_background.c +++ b/libbcachefs/alloc_background.c @@ -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; } diff --git a/libbcachefs/bcachefs_format.h b/libbcachefs/bcachefs_format.h index 498786ec..cc279abf 100644 --- a/libbcachefs/bcachefs_format.h +++ b/libbcachefs/bcachefs_format.h @@ -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 */ diff --git a/libbcachefs/btree_gc.h b/libbcachefs/btree_gc.h index 8de54005..95d803b5 100644 --- a/libbcachefs/btree_gc.h +++ b/libbcachefs/btree_gc.h @@ -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 */ diff --git a/libbcachefs/btree_key_cache.c b/libbcachefs/btree_key_cache.c index f5a942b6..ab394c2d 100644 --- a/libbcachefs/btree_key_cache.c +++ b/libbcachefs/btree_key_cache.c @@ -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) diff --git a/libbcachefs/btree_update.h b/libbcachefs/btree_update.h index ad13b073..a40f3460 100644 --- a/libbcachefs/btree_update.h +++ b/libbcachefs/btree_update.h @@ -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 *); diff --git a/libbcachefs/btree_update_leaf.c b/libbcachefs/btree_update_leaf.c index 4fb07b4c..fccfc0b3 100644 --- a/libbcachefs/btree_update_leaf.c +++ b/libbcachefs/btree_update_leaf.c @@ -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, diff --git a/libbcachefs/dirent.c b/libbcachefs/dirent.c index 28195988..716c8506 100644 --- a/libbcachefs/dirent.c +++ b/libbcachefs/dirent.c @@ -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; } diff --git a/libbcachefs/journal_io.c b/libbcachefs/journal_io.c index f9d13e6a..871477dc 100644 --- a/libbcachefs/journal_io.c +++ b/libbcachefs/journal_io.c @@ -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, diff --git a/libbcachefs/lru.c b/libbcachefs/lru.c index 267f2f8f..ef4b4a9f 100644 --- a/libbcachefs/lru.c +++ b/libbcachefs/lru.c @@ -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) diff --git a/libbcachefs/movinggc.c b/libbcachefs/movinggc.c index 6d0d4049..99980c3d 100644 --- a/libbcachefs/movinggc.c +++ b/libbcachefs/movinggc.c @@ -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), }; diff --git a/libbcachefs/recovery.c b/libbcachefs/recovery.c index 9aa507c1..80befab8 100644 --- a/libbcachefs/recovery.c +++ b/libbcachefs/recovery.c @@ -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, }; diff --git a/libbcachefs/super.c b/libbcachefs/super.c index aba679c6..1401cb57 100644 --- a/libbcachefs/super.c +++ b/libbcachefs/super.c @@ -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;