// SPDX-License-Identifier: GPL-2.0
#include "bcachefs.h"
#include "bkey.h"
#include "bkey_cmp.h"
#include "bkey_methods.h"
#include "bset.h"
#include "util.h"
const struct bkey_format bch2_bkey_format_current = BKEY_FORMAT_CURRENT;
void bch2_bkey_packed_to_binary_text(struct printbuf *out,
const struct bkey_format *f,
const struct bkey_packed *k)
{
const u64 *p = high_word(f, k);
unsigned word_bits = 64 - high_bit_offset;
unsigned nr_key_bits = bkey_format_key_bits(f) + high_bit_offset;
u64 v = *p & (~0ULL >> high_bit_offset);
if (!nr_key_bits) {
prt_str(out, "(empty)");
return;
}
while (1) {
unsigned next_key_bits = nr_key_bits;
if (nr_key_bits < 64) {
v >>= 64 - nr_key_bits;
next_key_bits = 0;
} else {
next_key_bits -= 64;
}
bch2_prt_u64_base2_nbits(out, v, min(word_bits, nr_key_bits));
if (!next_key_bits)
break;
prt_char(out, ' ');
p = next_word(p);
v = *p;
word_bits = 64;
nr_key_bits = next_key_bits;
}
}
#ifdef CONFIG_BCACHEFS_DEBUG
static void bch2_bkey_pack_verify(const struct bkey_packed *packed,
const struct bkey *unpacked,
const struct bkey_format *format)
{
struct bkey tmp;
BUG_ON(bkeyp_val_u64s(format, packed) !=
bkey_val_u64s(unpacked));
BUG_ON(packed->u64s < bkeyp_key_u64s(format, packed));
tmp = __bch2_bkey_unpack_key(format, packed);
if (memcmp(&tmp, unpacked, sizeof(struct bkey))) {
struct printbuf buf = PRINTBUF;
prt_printf(&buf, "keys differ: format u64s %u fields %u %u %u %u %u\n",
format->key_u64s,
format->bits_per_field[0],
format->bits_per_field[1],
format->bits_per_field[2],
format->bits_per_field[3],
format->bits_per_field[4]);
prt_printf(&buf, "compiled unpack: ");
bch2_bkey_to_text(&buf, unpacked);
prt_newline(&buf);
prt_printf(&buf, "c unpack: ");
bch2_bkey_to_text(&buf, &tmp);
prt_newline(&buf);
prt_printf(&buf, "compiled unpack: ");
bch2_bkey_packed_to_binary_text(&buf, &bch2_bkey_format_current,
(struct bkey_packed *) unpacked);
prt_newline(&buf);
prt_printf(&buf, "c unpack: ");
bch2_bkey_packed_to_binary_text(&buf, &bch2_bkey_format_current,
(struct bkey_packed *) &tmp);
prt_newline(&buf);
panic("%s", buf.buf);
}
}
#else
static inline void bch2_bkey_pack_verify(const struct bkey_packed *packed,
const struct bkey *unpacked,
const struct bkey_format *format) {}
#endif
struct pack_state {
const struct bkey_format *format;
unsigned bits; /* bits remaining in current word */
u64 w; /* current word */
u64 *p; /* pointer to next word */
};
__always_inline
static struct pack_state pack_state_init(const struct bkey_format *format,
struct bkey_packed *k)
{
u64 *p = high_word(format, k);
return (struct pack_state) {
.format = format,
.bits = 64 - high_bit_offset,
.w = 0,
.p = p,
};
}
__always_inline
static void pack_state_finish(struct pack_state *state,
struct bkey_packed *k)
{
EBUG_ON(state->p < k->_data);
EBUG_ON(state->p >= (u64 *) k->_data + state->format->key_u64s);
*state->p = state->w;
}
struct unpack_state {
const struct bkey_format *format;
unsigned bits; /* bits remaining in current word */
u64 w; /* current word */
const u64 *p; /* pointer to next word */
};
__always_inline
static struct unpack_state unpack_state_init(const struct bkey_format *format,
const struct bkey_packed *k)
{
const u64 *p = high_word(format, k);
return (struct unpack_state) {
.format = format,
.bits = 64 - high_bit_offset,
.w = *