/* STRIPES: */
        GENRADIX(struct stripe) stripes[2];
-       struct mutex            ec_stripe_create_lock;
 
        ec_stripes_heap         ec_stripes_heap;
        spinlock_t              ec_stripes_heap_lock;
 
                                copy_stripe_field(block_sectors[i],
                                                  "block_sectors[%u]", i);
 
-                       if (dst->alive)
+                       if (dst->alive) {
+                               spin_lock(&c->ec_stripes_heap_lock);
                                bch2_stripes_heap_insert(c, dst, dst_iter.pos);
+                               spin_unlock(&c->ec_stripes_heap_lock);
+                       }
 
                        genradix_iter_advance(&dst_iter, &c->stripes[0]);
                        genradix_iter_advance(&src_iter, &c->stripes[1]);
 
 }
 
 static void bucket_set_stripe(struct bch_fs *c,
-                             const struct bch_stripe *v,
+                             const struct bch_extent_ptr *ptr,
                              struct bch_fs_usage *fs_usage,
                              u64 journal_seq,
                              unsigned flags,
                              bool enabled)
 {
        bool gc = flags & BTREE_TRIGGER_GC;
-       unsigned i;
+       struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
+       struct bucket *g = PTR_BUCKET(ca, ptr, gc);
+       struct bucket_mark new, old;
 
-       for (i = 0; i < v->nr_blocks; i++) {
-               const struct bch_extent_ptr *ptr = v->ptrs + i;
-               struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
-               struct bucket *g = PTR_BUCKET(ca, ptr, gc);
-               struct bucket_mark new, old;
-
-               old = bucket_cmpxchg(g, new, ({
-                       new.stripe                      = enabled;
-                       if (journal_seq) {
-                               new.journal_seq_valid   = 1;
-                               new.journal_seq         = journal_seq;
-                       }
-               }));
+       old = bucket_cmpxchg(g, new, ({
+               new.stripe                      = enabled;
+               if (journal_seq) {
+                       new.journal_seq_valid   = 1;
+                       new.journal_seq         = journal_seq;
+               }
+       }));
 
-               bch2_dev_usage_update(c, ca, fs_usage, old, new, gc);
+       bch2_dev_usage_update(c, ca, fs_usage, old, new, gc);
 
-               /*
-                * XXX write repair code for these, flag stripe as possibly bad
-                */
-               if (old.gen != ptr->gen)
-                       bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
-                                     "stripe with stale pointer");
+       /*
+        * XXX write repair code for these, flag stripe as possibly bad
+        */
+       if (old.gen != ptr->gen)
+               bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
+                             "stripe with stale pointer");
 #if 0
-               /*
-                * We'd like to check for these, but these checks don't work
-                * yet:
-                */
-               if (old.stripe && enabled)
-                       bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
-                                     "multiple stripes using same bucket");
-
-               if (!old.stripe && !enabled)
-                       bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
-                                     "deleting stripe but bucket not marked as stripe bucket");
+       /*
+        * We'd like to check for these, but these checks don't work
+        * yet:
+        */
+       if (old.stripe && enabled)
+               bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
+                             "multiple stripes using same bucket");
+
+       if (!old.stripe && !enabled)
+               bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
+                             "deleting stripe but bucket not marked as stripe bucket");
 #endif
