]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Update bcachefs sources to ad72553649 bcachefs: Fix a null ptr deref
authorKent Overstreet <kent.overstreet@gmail.com>
Sun, 10 Apr 2022 18:41:57 +0000 (14:41 -0400)
committerKent Overstreet <kent.overstreet@gmail.com>
Sun, 10 Apr 2022 18:41:57 +0000 (14:41 -0400)
13 files changed:
.bcachefs_revision
libbcachefs/alloc_background.c
libbcachefs/bcachefs_format.h
libbcachefs/btree_gc.h
libbcachefs/btree_key_cache.c
libbcachefs/btree_update.h
libbcachefs/btree_update_leaf.c
libbcachefs/dirent.c
libbcachefs/journal_io.c
libbcachefs/lru.c
libbcachefs/movinggc.c
libbcachefs/recovery.c
libbcachefs/super.c

index d9504b5e87237a81d9d5d7006dd6c61e53c0d86d..10a1ce7d38bed63e1a0f9b22f1d5feb1b5343cc3 100644 (file)
@@ -1 +1 @@
-ac53c8857f8bb192ed59c0b3fab853760d56918d
+ad72553649c848bb907b294429d136f0069282b6
index 033914641d66970f051e53b926b77c1c9ab16004..4f208fab799af41a123977a99e26430f0e274742 100644 (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;
 }
 
index 498786ec14b28334165e5271ab76dfcef3258114..cc279abfe0af933767f8598186587bb6018e1423 100644 (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 */
 
index 8de54005e4eaf8f299c5318b8dbd3ef7c6ba0df2..95d803b5743de5bb9e8bc5d58a868e9b795c27cf 100644 (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 */
index f5a942b6bbf727ba2adf1bfe8e90680b5b7fee5b..ab394c2d6ef21317845ad49c1f0c7223d5394f2e 100644 (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)
index ad13b0739a688d4678844e6e276e02098764f173..a40f3460fd625b08e16f0ccf553d1c542d51268b 100644 (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 *);
index 4fb07b4cefc62ce39c07fb0d0bd13a4ec5c8515f..fccfc0b3a8a2b327e966aaa6bae5f08f66d08dc6 100644 (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,
index 281959885bb05e2bb90c05f3457f9effa53d48af..716c85062cea59f3ac85b91512d348ee8f06e0bd 100644 (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;
        }
index f9d13e6abbbda8e4ed67b61392ec0de8c33c0a3d..871477dc8b5cf1d9d97d2362d4219a2e91aaf0da 100644 (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,
index 267f2f8fb13bd1b722c386ae98f63e8ac8a43172..ef4b4a9f0d5fff47a622dc4d98f20039f45a342a 100644 (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)
index 6d0d4049534b56df2515181a6c5f2d7efaa25f61..99980c3d5d557c4147174f38190c536a4365f4e4 100644 (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),
                };
index 9aa507c19198b8a3f21d5ef0297146beacbeb8c7..80befab87f2d8288d3a35fa1d739bc8867f55be4 100644 (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,
                };
 
index aba679c6f30fedb11e28abe3eaf924192cbad8c5..1401cb576fa2fbeb510b85107314491dbee58c5c 100644 (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);
+       ret = bch2_dev_remove_alloc(c, ca);
        if (ret) {
-               bch_err(ca, "Remove failed: error %i flushing journal", ret);
+               bch_err(ca, "Remove failed, error deleting alloc info");
                goto err;
        }
 
-       ret = bch2_dev_remove_alloc(c, ca);
+       ret = bch2_journal_flush_device_pins(&c->journal, ca->dev_idx);
        if (ret) {
-               bch_err(ca, "Remove failed, error deleting alloc info");
+               bch_err(ca, "Remove failed: error %i flushing journal", ret);
                goto err;
        }
 
-       ret = bch2_journal_error(&c->journal);
+       ret = bch2_journal_flush(&c->journal);
        if (ret) {
                bch_err(ca, "Remove failed, journal error");
                goto err;