struct bkey_s_c k;
        bool invalidating_cached_data;
        size_t b;
-       int ret;
+       int ret = 0;
 
        BUG_ON(!ca->alloc_heap.used ||
               !ca->alloc_heap.data[0].nr);
 
        BUG_ON(!fifo_push(&ca->free_inc, b));
 
+       g = bucket(ca, b);
+       m = READ_ONCE(g->mark);
+
        bch2_mark_alloc_bucket(c, ca, b, true, gc_pos_alloc(c, NULL), 0);
 
        spin_unlock(&c->freelist_lock);
        percpu_up_read(&c->mark_lock);
 
+       invalidating_cached_data = m.cached_sectors != 0;
+       if (!invalidating_cached_data)
+               goto out;
+
        BUG_ON(BKEY_ALLOC_VAL_U64s_MAX > 8);
 
        bch2_btree_iter_set_pos(iter, POS(ca->dev_idx, b));
                                flags);
        if (ret == -EINTR)
                goto retry;
-
+out:
        if (!ret) {
                /* remove from alloc_heap: */
                struct alloc_heap_entry e, *top = ca->alloc_heap.data;
 
        if (ret < 0)
                return ret;
 
-       if (!ret && unlikely(!test_bit(BCH_FS_ALLOC_WRITTEN, &c->flags))) {
+       if (k.k->type != KEY_TYPE_alloc ||
+           (!ret && unlikely(!test_bit(BCH_FS_ALLOC_WRITTEN, &c->flags)))) {
                /*
                 * During journal replay, and if gc repairs alloc info at
                 * runtime, the alloc info in the btree might not be up to date
-                * yet - so, trust the in memory mark:
+                * yet - so, trust the in memory mark - unless we're already
+                * updating that key:
                 */
                struct bucket *g;
                struct bucket_mark m;
                u       = alloc_mem_to_key(g, m);
                percpu_up_read(&c->mark_lock);
        } else {
-               /*
-                * Unless we're already updating that key:
-                */
-               if (k.k->type != KEY_TYPE_alloc) {
-                       bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
-                                     "pointer to nonexistent bucket %llu:%llu",
-                                     iter->pos.inode, iter->pos.offset);
-                       ret = -1;
-                       goto out;
-               }
-
                u = bch2_alloc_unpack(k);
        }
 
-       if (gen_after(u.gen, p.ptr.gen)) {
+       if (u.gen != p.ptr.gen) {
                ret = 1;
+
+               if (gen_after(p.ptr.gen, u.gen)) {
+                       bch2_fs_inconsistent(c,
+                                     "bucket %llu:%llu gen %u data type %s: ptr gen %u newer than bucket gen",
+                                     iter->pos.inode, iter->pos.offset, u.gen,
+                                     bch2_data_types[u.data_type ?: data_type],
+                                     p.ptr.gen);
+                       ret = -EIO;
+               }
+
+               if (gen_cmp(u.gen, p.ptr.gen) >= 96U) {
+                       bch2_fs_inconsistent(c,
+                                     "bucket %llu:%llu gen %u data type %s: ptr gen %u too stale",
+                                     iter->pos.inode, iter->pos.offset, u.gen,
+                                     bch2_data_types[u.data_type ?: data_type],
+                                     p.ptr.gen);
+                       ret = -EIO;
+               }
+
+               if (!p.ptr.cached) {
+                       bch2_fs_inconsistent(c,
+                                     "bucket %llu:%llu gen %u data type %s: stale dirty ptr (gen %u)",
+                                     iter->pos.inode, iter->pos.offset, u.gen,
+                                     bch2_data_types[u.data_type ?: data_type],
+                                     p.ptr.gen);
+                       ret = -EIO;
+               }
+
                goto out;
        }