if (!b->c.level &&
            node_iter == &iter->l[0].iter &&
-           iter_current_key_modified) {
-               struct bkey_packed *k =
-                       bch2_btree_node_iter_peek_all(node_iter, b);
-
-               if (likely(k)) {
-                       bkey_disassemble(b, k, &iter->k);
-               } else {
-                       /* XXX: for extents, calculate size of hole? */
-                       iter->k.type = KEY_TYPE_deleted;
-               }
-
+           iter_current_key_modified)
                btree_iter_set_dirty(iter, BTREE_ITER_NEED_PEEK);
-       }
 }
 
 void bch2_btree_node_iter_fix(struct btree_iter *iter,
        EBUG_ON(iter->btree_id >= BTREE_ID_NR);
        EBUG_ON(btree_iter_type(iter) != type);
 
+       BUG_ON(type == BTREE_ITER_KEYS &&
+              (bkey_cmp(iter->pos, bkey_start_pos(&iter->k)) < 0 ||
+               bkey_cmp(iter->pos, iter->k.p) > 0));
+
        bch2_btree_iter_verify_locks(iter);
        bch2_btree_iter_verify_level(iter, iter->level);
 }
        EBUG_ON(!btree_node_locked(iter, 0));
        EBUG_ON(bkey_cmp(new_pos, l->b->key.k.p) > 0);
 
-       iter->pos = new_pos;
+       bkey_init(&iter->k);
+       iter->k.p = iter->pos = new_pos;
        btree_iter_set_dirty(iter, BTREE_ITER_NEED_PEEK);
 
        btree_iter_advance_to_pos(iter, l, -1);
                btree_iter_set_dirty(iter, BTREE_ITER_NEED_TRAVERSE);
 }
 
