]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/bkey.c
Disable pristine-tar option in gbp.conf, since there is no pristine-tar branch.
[bcachefs-tools-debian] / libbcachefs / bkey.c
index 630df060fbe934b5ff8d936eed91b13b792f8f81..76e79a15ba08fb23ed9d0560dcd5966fe68ce92a 100644 (file)
@@ -7,14 +7,6 @@
 #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;
 
 void bch2_bkey_packed_to_binary_text(struct printbuf *out,
@@ -41,7 +33,7 @@ void bch2_bkey_packed_to_binary_text(struct printbuf *out,
                        next_key_bits -= 64;
                }
 
-               bch2_prt_u64_binary(out, v, min(word_bits, nr_key_bits));
+               bch2_prt_u64_base2_nbits(out, v, min(word_bits, nr_key_bits));
 
                if (!next_key_bits)
                        break;
@@ -135,7 +127,7 @@ 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);
+       EBUG_ON(state->p >= (u64 *) k->_data + state->format->key_u64s);
 
        *state->p = state->w;
 }
@@ -184,6 +176,28 @@ static u64 get_inc_field(struct unpack_state *state, unsigned field)
        return v + offset;
 }
 
+__always_inline
+static void __set_inc_field(struct pack_state *state, unsigned field, u64 v)
+{
+       unsigned bits = state->format->bits_per_field[field];
+
+       if (bits) {
+               if (bits > state->bits) {
+                       bits -= state->bits;
+                       /* avoid shift by 64 if bits is 64 - bits is never 0 here: */
+                       state->w |= (v >> 1) >> (bits - 1);
+
+                       *state->p = state->w;
+                       state->p = next_word(state->p);
+                       state->w = 0;
+                       state->bits = 64;
+               }
+
+               state->bits -= bits;
+               state->w |= v << state->bits;
+       }
+}
+
 __always_inline
 static bool set_inc_field(struct pack_state *state, unsigned field, u64 v)
 {
@@ -198,20 +212,7 @@ static bool set_inc_field(struct pack_state *state, unsigned field, u64 v)
        if (fls64(v) > bits)
                return false;
 
-       if (bits > state->bits) {
-               bits -= state->bits;
-               /* avoid shift by 64 if bits is 0 - bits is never 64 here: */
-               state->w |= (v >> 1) >> (bits - 1);
-
-               *state->p = state->w;
-               state->p = next_word(state->p);
-               state->w = 0;
-               state->bits = 64;
-       }
-
-       state->bits -= bits;
-       state->w |= v << state->bits;
-
+       __set_inc_field(state, field, v);
        return true;
 }
 
@@ -262,14 +263,6 @@ bool bch2_bkey_transform(const struct bkey_format *out_f,
        return true;
 }
 
