1 // SPDX-License-Identifier: GPL-2.0
6 #include "bkey_methods.h"
10 const struct bkey_format bch2_bkey_format_current
= BKEY_FORMAT_CURRENT
;
12 void bch2_bkey_packed_to_binary_text(struct printbuf
*out
,
13 const struct bkey_format
*f
,
14 const struct bkey_packed
*k
)
16 const u64
*p
= high_word(f
, k
);
17 unsigned word_bits
= 64 - high_bit_offset
;
18 unsigned nr_key_bits
= bkey_format_key_bits(f
) + high_bit_offset
;
19 u64 v
= *p
& (~0ULL >> high_bit_offset
);
22 prt_str(out
, "(empty)");
27 unsigned next_key_bits
= nr_key_bits
;
29 if (nr_key_bits
< 64) {
30 v
>>= 64 - nr_key_bits
;
36 bch2_prt_u64_base2_nbits(out
, v
, min(word_bits
, nr_key_bits
));
46 nr_key_bits
= next_key_bits
;
50 #ifdef CONFIG_BCACHEFS_DEBUG
52 static void bch2_bkey_pack_verify(const struct bkey_packed
*packed
,
53 const struct bkey
*unpacked
,
54 const struct bkey_format
*format
)
58 BUG_ON(bkeyp_val_u64s(format
, packed
) !=
59 bkey_val_u64s(unpacked
));
61 BUG_ON(packed
->u64s
< bkeyp_key_u64s(format
, packed
));
63 tmp
= __bch2_bkey_unpack_key(format
, packed
);
65 if (memcmp(&tmp
, unpacked
, sizeof(struct bkey
))) {
66 struct printbuf buf
= PRINTBUF
;
68 prt_printf(&buf
, "keys differ: format u64s %u fields %u %u %u %u %u\n",
70 format
->bits_per_field
[0],
71 format
->bits_per_field
[1],
72 format
->bits_per_field
[2],
73 format
->bits_per_field
[3],
74 format
->bits_per_field
[4]);
76 prt_printf(&buf
, "compiled unpack: ");
77 bch2_bkey_to_text(&buf
, unpacked
);
80 prt_printf(&buf
, "c unpack: ");
81 bch2_bkey_to_text(&buf
, &tmp
);
84 prt_printf(&buf
, "compiled unpack: ");
85 bch2_bkey_packed_to_binary_text(&buf
, &bch2_bkey_format_current
,
86 (struct bkey_packed
*) unpacked
);
89 prt_printf(&buf
, "c unpack: ");
90 bch2_bkey_packed_to_binary_text(&buf
, &bch2_bkey_format_current
,
91 (struct bkey_packed
*) &tmp
);
99 static inline void bch2_bkey_pack_verify(const struct bkey_packed
*packed
,
100 const struct bkey
*unpacked
,
101 const struct bkey_format
*format
) {}
105 const struct bkey_format
*format
;
106 unsigned bits
; /* bits remaining in current word */
107 u64 w
; /* current word */
108 u64
*p
; /* pointer to next word */
112 static struct pack_state
pack_state_init(const struct bkey_format
*format
,
113 struct bkey_packed
*k
)
115 u64
*p
= high_word(format
, k
);
117 return (struct pack_state
) {
119 .bits
= 64 - high_bit_offset
,
126 static void pack_state_finish(struct pack_state
*state
,
127 struct bkey_packed
*k
)
129 EBUG_ON(state
->p
< k
->_data
);
130 EBUG_ON(state
->p
>= (u64
*) k
->_data
+ state
->format
->key_u64s
);
132 *state
->p
= state
->w
;
135 struct unpack_state
{
136 const struct bkey_format
*format
;
137 unsigned bits
; /* bits remaining in current word */
138 u64 w
; /* current word */
139 const u64
*p
; /* pointer to next word */
143 static struct unpack_state
unpack_state_init(const struct bkey_format
*format
,
144 const struct bkey_packed
*k
)
146 const u64
*p
= high_word(format
, k
);
148 return (struct unpack_state
) {
150 .bits
= 64 - high_bit_offset
,
151 .w
= *p
<< high_bit_offset
,
157 static u64
get_inc_field(struct unpack_state
*state
, unsigned field
)
159 unsigned bits
= state
->format
->bits_per_field
[field
];
160 u64 v
= 0, offset
= le64_to_cpu(state
->format
->field_offset
[field
]);
162 if (bits
>= state
->bits
) {
163 v
= state
->w
>> (64 - bits
);
166 state
->p
= next_word(state
->p
);
167 state
->w
= *state
->p
;
171 /* avoid shift by 64 if bits is 0 - bits is never 64 here: */
172 v
|= (state
->w
>> 1) >> (63 - bits
);
180 static void __set_inc_field(struct pack_state
*state
, unsigned field
, u64 v
)
182 unsigned bits
= state
->format
->bits_per_field
[field
];
185 if (bits
> state
->bits
) {
187 /* avoid shift by 64 if bits is 64 - bits is never 0 here: */
188 state
->w
|= (v
>> 1) >> (bits
- 1);
190 *state
->p
= state
->w
;
191 state
->p
= next_word(state
->p
);
197 state
->w
|= v
<< state
->bits
;
202 static bool set_inc_field(struct pack_state
*state
, unsigned field
, u64 v
)
204 unsigned bits
= state
->format
->bits_per_field
[field
];
205 u64 offset
= le64_to_cpu(state
->format
->field_offset
[field
]);
215 __set_inc_field(state
, field
, v
);
220 * Note: does NOT set out->format (we don't know what it should be here!)
222 * Also: doesn't work on extents - it doesn't preserve the invariant that
223 * if k is packed bkey_start_pos(k) will successfully pack
225 static bool bch2_bkey_transform_key(const struct bkey_format
*out_f
,
226 struct bkey_packed
*out
,
227 const struct bkey_format
*in_f
,
228 const struct bkey_packed
*in
)
230 struct pack_state out_s
= pack_state_init(out_f
, out
);
231 struct unpack_state in_s
= unpack_state_init(in_f
, in
);
237 for (i
= 0; i
< BKEY_NR_FIELDS
; i
++)
238 if (!set_inc_field(&out_s
, i
, get_inc_field(&in_s
, i
)))
241 /* Can't happen because the val would be too big to unpack: */
242 EBUG_ON(in
->u64s
- in_f
->key_u64s
+ out_f
->key_u64s
> U8_MAX
);
244 pack_state_finish(&out_s
, out
);
245 out
->u64s
= out_f
->key_u64s
+ in
->u64s
- in_f
->key_u64s
;
246 out
->needs_whiteout
= in
->needs_whiteout
;
247 out
->type
= in
->type
;
252 bool bch2_bkey_transform(const struct bkey_format
*out_f
,
253 struct bkey_packed
*out
,
254 const struct bkey_format
*in_f
,
255 const struct bkey_packed
*in
)
257 if (!bch2_bkey_transform_key(out_f
, out
, in_f
, in
))
260 memcpy_u64s((u64
*) out
+ out_f
->key_u64s
,
261 (u64
*) in
+ in_f
->key_u64s
,
262 (in
->u64s
- in_f
->key_u64s
));
266 struct bkey
__bch2_bkey_unpack_key(const struct bkey_format
*format
,
267 const struct bkey_packed
*in
)
269 struct unpack_state state
= unpack_state_init(format
, in
);
272 EBUG_ON(format
->nr_fields
!= BKEY_NR_FIELDS
);
273 EBUG_ON(in
->u64s
< format
->key_u64s
);
274 EBUG_ON(in
->format
!= KEY_FORMAT_LOCAL_BTREE
);
275 EBUG_ON(in
->u64s
- format
->key_u64s
+ BKEY_U64s
> U8_MAX
);
277 out
.u64s
= BKEY_U64s
+ in
->u64s
- format
->key_u64s
;
278 out
.format
= KEY_FORMAT_CURRENT
;
279 out
.needs_whiteout
= in
->needs_whiteout
;
283 #define x(id, field) out.field = get_inc_field(&state, id);
290 #ifndef HAVE_BCACHEFS_COMPILED_UNPACK
291 struct bpos
__bkey_unpack_pos(const struct bkey_format
*format
,
292 const struct bkey_packed
*in
)
294 struct unpack_state state
= unpack_state_init(format
, in
);
297 EBUG_ON(format
->nr_fields
!= BKEY_NR_FIELDS
);
298 EBUG_ON(in
->u64s
< format
->key_u64s
);
299 EBUG_ON(in
->format
!= KEY_FORMAT_LOCAL_BTREE
);
301 out
.inode
= get_inc_field(&state
, BKEY_FIELD_INODE
);
302 out
.offset
= get_inc_field(&state
, BKEY_FIELD_OFFSET
);
303 out
.snapshot
= get_inc_field(&state
, BKEY_FIELD_SNAPSHOT
);
310 * bch2_bkey_pack_key -- pack just the key, not the value
311 * @out: packed result
313 * @format: format of packed result
315 * Returns: true on success, false on failure
317 bool bch2_bkey_pack_key(struct bkey_packed
*out
, const struct bkey
*in
,
318 const struct bkey_format
*format
)
320 struct pack_state state
= pack_state_init(format
, out
);
323 EBUG_ON((void *) in
== (void *) out
);
324 EBUG_ON(format
->nr_fields
!= BKEY_NR_FIELDS
);
325 EBUG_ON(in
->format
!= KEY_FORMAT_CURRENT
);
329 #define x(id, field) if (!set_inc_field(&state, id, in->field)) return false;
332 pack_state_finish(&state
, out
);
333 out
->u64s
= format
->key_u64s
+ in
->u64s
- BKEY_U64s
;
334 out
->format
= KEY_FORMAT_LOCAL_BTREE
;
335 out
->needs_whiteout
= in
->needs_whiteout
;
336 out
->type
= in
->type
;
338 bch2_bkey_pack_verify(out
, in
, format
);
343 * bch2_bkey_unpack -- unpack the key and the value
344 * @b: btree node of @src key (for packed format)
345 * @dst: unpacked result
348 void bch2_bkey_unpack(const struct btree
*b
, struct bkey_i
*dst
,
349 const struct bkey_packed
*src
)
351 __bkey_unpack_key(b
, &dst
->k
, src
);
354 bkeyp_val(&b
->format
, src
),
355 bkeyp_val_u64s(&b
->format
, src
));
359 * bch2_bkey_pack -- pack the key and the value
360 * @dst: packed result
361 * @src: unpacked input
362 * @format: format of packed result
364 * Returns: true on success, false on failure
366 bool bch2_bkey_pack(struct bkey_packed
*dst
, const struct bkey_i
*src
,
367 const struct bkey_format
*format
)
369 struct bkey_packed tmp
;
371 if (!bch2_bkey_pack_key(&tmp
, &src
->k
, format
))
374 memmove_u64s((u64
*) dst
+ format
->key_u64s
,
376 bkey_val_u64s(&src
->k
));
377 memcpy_u64s_small(dst
, &tmp
, format
->key_u64s
);
383 static bool set_inc_field_lossy(struct pack_state
*state
, unsigned field
, u64 v
)
385 unsigned bits
= state
->format
->bits_per_field
[field
];
386 u64 offset
= le64_to_cpu(state
->format
->field_offset
[field
]);
392 if (fls64(v
) > bits
) {
393 v
= ~(~0ULL << bits
);
397 __set_inc_field(state
, field
, v
);
401 #ifdef CONFIG_BCACHEFS_DEBUG
402 static bool bkey_packed_successor(struct bkey_packed
*out
,
403 const struct btree
*b
,
404 struct bkey_packed k
)
406 const struct bkey_format
*f
= &b
->format
;
407 unsigned nr_key_bits
= b
->nr_key_bits
;
408 unsigned first_bit
, offset
;
411 EBUG_ON(b
->nr_key_bits
!= bkey_format_key_bits(f
));
418 first_bit
= high_bit_offset
+ nr_key_bits
- 1;
419 p
= nth_word(high_word(f
, out
), first_bit
>> 6);
420 offset
= 63 - (first_bit
& 63);
422 while (nr_key_bits
) {
423 unsigned bits
= min(64 - offset
, nr_key_bits
);
424 u64 mask
= (~0ULL >> (64 - bits
)) << offset
;
426 if ((*p
& mask
) != mask
) {
427 *p
+= 1ULL << offset
;
428 EBUG_ON(bch2_bkey_cmp_packed(b
, out
, &k
) <= 0);
441 static bool bkey_format_has_too_big_fields(const struct bkey_format
*f
)
443 for (unsigned i
= 0; i
< f
->nr_fields
; i
++) {
444 unsigned unpacked_bits
= bch2_bkey_format_current
.bits_per_field
[i
];
445 u64 unpacked_max
= ~((~0ULL << 1) << (unpacked_bits
- 1));
446 u64 packed_max
= f
->bits_per_field
[i
]
447 ? ~((~0ULL << 1) << (f
->bits_per_field
[i
] - 1))
449 u64 field_offset
= le64_to_cpu(f
->field_offset
[i
]);
451 if (packed_max
+ field_offset
< packed_max
||
452 packed_max
+ field_offset
> unpacked_max
)
461 * Returns a packed key that compares <= in
463 * This is used in bset_search_tree(), where we need a packed pos in order to be
464 * able to compare against the keys in the auxiliary search tree - and it's
465 * legal to use a packed pos that isn't equivalent to the original pos,
466 * _provided_ it compares <= to the original pos.
468 enum bkey_pack_pos_ret
bch2_bkey_pack_pos_lossy(struct bkey_packed
*out
,
470 const struct btree
*b
)
472 const struct bkey_format
*f
= &b
->format
;
473 struct pack_state state
= pack_state_init(f
, out
);
475 #ifdef CONFIG_BCACHEFS_DEBUG
476 struct bpos orig
= in
;
482 * bch2_bkey_pack_key() will write to all of f->key_u64s, minus the 3
483 * byte header, but pack_pos() won't if the len/version fields are big
484 * enough - we need to make sure to zero them out:
486 for (i
= 0; i
< f
->key_u64s
; i
++)
489 if (unlikely(in
.snapshot
<
490 le64_to_cpu(f
->field_offset
[BKEY_FIELD_SNAPSHOT
]))) {
493 return BKEY_PACK_POS_FAIL
;
494 in
.snapshot
= KEY_SNAPSHOT_MAX
;
498 if (unlikely(in
.offset
<
499 le64_to_cpu(f
->field_offset
[BKEY_FIELD_OFFSET
]))) {
501 return BKEY_PACK_POS_FAIL
;
502 in
.offset
= KEY_OFFSET_MAX
;
503 in
.snapshot
= KEY_SNAPSHOT_MAX
;
507 if (unlikely(in
.inode
<
508 le64_to_cpu(f
->field_offset
[BKEY_FIELD_INODE
])))
509 return BKEY_PACK_POS_FAIL
;
511 if (unlikely(!set_inc_field_lossy(&state
, BKEY_FIELD_INODE
, in
.inode
))) {
512 in
.offset
= KEY_OFFSET_MAX
;
513 in
.snapshot
= KEY_SNAPSHOT_MAX
;
517 if (unlikely(!set_inc_field_lossy(&state
, BKEY_FIELD_OFFSET
, in
.offset
))) {
518 in
.snapshot
= KEY_SNAPSHOT_MAX
;
522 if (unlikely(!set_inc_field_lossy(&state
, BKEY_FIELD_SNAPSHOT
, in
.snapshot
)))
525 pack_state_finish(&state
, out
);
526 out
->u64s
= f
->key_u64s
;
527 out
->format
= KEY_FORMAT_LOCAL_BTREE
;
528 out
->type
= KEY_TYPE_deleted
;
530 #ifdef CONFIG_BCACHEFS_DEBUG
532 BUG_ON(bkey_cmp_left_packed(b
, out
, &orig
));
534 struct bkey_packed successor
;
536 BUG_ON(bkey_cmp_left_packed(b
, out
, &orig
) >= 0);
537 BUG_ON(bkey_packed_successor(&successor
, b
, *out
) &&
538 bkey_cmp_left_packed(b
, &successor
, &orig
) < 0 &&
539 !bkey_format_has_too_big_fields(f
));
543 return exact
? BKEY_PACK_POS_EXACT
: BKEY_PACK_POS_SMALLER
;
546 void bch2_bkey_format_init(struct bkey_format_state
*s
)
550 for (i
= 0; i
< ARRAY_SIZE(s
->field_min
); i
++)
551 s
->field_min
[i
] = U64_MAX
;
553 for (i
= 0; i
< ARRAY_SIZE(s
->field_max
); i
++)
556 /* Make sure we can store a size of 0: */
557 s
->field_min
[BKEY_FIELD_SIZE
] = 0;
560 void bch2_bkey_format_add_pos(struct bkey_format_state
*s
, struct bpos p
)
564 __bkey_format_add(s
, field
++, p
.inode
);
565 __bkey_format_add(s
, field
++, p
.offset
);
566 __bkey_format_add(s
, field
++, p
.snapshot
);
570 * We don't want it to be possible for the packed format to represent fields
571 * bigger than a u64... that will cause confusion and issues (like with
572 * bkey_packed_successor())
574 static void set_format_field(struct bkey_format
*f
, enum bch_bkey_fields i
,
575 unsigned bits
, u64 offset
)
577 unsigned unpacked_bits
= bch2_bkey_format_current
.bits_per_field
[i
];
578 u64 unpacked_max
= ~((~0ULL << 1) << (unpacked_bits
- 1));
580 bits
= min(bits
, unpacked_bits
);
582 offset
= bits
== unpacked_bits
? 0 : min(offset
, unpacked_max
- ((1ULL << bits
) - 1));
584 f
->bits_per_field
[i
] = bits
;
585 f
->field_offset
[i
] = cpu_to_le64(offset
);
588 struct bkey_format
bch2_bkey_format_done(struct bkey_format_state
*s
)
590 unsigned i
, bits
= KEY_PACKED_BITS_START
;
591 struct bkey_format ret
= {
592 .nr_fields
= BKEY_NR_FIELDS
,
595 for (i
= 0; i
< ARRAY_SIZE(s
->field_min
); i
++) {
596 s
->field_min
[i
] = min(s
->field_min
[i
], s
->field_max
[i
]);
598 set_format_field(&ret
, i
,
599 fls64(s
->field_max
[i
] - s
->field_min
[i
]),
602 bits
+= ret
.bits_per_field
[i
];
605 /* allow for extent merging: */
606 if (ret
.bits_per_field
[BKEY_FIELD_SIZE
]) {
607 unsigned b
= min(4U, 32U - ret
.bits_per_field
[BKEY_FIELD_SIZE
]);
609 ret
.bits_per_field
[BKEY_FIELD_SIZE
] += b
;
613 ret
.key_u64s
= DIV_ROUND_UP(bits
, 64);
615 /* if we have enough spare bits, round fields up to nearest byte */
616 bits
= ret
.key_u64s
* 64 - bits
;
618 for (i
= 0; i
< ARRAY_SIZE(ret
.bits_per_field
); i
++) {
619 unsigned r
= round_up(ret
.bits_per_field
[i
], 8) -
620 ret
.bits_per_field
[i
];
623 set_format_field(&ret
, i
,
624 ret
.bits_per_field
[i
] + r
,
625 le64_to_cpu(ret
.field_offset
[i
]));
630 #ifdef CONFIG_BCACHEFS_DEBUG
632 struct printbuf buf
= PRINTBUF
;
634 BUG_ON(bch2_bkey_format_invalid(NULL
, &ret
, 0, &buf
));
641 int bch2_bkey_format_invalid(struct bch_fs
*c
,
642 struct bkey_format
*f
,
643 enum bch_validate_flags flags
,
644 struct printbuf
*err
)
646 unsigned bits
= KEY_PACKED_BITS_START
;
648 if (f
->nr_fields
!= BKEY_NR_FIELDS
) {
649 prt_printf(err
, "incorrect number of fields: got %u, should be %u",
650 f
->nr_fields
, BKEY_NR_FIELDS
);
651 return -BCH_ERR_invalid
;
655 * Verify that the packed format can't represent fields larger than the
658 for (unsigned i
= 0; i
< f
->nr_fields
; i
++) {
659 if (bch2_bkey_format_field_overflows(f
, i
)) {
660 unsigned unpacked_bits
= bch2_bkey_format_current
.bits_per_field
[i
];
661 u64 unpacked_max
= ~((~0ULL << 1) << (unpacked_bits
- 1));
662 unsigned packed_bits
= min(64, f
->bits_per_field
[i
]);
663 u64 packed_max
= packed_bits
664 ? ~((~0ULL << 1) << (packed_bits
- 1))
667 prt_printf(err
, "field %u too large: %llu + %llu > %llu",
668 i
, packed_max
, le64_to_cpu(f
->field_offset
[i
]), unpacked_max
);
669 return -BCH_ERR_invalid
;
672 bits
+= f
->bits_per_field
[i
];
675 if (f
->key_u64s
!= DIV_ROUND_UP(bits
, 64)) {
676 prt_printf(err
, "incorrect key_u64s: got %u, should be %u",
677 f
->key_u64s
, DIV_ROUND_UP(bits
, 64));
678 return -BCH_ERR_invalid
;
684 void bch2_bkey_format_to_text(struct printbuf
*out
, const struct bkey_format
*f
)
686 prt_printf(out
, "u64s %u fields ", f
->key_u64s
);
688 for (unsigned i
= 0; i
< ARRAY_SIZE(f
->bits_per_field
); i
++) {
691 prt_printf(out
, "%u:%llu",
692 f
->bits_per_field
[i
],
693 le64_to_cpu(f
->field_offset
[i
]));
698 * Most significant differing bit
699 * Bits are indexed from 0 - return is [0, nr_key_bits)
702 unsigned bch2_bkey_greatest_differing_bit(const struct btree
*b
,
703 const struct bkey_packed
*l_k
,
704 const struct bkey_packed
*r_k
)
706 const u64
*l
= high_word(&b
->format
, l_k
);
707 const u64
*r
= high_word(&b
->format
, r_k
);
708 unsigned nr_key_bits
= b
->nr_key_bits
;
709 unsigned word_bits
= 64 - high_bit_offset
;
712 EBUG_ON(b
->nr_key_bits
!= bkey_format_key_bits(&b
->format
));
714 /* for big endian, skip past header */
715 l_v
= *l
& (~0ULL >> high_bit_offset
);
716 r_v
= *r
& (~0ULL >> high_bit_offset
);
718 while (nr_key_bits
) {
719 if (nr_key_bits
< word_bits
) {
720 l_v
>>= word_bits
- nr_key_bits
;
721 r_v
>>= word_bits
- nr_key_bits
;
724 nr_key_bits
-= word_bits
;
728 return fls64(l_v
^ r_v
) - 1 + nr_key_bits
;
743 * Bits are indexed from 0 - return is [0, nr_key_bits)
746 unsigned bch2_bkey_ffs(const struct btree
*b
, const struct bkey_packed
*k
)
748 const u64
*p
= high_word(&b
->format
, k
);
749 unsigned nr_key_bits
= b
->nr_key_bits
;
750 unsigned ret
= 0, offset
;
752 EBUG_ON(b
->nr_key_bits
!= bkey_format_key_bits(&b
->format
));
754 offset
= nr_key_bits
;
755 while (offset
> 64) {
760 offset
= 64 - offset
;
762 while (nr_key_bits
) {
763 unsigned bits
= nr_key_bits
+ offset
< 64
767 u64 mask
= (~0ULL >> (64 - bits
)) << offset
;
770 return ret
+ __ffs64(*p
& mask
) - offset
;
781 #ifdef HAVE_BCACHEFS_COMPILED_UNPACK
783 #define I(_x) (*(out)++ = (_x))
785 #define I2(i0, i1) (I1(i0), I(i1))
786 #define I3(i0, i1, i2) (I2(i0, i1), I(i2))
787 #define I4(i0, i1, i2, i3) (I3(i0, i1, i2), I(i3))
788 #define I5(i0, i1, i2, i3, i4) (I4(i0, i1, i2, i3), I(i4))
790 static u8
*compile_bkey_field(const struct bkey_format
*format
, u8
*out
,
791 enum bch_bkey_fields field
,
792 unsigned dst_offset
, unsigned dst_size
,
795 unsigned bits
= format
->bits_per_field
[field
];
796 u64 offset
= le64_to_cpu(format
->field_offset
[field
]);
797 unsigned i
, byte
, bit_offset
, align
, shl
, shr
;
799 if (!bits
&& !offset
) {
810 /* just return offset: */
814 if (offset
> S32_MAX
) {
815 /* mov [rdi + dst_offset], offset */
816 I3(0xc7, 0x47, dst_offset
);
817 memcpy(out
, &offset
, 4);
820 I3(0xc7, 0x47, dst_offset
+ 4);
821 memcpy(out
, (void *) &offset
+ 4, 4);
824 /* mov [rdi + dst_offset], offset */
826 I4(0x48, 0xc7, 0x47, dst_offset
);
827 memcpy(out
, &offset
, 4);
832 /* mov [rdi + dst_offset], offset */
833 I3(0xc7, 0x47, dst_offset
);
834 memcpy(out
, &offset
, 4);
844 bit_offset
= format
->key_u64s
* 64;
845 for (i
= 0; i
<= field
; i
++)
846 bit_offset
-= format
->bits_per_field
[i
];
848 byte
= bit_offset
/ 8;
849 bit_offset
-= byte
* 8;
853 if (bit_offset
== 0 && bits
== 8) {
854 /* movzx eax, BYTE PTR [rsi + imm8] */
855 I4(0x0f, 0xb6, 0x46, byte
);
856 } else if (bit_offset
== 0 && bits
== 16) {
857 /* movzx eax, WORD PTR [rsi + imm8] */
858 I4(0x0f, 0xb7, 0x46, byte
);
859 } else if (bit_offset
+ bits
<= 32) {
860 align
= min(4 - DIV_ROUND_UP(bit_offset
+ bits
, 8), byte
& 3);
862 bit_offset
+= align
* 8;
864 BUG_ON(bit_offset
+ bits
> 32);
866 /* mov eax, [rsi + imm8] */
867 I3(0x8b, 0x46, byte
);
871 I3(0xc1, 0xe8, bit_offset
);
874 if (bit_offset
+ bits
< 32) {
875 unsigned mask
= ~0U >> (32 - bits
);
879 memcpy(out
, &mask
, 4);
882 } else if (bit_offset
+ bits
<= 64) {
883 align
= min(8 - DIV_ROUND_UP(bit_offset
+ bits
, 8), byte
& 7);
885 bit_offset
+= align
* 8;
887 BUG_ON(bit_offset
+ bits
> 64);
889 /* mov rax, [rsi + imm8] */
890 I4(0x48, 0x8b, 0x46, byte
);
892 shl
= 64 - bit_offset
- bits
;
893 shr
= bit_offset
+ shl
;
897 I4(0x48, 0xc1, 0xe0, shl
);
902 I4(0x48, 0xc1, 0xe8, shr
);
905 align
= min(4 - DIV_ROUND_UP(bit_offset
+ bits
, 8), byte
& 3);
907 bit_offset
+= align
* 8;
909 BUG_ON(bit_offset
+ bits
> 96);
911 /* mov rax, [rsi + byte] */
912 I4(0x48, 0x8b, 0x46, byte
);
914 /* mov edx, [rsi + byte + 8] */
915 I3(0x8b, 0x56, byte
+ 8);
917 /* bits from next word: */
918 shr
= bit_offset
+ bits
- 64;
919 BUG_ON(shr
> bit_offset
);
921 /* shr rax, bit_offset */
922 I4(0x48, 0xc1, 0xe8, shr
);
925 I4(0x48, 0xc1, 0xe2, 64 - shr
);
928 I3(0x48, 0x09, 0xd0);
930 shr
= bit_offset
- shr
;
934 I4(0x48, 0xc1, 0xe8, shr
);
939 if (offset
> S32_MAX
) {
942 memcpy(out
, &offset
, 8);
945 I3(0x48, 0x01, 0xd0);
946 } else if (offset
+ (~0ULL >> (64 - bits
)) > U32_MAX
) {
949 memcpy(out
, &offset
, 4);
954 memcpy(out
, &offset
, 4);
960 /* mov [rdi + dst_offset], rax */
961 I4(0x48, 0x89, 0x47, dst_offset
);
964 /* mov [rdi + dst_offset], eax */
965 I3(0x89, 0x47, dst_offset
);
974 int bch2_compile_bkey_format(const struct bkey_format
*format
, void *_out
)
976 bool eax_zeroed
= false;
980 * rdi: dst - unpacked key
981 * rsi: src - packed key
984 /* k->u64s, k->format, k->type */
989 /* add eax, BKEY_U64s - format->key_u64s */
990 I5(0x05, BKEY_U64s
- format
->key_u64s
, KEY_FORMAT_CURRENT
, 0, 0);
992 /* and eax, imm32: mask out k->pad: */
993 I5(0x25, 0xff, 0xff, 0xff, 0);
998 #define x(id, field) \
999 out = compile_bkey_field(format, out, id, \
1000 offsetof(struct bkey, field), \
1001 sizeof(((struct bkey *) NULL)->field), \
1009 return (void *) out
- _out
;
1016 int __bch2_bkey_cmp_packed_format_checked(const struct bkey_packed
*l
,
1017 const struct bkey_packed
*r
,
1018 const struct btree
*b
)
1020 return __bch2_bkey_cmp_packed_format_checked_inlined(l
, r
, b
);
1024 int __bch2_bkey_cmp_left_packed_format_checked(const struct btree
*b
,
1025 const struct bkey_packed
*l
,
1026 const struct bpos
*r
)
1028 return bpos_cmp(bkey_unpack_pos_format_checked(b
, l
), *r
);
1032 int bch2_bkey_cmp_packed(const struct btree
*b
,
1033 const struct bkey_packed
*l
,
1034 const struct bkey_packed
*r
)
1036 return bch2_bkey_cmp_packed_inlined(b
, l
, r
);
1040 int __bch2_bkey_cmp_left_packed(const struct btree
*b
,
1041 const struct bkey_packed
*l
,
1042 const struct bpos
*r
)
1044 const struct bkey
*l_unpacked
;
1046 return unlikely(l_unpacked
= packed_to_bkey_c(l
))
1047 ? bpos_cmp(l_unpacked
->p
, *r
)
1048 : __bch2_bkey_cmp_left_packed_format_checked(b
, l
, r
);
1051 void bch2_bpos_swab(struct bpos
*p
)
1054 u8
*h
= ((u8
*) &p
[1]) - 1;
1063 void bch2_bkey_swab_key(const struct bkey_format
*_f
, struct bkey_packed
*k
)
1065 const struct bkey_format
*f
= bkey_packed(k
) ? _f
: &bch2_bkey_format_current
;
1066 u8
*l
= k
->key_start
;
1067 u8
*h
= (u8
*) ((u64
*) k
->_data
+ f
->key_u64s
) - 1;
1076 #ifdef CONFIG_BCACHEFS_DEBUG
1077 void bch2_bkey_pack_test(void)
1079 struct bkey t
= KEY(4134ULL, 1250629070527416633ULL, 0);
1080 struct bkey_packed p
;
1082 struct bkey_format test_format
= {
1084 .nr_fields
= BKEY_NR_FIELDS
,
1092 struct unpack_state in_s
=
1093 unpack_state_init(&bch2_bkey_format_current
, (void *) &t
);
1094 struct pack_state out_s
= pack_state_init(&test_format
, &p
);
1097 for (i
= 0; i
< out_s
.format
->nr_fields
; i
++) {
1098 u64 a
, v
= get_inc_field(&in_s
, i
);
1101 #define x(id, field) case id: a = t.field; break;
1109 panic("got %llu actual %llu i %u\n", v
, a
, i
);
1111 if (!set_inc_field(&out_s
, i
, v
))
1112 panic("failed at %u\n", i
);
1115 BUG_ON(!bch2_bkey_pack_key(&p
, &t
, &test_format
));