// SPDX-License-Identifier: GPL-2.0
#include "bcachefs.h"
#include "bkey.h"
#include "bkey_methods.h"
#include "bset.h"
#include "util.h"
#undef EBUG_ON
#ifdef DEBUG_BKEYS
#define EBUG_ON(cond) BUG_ON(cond)
#else
#define EBUG_ON(cond)
#endif
const struct bkey_format bch2_bkey_format_current = BKEY_FORMAT_CURRENT;
struct bkey __bch2_bkey_unpack_key(const struct bkey_format *,
const struct bkey_packed *);
void bch2_to_binary(char *out, const u64 *p, unsigned nr_bits)
{
unsigned bit = high_bit_offset, done = 0;
while (1) {
while (bit < 64) {
if (done && !(done % 8))
*out++ = ' ';
*out++ = *p & (1ULL << (63 - bit)) ? '1' : '0';
bit++;
done++;
if (done == nr_bits) {
*out++ = '\0';
return;
}
}
p = next_word(p);
bit = 0;
}
}
#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 buf1 = PRINTBUF;
struct printbuf buf2 = PRINTBUF;
char buf3[160], buf4[160];
bch2_bkey_to_text(&buf1, unpacked);
bch2_bkey_to_text(&buf2, &tmp);
bch2_to_binary(buf3, (void *) unpacked, 80);
bch2_to_binary(buf4, high_word(format, packed), 80);
panic("keys differ: format u64s %u fields %u %u %u %u %u\n%s\n%s\n%s\n%s\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],
buf1.buf, buf2.buf, buf3, buf4);
}
}
#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 >= 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