-#define bkey_fields()                                                  \
-       x(BKEY_FIELD_INODE,             p.inode)                        \
-       x(BKEY_FIELD_OFFSET,            p.offset)                       \
-       x(BKEY_FIELD_SNAPSHOT,          p.snapshot)                     \
-       x(BKEY_FIELD_SIZE,              size)                           \
-       x(BKEY_FIELD_VERSION_HI,        version.hi)                     \
-       x(BKEY_FIELD_VERSION_LO,        version.lo)
-
 struct bkey __bch2_bkey_unpack_key(const struct bkey_format *format,
                              const struct bkey_packed *in)
 {
@@ -315,9 +308,14 @@ struct bpos __bkey_unpack_pos(const struct bkey_format *format,
 
 /**
  * bch2_bkey_pack_key -- pack just the key, not the value
+ * @out:       packed result
+ * @in:                key to pack
+ * @format:    format of packed result
+ *
+ * Returns: true on success, false on failure
  */
 bool bch2_bkey_pack_key(struct bkey_packed *out, const struct bkey *in,
-                  const struct bkey_format *format)
+                       const struct bkey_format *format)
 {
        struct pack_state state = pack_state_init(format, out);
        u64 *w = out->_data;
@@ -331,15 +329,6 @@ bool bch2_bkey_pack_key(struct bkey_packed *out, const struct bkey *in,
 #define x(id, field)   if (!set_inc_field(&state, id, in->field)) return false;
        bkey_fields()
 #undef x
-
-       /*
-        * Extents - we have to guarantee that if an extent is packed, a trimmed
-        * version will also pack:
-        */
-       if (bkey_start_offset(in) <
-           le64_to_cpu(format->field_offset[BKEY_FIELD_OFFSET]))
-               return false;
-
        pack_state_finish(&state, out);
        out->u64s       = format->key_u64s + in->u64s - BKEY_U64s;
        out->format     = KEY_FORMAT_LOCAL_BTREE;
@@ -352,9 +341,12 @@ bool bch2_bkey_pack_key(struct bkey_packed *out, const struct bkey *in,
 
 /**
  * bch2_bkey_unpack -- unpack the key and the value
+ * @b:         btree node of @src key (for packed format)
+ * @dst:       unpacked result
+ * @src:       packed input
  */
 void bch2_bkey_unpack(const struct btree *b, struct bkey_i *dst,
-                const struct bkey_packed *src)
+                     const struct bkey_packed *src)
 {
        __bkey_unpack_key(b, &dst->k, src);
 
@@ -365,19 +357,24 @@ void bch2_bkey_unpack(const struct btree *b, struct bkey_i *dst,
 
 /**
  * bch2_bkey_pack -- pack the key and the value
+ * @dst:       packed result
+ * @src:       unpacked input
+ * @format:    format of packed result
+ *
+ * Returns: true on success, false on failure
  */
-bool bch2_bkey_pack(struct bkey_packed *out, const struct bkey_i *in,
-              const struct bkey_format *format)
+bool bch2_bkey_pack(struct bkey_packed *dst, const struct bkey_i *src,
+                   const struct bkey_format *format)
 {
        struct bkey_packed tmp;
 
-       if (!bch2_bkey_pack_key(&tmp, &in->k, format))
+       if (!bch2_bkey_pack_key(&tmp, &src->k, format))
                return false;
 
-       memmove_u64s((u64 *) out + format->key_u64s,
-                    &in->v,
-                    bkey_val_u64s(&in->k));
-       memcpy_u64s(out, &tmp, format->key_u64s);
+       memmove_u64s((u64 *) dst + format->key_u64s,
+                    &src->v,
+                    bkey_val_u64s(&src->k));
+       memcpy_u64s_small(dst, &tmp, format->key_u64s);
 
        return true;
 }
@@ -397,19 +394,7 @@ static bool set_inc_field_lossy(struct pack_state *state, unsigned field, u64 v)
                ret = false;
        }
 
-       if (bits > state->bits) {
-               bits -= state->bits;
-               state->w |= (v >> 1) >> (bits - 1);
-
-               *state->p = state->w;
-               state->p = next_word(state->p);
-               state->w = 0;
-               state->bits = 64;
-       }
-
-       state->bits -= bits;
-       state->w |= v << state->bits;
-
+       __set_inc_field(state, field, v);
        return ret;
 }
 
@@ -452,6 +437,24 @@ static bool bkey_packed_successor(struct bkey_packed *out,
 
        return false;
 }
+
+static bool bkey_format_has_too_big_fields(const struct bkey_format *f)
+{
+       for (unsigned i = 0; i < f->nr_fields; i++) {
+               unsigned unpacked_bits = bch2_bkey_format_current.bits_per_field[i];
+               u64 unpacked_max = ~((~0ULL << 1) << (unpacked_bits - 1));
+               u64 packed_max = f->bits_per_field[i]
+                       ? ~((~0ULL << 1) << (f->bits_per_field[i] - 1))
+                       : 0;
+               u64 field_offset = le64_to_cpu(f->field_offset[i]);
+
+               if (packed_max + field_offset < packed_max ||
+                   packed_max + field_offset > unpacked_max)
+                       return true;
+       }
+
+       return false;
+}
 #endif
 
 /*
@@ -505,18 +508,18 @@ enum bkey_pack_pos_ret bch2_bkey_pack_pos_lossy(struct bkey_packed *out,
                     le64_to_cpu(f->field_offset[BKEY_FIELD_INODE])))
                return BKEY_PACK_POS_FAIL;
 
-       if (!set_inc_field_lossy(&state, BKEY_FIELD_INODE, in.inode)) {
+       if (unlikely(!set_inc_field_lossy(&state, BKEY_FIELD_INODE, in.inode))) {
                in.offset       = KEY_OFFSET_MAX;
                in.snapshot     = KEY_SNAPSHOT_MAX;
                exact = false;
        }
 
-       if (!set_inc_field_lossy(&state, BKEY_FIELD_OFFSET, in.offset)) {
+       if (unlikely(!set_inc_field_lossy(&state, BKEY_FIELD_OFFSET, in.offset))) {
                in.snapshot     = KEY_SNAPSHOT_MAX;
                exact = false;
        }
 
-       if (!set_inc_field_lossy(&state, BKEY_FIELD_SNAPSHOT, in.snapshot))
+       if (unlikely(!set_inc_field_lossy(&state, BKEY_FIELD_SNAPSHOT, in.snapshot)))
                exact = false;
 
        pack_state_finish(&state, out);
@@ -532,7 +535,8 @@ enum bkey_pack_pos_ret bch2_bkey_pack_pos_lossy(struct bkey_packed *out,
 
                BUG_ON(bkey_cmp_left_packed(b, out, &orig) >= 0);
                BUG_ON(bkey_packed_successor(&successor, b, *out) &&
-                      bkey_cmp_left_packed(b, &successor, &orig) < 0);
+                      bkey_cmp_left_packed(b, &successor, &orig) < 0 &&
+                      !bkey_format_has_too_big_fields(f));
        }
 #endif
 
@@ -553,24 +557,6 @@ void bch2_bkey_format_init(struct bkey_format_state *s)
        s->field_min[BKEY_FIELD_SIZE] = 0;
 }
 
-static void __bkey_format_add(struct bkey_format_state *s,
-                             unsigned field, u64 v)
-{
-       s->field_min[field] = min(s->field_min[field], v);
-       s->field_max[field] = max(s->field_max[field], v);
-}
-
-/*
- * Changes @format so that @k can be successfully packed with @format
- */
-void bch2_bkey_format_add_key(struct bkey_format_state *s, const struct bkey *k)
-{
-#define x(id, field) __bkey_format_add(s, id, k->field);
-       bkey_fields()
-#undef x
-       __bkey_format_add(s, BKEY_FIELD_OFFSET, bkey_start_offset(k));
-}
-
 void bch2_bkey_format_add_pos(struct bkey_format_state *s, struct bpos p)
 {
        unsigned field = 0;
@@ -618,8 +604,10 @@ struct bkey_format bch2_bkey_format_done(struct bkey_format_state *s)
 
        /* allow for extent merging: */
        if (ret.bits_per_field[BKEY_FIELD_SIZE]) {
-               ret.bits_per_field[BKEY_FIELD_SIZE] += 4;
-               bits += 4;
+               unsigned b = min(4U, 32U - ret.bits_per_field[BKEY_FIELD_SIZE]);
+
+               ret.bits_per_field[BKEY_FIELD_SIZE] += b;
+               bits += b;
        }
 
        ret.key_u64s = DIV_ROUND_UP(bits, 64);
@@ -639,40 +627,74 @@ struct bkey_format bch2_bkey_format_done(struct bkey_format_state *s)
                }
        }
 
-       EBUG_ON(bch2_bkey_format_validate(&ret));
+#ifdef CONFIG_BCACHEFS_DEBUG
+       {
+               struct printbuf buf = PRINTBUF;
+
+               BUG_ON(bch2_bkey_format_invalid(NULL, &ret, 0, &buf));
+               printbuf_exit(&buf);
+       }
+#endif
        return ret;
 }
 
-const char *bch2_bkey_format_validate(struct bkey_format *f)
+int bch2_bkey_format_invalid(struct bch_fs *c,
+                            struct bkey_format *f,
+                            enum bkey_invalid_flags flags,
+                            struct printbuf *err)
 {
        unsigned i, bits = KEY_PACKED_BITS_START;
 
-       if (f->nr_fields != BKEY_NR_FIELDS)
-               return "incorrect number of fields";
+       if (f->nr_fields != BKEY_NR_FIELDS) {
+               prt_printf(err, "incorrect number of fields: got %u, should be %u",
+                          f->nr_fields, BKEY_NR_FIELDS);
+               return -BCH_ERR_invalid;
+       }
 
        /*
         * Verify that the packed format can't represent fields larger than the
         * unpacked format:
         */
        for (i = 0; i < f->nr_fields; i++) {
-               unsigned unpacked_bits = bch2_bkey_format_current.bits_per_field[i];
-               u64 unpacked_max = ~((~0ULL << 1) << (unpacked_bits - 1));
-               u64 packed_max = f->bits_per_field[i]
-                       ? ~((~0ULL << 1) << (f->bits_per_field[i] - 1))
-                       : 0;
-               u64 field_offset = le64_to_cpu(f->field_offset[i]);
-
-               if (packed_max + field_offset < packed_max ||
-                   packed_max + field_offset > unpacked_max)
-                       return "field too large";
+               if (!c || c->sb.version_min >= bcachefs_metadata_version_snapshot) {
+                       unsigned unpacked_bits = bch2_bkey_format_current.bits_per_field[i];
+                       u64 unpacked_max = ~((~0ULL << 1) << (unpacked_bits - 1));
+                       u64 packed_max = f->bits_per_field[i]
+                               ? ~((~0ULL << 1) << (f->bits_per_field[i] - 1))
+                               : 0;
+                       u64 field_offset = le64_to_cpu(f->field_offset[i]);
+
+                       if (packed_max + field_offset < packed_max ||
+                           packed_max + field_offset > unpacked_max) {
+                               prt_printf(err, "field %u too large: %llu + %llu > %llu",
+                                          i, packed_max, field_offset, unpacked_max);
+                               return -BCH_ERR_invalid;
+                       }
+               }
 
                bits += f->bits_per_field[i];
        }
 
-       if (f->key_u64s != DIV_ROUND_UP(bits, 64))
-               return "incorrect key_u64s";
+       if (f->key_u64s != DIV_ROUND_UP(bits, 64)) {
+               prt_printf(err, "incorrect key_u64s: got %u, should be %u",
+                          f->key_u64s, DIV_ROUND_UP(bits, 64));
+               return -BCH_ERR_invalid;
+       }
 
-       return NULL;
+       return 0;
+}
+
+void bch2_bkey_format_to_text(struct printbuf *out, const struct bkey_format *f)
+{
+       prt_printf(out, "u64s %u fields ", f->key_u64s);
+
+       for (unsigned i = 0; i < ARRAY_SIZE(f->bits_per_field); i++) {
+               if (i)
+                       prt_str(out, ", ");
+               prt_printf(out, "%u:%llu",
+                          f->bits_per_field[i],
+                          le64_to_cpu(f->field_offset[i]));
+       }
 }
 
 /*
@@ -759,7 +781,7 @@ unsigned bch2_bkey_ffs(const struct btree *b, const struct bkey_packed *k)
        return 0;
 }
 
-#ifdef CONFIG_X86_64
+#ifdef HAVE_BCACHEFS_COMPILED_UNPACK
 
 #define I(_x)                  (*(out)++ = (_x))
 #define I1(i0)                                         I(i0)