return NULL;
 }
 
-void bch2_alloc_to_text(struct bch_fs *c, char *buf,
-                       size_t size, struct bkey_s_c k)
+int bch2_alloc_to_text(struct bch_fs *c, char *buf,
+                      size_t size, struct bkey_s_c k)
 {
        buf[0] = '\0';
 
        case BCH_ALLOC:
                break;
        }
+
+       return 0;
 }
 
 static inline unsigned get_alloc_field(const u8 **p, unsigned bytes)
         * invalidated on disk:
         */
        if (invalidating_data) {
+               BUG();
+               pr_info("holding writes");
                pr_debug("invalidating existing data");
                set_bit(BCH_FS_HOLD_BTREE_WRITES, &c->flags);
        } else {
 
 #define ALLOC_SCAN_BATCH(ca)           ((ca)->mi.nbuckets >> 9)
 
 const char *bch2_alloc_invalid(const struct bch_fs *, struct bkey_s_c);
-void bch2_alloc_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
+int bch2_alloc_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
 
 #define bch2_bkey_alloc_ops (struct bkey_ops) {                \
        .key_invalid    = bch2_alloc_invalid,           \
 
 
 #define p(...) (out += scnprintf(out, end - out, __VA_ARGS__))
 
+int bch2_bpos_to_text(char *buf, size_t size, struct bpos pos)
+{
+       char *out = buf, *end = buf + size;
+
+       if (!bkey_cmp(pos, POS_MIN))
+               p("POS_MIN");
+       else if (!bkey_cmp(pos, POS_MAX))
+               p("POS_MAX");
+       else
+               p("%llu:%llu", pos.inode, pos.offset);
+
+       return out - buf;
+}
+
 int bch2_bkey_to_text(char *buf, size_t size, const struct bkey *k)
 {
        char *out = buf, *end = buf + size;
 
        p("u64s %u type %u ", k->u64s, k->type);
 
-       if (bkey_cmp(k->p, POS_MAX))
-               p("%llu:%llu", k->p.inode, k->p.offset);
-       else
-               p("POS_MAX");
+       out += bch2_bpos_to_text(out, end - out, k->p);
 
        p(" snap %u len %u ver %llu", k->p.snapshot, k->size, k->version.lo);
 
                break;
        default:
                if (k.k->type >= KEY_TYPE_GENERIC_NR && ops->val_to_text)
-                       ops->val_to_text(c, buf, size, k);
+                       out += ops->val_to_text(c, out, end - out, k);
                break;
        }
 
 
                                       struct bkey_s_c);
        void            (*key_debugcheck)(struct bch_fs *, struct btree *,
                                          struct bkey_s_c);
-       void            (*val_to_text)(struct bch_fs *, char *,
+       int             (*val_to_text)(struct bch_fs *, char *,
                                       size_t, struct bkey_s_c);
        void            (*swab)(const struct bkey_format *, struct bkey_packed *);
        key_filter_fn   key_normalize;
 
 void bch2_bkey_debugcheck(struct bch_fs *, struct btree *, struct bkey_s_c);
 
+int bch2_bpos_to_text(char *, size_t, struct bpos);
 int bch2_bkey_to_text(char *, size_t, const struct bkey *);
 int bch2_val_to_text(struct bch_fs *, enum bkey_type,
                     char *, size_t, struct bkey_s_c);
 
        }
 }
 