-static unsigned btree_iter_pos_changed(struct btree_iter *iter, int cmp)
+static void btree_iter_pos_changed(struct btree_iter *iter, int cmp)
 {
-       unsigned l = btree_iter_up_until_good_node(iter, cmp);
+       unsigned l = iter->level;
+
+       if (!cmp)
+               goto out;
+
+       l = btree_iter_up_until_good_node(iter, cmp);
 
        if (btree_iter_node(iter, l)) {
                /*
                if (btree_lock_want(iter, l) == BTREE_NODE_UNLOCKED)
                        btree_node_unlock(iter, l);
        }
-
-       return l;
+out:
+       if (l != iter->level)
+               btree_iter_set_dirty(iter, BTREE_ITER_NEED_TRAVERSE);
+       else
+               btree_iter_set_dirty(iter, BTREE_ITER_NEED_PEEK);
 }
 
 void __bch2_btree_iter_set_pos(struct btree_iter *iter, struct bpos new_pos,
                               bool strictly_greater)
 {
        struct bpos old = btree_iter_search_key(iter);
-       unsigned l;
        int cmp;
 
        iter->flags &= ~BTREE_ITER_IS_EXTENTS;
        iter->flags |= strictly_greater ? BTREE_ITER_IS_EXTENTS : 0;
-       iter->pos = new_pos;
 
-       cmp = bkey_cmp(btree_iter_search_key(iter), old);
-       if (!cmp)
-               return;
+       bkey_init(&iter->k);
+       iter->k.p = iter->pos = new_pos;
 
-       l = btree_iter_pos_changed(iter, cmp);
+       cmp = bkey_cmp(btree_iter_search_key(iter), old);
 
-       if (l != iter->level)
-               btree_iter_set_dirty(iter, BTREE_ITER_NEED_TRAVERSE);
-       else
-               btree_iter_set_dirty(iter, BTREE_ITER_NEED_PEEK);
+       btree_iter_pos_changed(iter, cmp);
 }
 
 void bch2_btree_iter_set_pos(struct btree_iter *iter, struct bpos new_pos)
 {
        int cmp = bkey_cmp(new_pos, iter->pos);
-       unsigned l;
-
-       if (!cmp)
-               return;
 
-       iter->pos = new_pos;
-
-       l = btree_iter_pos_changed(iter, cmp);
+       bkey_init(&iter->k);
+       iter->k.p = iter->pos = new_pos;
 
-       if (l != iter->level)
-               btree_iter_set_dirty(iter, BTREE_ITER_NEED_TRAVERSE);
-       else
-               btree_iter_set_dirty(iter, BTREE_ITER_NEED_PEEK);
+       btree_iter_pos_changed(iter, cmp);
 }
 
 static inline bool btree_iter_set_pos_to_next_leaf(struct btree_iter *iter)
 {
        struct btree_iter_level *l = &iter->l[0];
+       bool ret;
 
-       iter->pos       = l->b->key.k.p;
-       iter->uptodate  = BTREE_ITER_NEED_TRAVERSE;
+       bkey_init(&iter->k);
+       iter->k.p = iter->pos = l->b->key.k.p;
 
-       if (!bkey_cmp(iter->pos, POS_MAX)) {
-               bkey_init(&iter->k);
-               iter->k.p       = POS_MAX;
-               return false;
-       }
+       ret = bkey_cmp(iter->pos, POS_MAX) != 0;
+       if (ret)
+               iter->k.p = iter->pos = btree_type_successor(iter->btree_id, iter->pos);
 
-       iter->pos = btree_type_successor(iter->btree_id, iter->pos);
        btree_iter_pos_changed(iter, 1);
-       return true;
+       return ret;
 }
 
 static inline bool btree_iter_set_pos_to_prev_leaf(struct btree_iter *iter)
 {
        struct btree_iter_level *l = &iter->l[0];
+       bool ret;
 
-       iter->pos       = l->b->data->min_key;
+       bkey_init(&iter->k);
+       iter->k.p = iter->pos = l->b->data->min_key;
        iter->uptodate  = BTREE_ITER_NEED_TRAVERSE;
 
-       if (!bkey_cmp(iter->pos, POS_MIN)) {
-               bkey_init(&iter->k);
-               iter->k.p       = POS_MIN;
-               return false;
-       }
+       ret = bkey_cmp(iter->pos, POS_MIN) != 0;
+       if (ret)
+               iter->k.p = iter->pos = btree_type_predecessor(iter->btree_id, iter->pos);
 
-       iter->pos = btree_type_predecessor(iter->btree_id, iter->pos);
        btree_iter_pos_changed(iter, -1);
-       return true;
+       return ret;
 }
 
 /**
  */
 struct bkey_s_c bch2_btree_iter_next(struct btree_iter *iter)
 {
-       struct bpos next = iter->k.p;
-
-       bch2_btree_iter_checks(iter, BTREE_ITER_KEYS);
-
-       if (bkey_cmp(next, POS_MAX))
-               next = btree_type_successor(iter->btree_id, next);
+       if (unlikely(!bkey_cmp(iter->k.p, POS_MAX)))
+               return bkey_s_c_null;
 
-       bch2_btree_iter_set_pos(iter, next);
+       bch2_btree_iter_set_pos(iter,
+               btree_type_successor(iter->btree_id, iter->k.p));
 
        return bch2_btree_iter_peek(iter);
 }
  */
 struct bkey_s_c bch2_btree_iter_peek_prev(struct btree_iter *iter)
 {
+       struct bpos pos = iter->pos;
        struct btree_iter_level *l = &iter->l[0];
        struct bkey_s_c k;
        int ret;
                        return bkey_s_c_err(ret);
 
                k = __btree_iter_peek(iter, l);
-               if (!k.k ||
-                   bkey_cmp(bkey_start_pos(k.k), iter->pos) > 0)
+               if (!k.k || bkey_cmp(bkey_start_pos(k.k), pos) > 0)
                        k = __btree_iter_prev(iter, l);
 
                if (likely(k.k))
                        return bkey_s_c_null;
        }
 
-       EBUG_ON(bkey_cmp(bkey_start_pos(k.k), iter->pos) > 0);
+       EBUG_ON(bkey_cmp(bkey_start_pos(k.k), pos) > 0);
        iter->pos       = bkey_start_pos(k.k);
        iter->uptodate  = BTREE_ITER_UPTODATE;
        return k;
  */
 struct bkey_s_c bch2_btree_iter_prev(struct btree_iter *iter)
 {
-       struct btree_iter_level *l = &iter->l[0];
-       struct bkey_s_c k;
+       struct bpos pos = bkey_start_pos(&iter->k);
 
        bch2_btree_iter_checks(iter, BTREE_ITER_KEYS);
 
-       if (unlikely(iter->uptodate != BTREE_ITER_UPTODATE)) {
-               /*
-                * XXX: when we just need to relock we should be able to avoid
-                * calling traverse, but we need to kill BTREE_ITER_NEED_PEEK
-                * for that to work
-                */
-               iter->pos       = btree_type_predecessor(iter->btree_id,
-                                                        iter->pos);
-               iter->uptodate  = BTREE_ITER_NEED_TRAVERSE;
-
-               return bch2_btree_iter_peek_prev(iter);
-       }
+       if (unlikely(!bkey_cmp(pos, POS_MIN)))
+               return bkey_s_c_null;
 
-       k = __btree_iter_prev(iter, l);
-       if (unlikely(!k.k))
-               return btree_iter_set_pos_to_prev_leaf(iter)
-                       ? bch2_btree_iter_peek(iter)
-                       : bkey_s_c_null;
+       bch2_btree_iter_set_pos(iter, bkey_predecessor(pos));
 
-       EBUG_ON(bkey_cmp(bkey_start_pos(k.k), iter->pos) >= 0);
-       iter->pos       = bkey_start_pos(k.k);
-       return k;
+       return bch2_btree_iter_peek_prev(iter);
 }
 
 static inline struct bkey_s_c
 
 struct bkey_s_c bch2_btree_iter_next_slot(struct btree_iter *iter)
 {
-       bch2_btree_iter_checks(iter, BTREE_ITER_KEYS);
+       if (unlikely(!bkey_cmp(iter->k.p, POS_MAX)))
+               return bkey_s_c_null;
 
        bch2_btree_iter_set_pos(iter,
                btree_type_successor(iter->btree_id, iter->k.p));