-       }
 }
 
 static int __mark_pointer(struct bch_fs *c, struct bkey_s_c k,
 {
        bool gc = flags & BTREE_TRIGGER_GC;
        struct stripe *m;
-       unsigned old, new;
-       int blocks_nonempty_delta;
+       unsigned i, blocks_nonempty = 0;
 
        m = genradix_ptr(&c->stripes[gc], p.idx);
 
        *nr_parity      = m->nr_redundant;
        *r = m->r;
 
-       old = m->block_sectors[p.block];
        m->block_sectors[p.block] += sectors;
-       new = m->block_sectors[p.block];
 
-       blocks_nonempty_delta = (int) !!new - (int) !!old;
-       if (blocks_nonempty_delta) {
-               m->blocks_nonempty += blocks_nonempty_delta;
+       for (i = 0; i < m->nr_blocks; i++)
+               blocks_nonempty += m->block_sectors[i] != 0;
 
+       if (m->blocks_nonempty != blocks_nonempty) {
+               m->blocks_nonempty = blocks_nonempty;
                if (!gc)
                        bch2_stripes_heap_update(c, m, p.idx);
        }
 
-       m->dirty = true;
-
        spin_unlock(&c->ec_stripes_heap_lock);
 
        return 0;
 
        if (!new_s) {
                /* Deleting: */
-               bucket_set_stripe(c, old_s, fs_usage,
-                                 journal_seq, flags, false);
+               for (i = 0; i < old_s->nr_blocks; i++)
+                       bucket_set_stripe(c, old_s->ptrs + i, fs_usage,
+                                         journal_seq, flags, false);
 
-               if (!gc) {
+               if (!gc && m->on_heap) {
                        spin_lock(&c->ec_stripes_heap_lock);
                        bch2_stripes_heap_del(c, m, idx);
                        spin_unlock(&c->ec_stripes_heap_lock);
                BUG_ON(old_s && new_s->nr_blocks != old_s->nr_blocks);
                BUG_ON(old_s && new_s->nr_redundant != old_s->nr_redundant);
 
-               if (!old_s)
-                       bucket_set_stripe(c, new_s, fs_usage,
-                                         journal_seq, flags, true);
+               for (i = 0; i < new_s->nr_blocks; i++) {
+                       if (!old_s ||
+                           memcmp(new_s->ptrs + i,
+                                  old_s->ptrs + i,
+                                  sizeof(struct bch_extent_ptr))) {
+
+                               if (old_s)
+                                       bucket_set_stripe(c, old_s->ptrs + i, fs_usage,
+                                                         journal_seq, flags, false);
+                               bucket_set_stripe(c, new_s->ptrs + i, fs_usage,
+                                                 journal_seq, flags, true);
+                       }
+               }
 
+               m->alive        = true;
                m->sectors      = le16_to_cpu(new_s->sectors);
                m->algorithm    = new_s->algorithm;
                m->nr_blocks    = new_s->nr_blocks;
                        bch2_stripes_heap_update(c, m, idx);
                        spin_unlock(&c->ec_stripes_heap_lock);
                }
-
-               m->alive        = true;
        }
 
        return 0;
 
        BUG_ON(h->data[m->heap_idx].idx != idx);
 }
 
-void bch2_stripes_heap_update(struct bch_fs *c,
-                             struct stripe *m, size_t idx)
-{
-       ec_stripes_heap *h = &c->ec_stripes_heap;
-       size_t i;
-
-       if (m->alive) {
-               heap_verify_backpointer(c, idx);
-
-               h->data[m->heap_idx].blocks_nonempty = m->blocks_nonempty;
-
-               i = m->heap_idx;
-               heap_sift_up(h,   i, ec_stripes_heap_cmp,
-                            ec_stripes_heap_set_backpointer);
-               heap_sift_down(h, i, ec_stripes_heap_cmp,
-                              ec_stripes_heap_set_backpointer);
-
-               heap_verify_backpointer(c, idx);
-       } else {
-               bch2_stripes_heap_insert(c, m, idx);
-       }
-
-       if (stripe_idx_to_delete(c) >= 0 &&
-           !percpu_ref_is_dying(&c->writes))
-               schedule_work(&c->ec_stripe_delete_work);
-}
-
 void bch2_stripes_heap_del(struct bch_fs *c,
                           struct stripe *m, size_t idx)
 {
+       if (!m->on_heap)
+               return;
+
+       m->on_heap = false;
+
        heap_verify_backpointer(c, idx);
 
-       m->alive = false;
        heap_del(&c->ec_stripes_heap, m->heap_idx,
                 ec_stripes_heap_cmp,
                 ec_stripes_heap_set_backpointer);
 void bch2_stripes_heap_insert(struct bch_fs *c,
                              struct stripe *m, size_t idx)
 {
+       if (m->on_heap)
+               return;
+
        BUG_ON(heap_full(&c->ec_stripes_heap));
 
+       m->on_heap = true;
+
        heap_add(&c->ec_stripes_heap, ((struct ec_stripe_heap_entry) {
                        .idx = idx,
                        .blocks_nonempty = m->blocks_nonempty,
                }),
                 ec_stripes_heap_cmp,
                 ec_stripes_heap_set_backpointer);
-       m->alive = true;
 
        heap_verify_backpointer(c, idx);
 }
 
+void bch2_stripes_heap_update(struct bch_fs *c,
+                             struct stripe *m, size_t idx)
+{
+       ec_stripes_heap *h = &c->ec_stripes_heap;
+       size_t i;
+
+       if (!m->on_heap)
+               return;
+
+       heap_verify_backpointer(c, idx);
+
+       h->data[m->heap_idx].blocks_nonempty = m->blocks_nonempty;
+
+       i = m->heap_idx;
+       heap_sift_up(h,   i, ec_stripes_heap_cmp,
+                    ec_stripes_heap_set_backpointer);
+       heap_sift_down(h, i, ec_stripes_heap_cmp,
+                      ec_stripes_heap_set_backpointer);
+
+       heap_verify_backpointer(c, idx);
+
+       if (stripe_idx_to_delete(c) >= 0 &&
+           !percpu_ref_is_dying(&c->writes))
+               schedule_work(&c->ec_stripe_delete_work);
+}
+
 /* stripe deletion */
 
 static int ec_stripe_delete(struct bch_fs *c, size_t idx)
                container_of(work, struct bch_fs, ec_stripe_delete_work);
        ssize_t idx;
 
-       down_read(&c->gc_lock);
-       mutex_lock(&c->ec_stripe_create_lock);
-
        while (1) {
                spin_lock(&c->ec_stripes_heap_lock);
                idx = stripe_idx_to_delete(c);
-               spin_unlock(&c->ec_stripes_heap_lock);
-
-               if (idx < 0)
+               if (idx < 0) {
+                       spin_unlock(&c->ec_stripes_heap_lock);
                        break;
+               }
+
+               bch2_stripes_heap_del(c, genradix_ptr(&c->stripes[0], idx), idx);
+               spin_unlock(&c->ec_stripes_heap_lock);
 
                if (ec_stripe_delete(c, idx))
                        break;
        }
-
-       mutex_unlock(&c->ec_stripe_create_lock);
-       up_read(&c->gc_lock);
 }
 
 /* stripe creation: */
        struct bch_fs *c = s->c;
        struct open_bucket *ob;
        struct bkey_i *k;
+       struct stripe *m;
        struct bch_stripe *v = &s->stripe.key.v;
        unsigned i, nr_data = v->nr_blocks - v->nr_redundant;
        struct closure cl;
                        goto err_put_writes;
                }
 
-       mutex_lock(&c->ec_stripe_create_lock);
-
        ret = ec_stripe_bkey_insert(c, &s->stripe.key);
        if (ret) {
                bch_err(c, "error creating stripe: error creating stripe key");
-               goto err_unlock;
+               goto err_put_writes;
        }
 
        for_each_keylist_key(&s->keys, k) {
                        break;
        }
 
-err_unlock:
-       mutex_unlock(&c->ec_stripe_create_lock);
+       spin_lock(&c->ec_stripes_heap_lock);
+       m = genradix_ptr(&c->stripes[0], s->stripe.key.k.p.offset);
+       BUG_ON(m->on_heap);
+       bch2_stripes_heap_insert(c, m, s->stripe.key.k.p.offset);
+       spin_unlock(&c->ec_stripes_heap_lock);
 err_put_writes:
        percpu_ref_put(&c->writes);
 err:
 {
        int ret = 0;
 
-       if (k.k->type == KEY_TYPE_stripe)
+       if (k.k->type == KEY_TYPE_stripe) {
+               struct stripe *m;
+
                ret = __ec_stripe_mem_alloc(c, k.k->p.offset, GFP_KERNEL) ?:
                        bch2_mark_key(c, k, 0, 0, NULL, 0,
                                      BTREE_TRIGGER_ALLOC_READ|
                                      BTREE_TRIGGER_NOATOMIC);
+               if (ret)
+                       return ret;
+
+               spin_lock(&c->ec_stripes_heap_lock);
+               m = genradix_ptr(&c->stripes[0], k.k->p.offset);
+               bch2_stripes_heap_insert(c, m, k.k->p.offset);
+               spin_unlock(&c->ec_stripes_heap_lock);
+       }
 
        return ret;
 }
        return 0;
 }
 
+void bch2_stripes_heap_to_text(struct printbuf *out, struct bch_fs *c)
+{
+       ec_stripes_heap *h = &c->ec_stripes_heap;
+       struct stripe *m;
+       size_t i;
+
+       spin_lock(&c->ec_stripes_heap_lock);
+       for (i = 0; i < min(h->used, 20UL); i++) {
+               m = genradix_ptr(&c->stripes[0], h->data[i].idx);
+
+               pr_buf(out, "%zu %u/%u+%u\n", h->data[i].idx,
+                      h->data[i].blocks_nonempty,
+                      m->nr_blocks - m->nr_redundant,
+                      m->nr_redundant);
+       }
+       spin_unlock(&c->ec_stripes_heap_lock);
+}
+
 void bch2_fs_ec_exit(struct bch_fs *c)
 {
        struct ec_stripe_head *h;
 
 
 int bch2_ec_mem_alloc(struct bch_fs *, bool);
 
+void bch2_stripes_heap_to_text(struct printbuf *, struct bch_fs *);
+
 void bch2_fs_ec_exit(struct bch_fs *);
 int bch2_fs_ec_init(struct bch_fs *);
 
 
 
        unsigned                alive:1;
        unsigned                dirty:1;
+       unsigned                on_heap:1;
        u8                      blocks_nonempty;
        u16                     block_sectors[EC_STRIPE_MAX];
 
 
 
        INIT_LIST_HEAD(&c->ec_new_stripe_list);
        mutex_init(&c->ec_new_stripe_lock);
-       mutex_init(&c->ec_stripe_create_lock);
        spin_lock_init(&c->ec_stripes_heap_lock);
 
        seqcount_init(&c->gc_pos_lock);
 
 read_attribute(dirty_btree_nodes);
 read_attribute(btree_key_cache);
 read_attribute(btree_transactions);
+read_attribute(stripes_heap);
 
 read_attribute(internal_uuid);
 
                return out.pos - buf;
        }
 
+       if (attr == &sysfs_stripes_heap) {
+               struct printbuf out = _PBUF(buf, PAGE_SIZE);
+
+               bch2_stripes_heap_to_text(&out, c);
+               return out.pos - buf;
+       }
+
        if (attr == &sysfs_compression_stats)
                return bch2_compression_stats(c, buf);
 
        &sysfs_dirty_btree_nodes,
        &sysfs_btree_key_cache,
        &sysfs_btree_transactions,
+       &sysfs_stripes_heap,
 
        &sysfs_read_realloc_races,
        &sysfs_extent_migrate_done,