-void bch2_dirent_to_text(struct bch_fs *c, char *buf,
-                        size_t size, struct bkey_s_c k)
+int bch2_dirent_to_text(struct bch_fs *c, char *buf,
+                       size_t size, struct bkey_s_c k)
 {
+       char *out = buf, *end = buf + size;
        struct bkey_s_c_dirent d;
-       size_t n = 0;
 
        switch (k.k->type) {
        case BCH_DIRENT:
                d = bkey_s_c_to_dirent(k);
 
-               n += bch_scnmemcpy(buf + n, size - n, d.v->d_name,
-                                  bch2_dirent_name_bytes(d));
-               n += scnprintf(buf + n, size - n, " -> %llu", d.v->d_inum);
+               out += bch_scnmemcpy(out, end - out, d.v->d_name,
+                                    bch2_dirent_name_bytes(d));
+               out += scnprintf(out, end - out, " -> %llu", d.v->d_inum);
                break;
        case BCH_DIRENT_WHITEOUT:
-               scnprintf(buf, size, "whiteout");
+               out += scnprintf(out, end - out, "whiteout");
                break;
        }
+
+       return out - buf;
 }
 
 static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans,
 
 extern const struct bch_hash_desc bch2_dirent_hash_desc;
 
 const char *bch2_dirent_invalid(const struct bch_fs *, struct bkey_s_c);
-void bch2_dirent_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
+int bch2_dirent_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
 
 #define bch2_bkey_dirent_ops (struct bkey_ops) {       \
        .key_invalid    = bch2_dirent_invalid,          \
 
                      mark.gen, (unsigned) mark.v.counter);
 }
 
-void bch2_btree_ptr_to_text(struct bch_fs *c, char *buf,
-                           size_t size, struct bkey_s_c k)
+int bch2_btree_ptr_to_text(struct bch_fs *c, char *buf,
+                          size_t size, struct bkey_s_c k)
 {
        char *out = buf, *end = buf + size;
        const char *invalid;
        if (invalid)
                p(" invalid: %s", invalid);
 #undef p
+       return out - buf;
 }
 
 int bch2_btree_pick_ptr(struct bch_fs *c, const struct btree *b,
        }
 }
 
-void bch2_extent_to_text(struct bch_fs *c, char *buf,
-                        size_t size, struct bkey_s_c k)
+int bch2_extent_to_text(struct bch_fs *c, char *buf,
+                       size_t size, struct bkey_s_c k)
 {
        char *out = buf, *end = buf + size;
        const char *invalid;
        if (invalid)
                p(" invalid: %s", invalid);
 #undef p
+       return out - buf;
 }
 
 static void bch2_extent_crc_init(union bch_extent_crc *crc,
 
 const char *bch2_btree_ptr_invalid(const struct bch_fs *, struct bkey_s_c);
 void bch2_btree_ptr_debugcheck(struct bch_fs *, struct btree *,
                               struct bkey_s_c);
-void bch2_btree_ptr_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
+int bch2_btree_ptr_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
 void bch2_ptr_swab(const struct bkey_format *, struct bkey_packed *);
 
 #define bch2_bkey_btree_ops (struct bkey_ops) {                        \
 
 const char *bch2_extent_invalid(const struct bch_fs *, struct bkey_s_c);
 void bch2_extent_debugcheck(struct bch_fs *, struct btree *, struct bkey_s_c);
-void bch2_extent_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
+int bch2_extent_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
 bool bch2_ptr_normalize(struct bch_fs *, struct btree *, struct bkey_s);
 enum merge_result bch2_extent_merge(struct bch_fs *, struct btree *,
                                    struct bkey_i *, struct bkey_i *);
 
        }
 }
 
-void bch2_inode_to_text(struct bch_fs *c, char *buf,
-                       size_t size, struct bkey_s_c k)
+int bch2_inode_to_text(struct bch_fs *c, char *buf,
+                      size_t size, struct bkey_s_c k)
 {
        char *out = buf, *end = out + size;
        struct bkey_s_c_inode inode;
 #undef  BCH_INODE_FIELD
                break;
        }
+
+       return out - buf;
 }
 
 void bch2_inode_init(struct bch_fs *c, struct bch_inode_unpacked *inode_u,
 
 #include <linux/math64.h>
 
 const char *bch2_inode_invalid(const struct bch_fs *, struct bkey_s_c);
-void bch2_inode_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
+int bch2_inode_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
 
 #define bch2_bkey_inode_ops (struct bkey_ops) {                \
        .key_invalid    = bch2_inode_invalid,           \
 
        "inodes",
 };
 
-void bch2_quota_to_text(struct bch_fs *c, char *buf,
-                       size_t size, struct bkey_s_c k)
+int bch2_quota_to_text(struct bch_fs *c, char *buf,
+                      size_t size, struct bkey_s_c k)
 {
-       char *out = buf, *end= buf + size;
+       char *out = buf, *end = buf + size;
        struct bkey_s_c_quota dq;
        unsigned i;
 
                                         le64_to_cpu(dq.v->c[i].softlimit));
                break;
        }
+
+       return out - buf;
 }
 
 #ifdef CONFIG_BCACHEFS_QUOTA
 
 extern const struct bch_sb_field_ops bch_sb_field_ops_quota;
 
 const char *bch2_quota_invalid(const struct bch_fs *, struct bkey_s_c);
-void bch2_quota_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
+int bch2_quota_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
 
 #define bch2_bkey_quota_ops (struct bkey_ops) {                \
        .key_invalid    = bch2_quota_invalid,           \
 
        }
 }
 
-void bch2_xattr_to_text(struct bch_fs *c, char *buf,
-                       size_t size, struct bkey_s_c k)
+int bch2_xattr_to_text(struct bch_fs *c, char *buf,
+                      size_t size, struct bkey_s_c k)
 {
+       char *out = buf, *end = buf + size;
        const struct xattr_handler *handler;
        struct bkey_s_c_xattr xattr;
-       size_t n = 0;
 
        switch (k.k->type) {
        case BCH_XATTR:
 
                handler = bch2_xattr_type_to_handler(xattr.v->x_type);
                if (handler && handler->prefix)
-                       n += scnprintf(buf + n, size - n, "%s", handler->prefix);
+                       out += scnprintf(out, end - out, "%s", handler->prefix);
                else if (handler)
-                       n += scnprintf(buf + n, size - n, "(type %u)",
-                                      xattr.v->x_type);
+                       out += scnprintf(out, end - out, "(type %u)",
+                                        xattr.v->x_type);
                else
-                       n += scnprintf(buf + n, size - n, "(unknown type %u)",
-                                      xattr.v->x_type);
-
-               n += bch_scnmemcpy(buf + n, size - n, xattr.v->x_name,
-                                  xattr.v->x_name_len);
-               n += scnprintf(buf + n, size - n, ":");
-               n += bch_scnmemcpy(buf + n, size - n, xattr_val(xattr.v),
-                                  le16_to_cpu(xattr.v->x_val_len));
+                       out += scnprintf(out, end - out, "(unknown type %u)",
+                                        xattr.v->x_type);
+
+               out += bch_scnmemcpy(out, end - out, xattr.v->x_name,
+                                    xattr.v->x_name_len);
+               out += scnprintf(out, end - out, ":");
+               out += bch_scnmemcpy(out, end - out, xattr_val(xattr.v),
+                                    le16_to_cpu(xattr.v->x_val_len));
                break;
        case BCH_XATTR_WHITEOUT:
-               scnprintf(buf, size, "whiteout");
+               out += scnprintf(out, end - out, "whiteout");
                break;
        }
+
+       return out - buf;
 }
 
 int bch2_xattr_get(struct bch_fs *c, struct bch_inode_info *inode,
 
 extern const struct bch_hash_desc bch2_xattr_hash_desc;
 
 const char *bch2_xattr_invalid(const struct bch_fs *, struct bkey_s_c);
-void bch2_xattr_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
+int bch2_xattr_to_text(struct bch_fs *, char *, size_t, struct bkey_s_c);
 
 #define bch2_bkey_xattr_ops (struct bkey_ops) {                \
        .key_invalid    = bch2_xattr_invalid,           \