bcachefs: bcachefs_metadata_version_extent_flags
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 25 Feb 2025 01:29:58 +0000 (20:29 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 15 Mar 2025 01:02:15 +0000 (21:02 -0400)
This implements a new extent field bitflags that apply to the whole
extent. There's been a couple things we've wanted this for in the past,
but the immediate need is extent poisoning, to solve a rebalance issue.

Unknown extent fields can't be parsed (we won't known their size, so we
can't advance to the next field), so this is an incompat feature, and
using it prevents the filesystem from being mounted by old versions.

This also adds the BCH_EXTENT_poisoned flag; this indicates that the
data is known to be bad (i.e. there was a checksum error, and we had to
write a new checksum) and reads will return errors.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bcachefs_format.h
fs/bcachefs/errcode.h
fs/bcachefs/extents.c
fs/bcachefs/extents.h
fs/bcachefs/extents_format.h
fs/bcachefs/sb-errors_format.h

index 8114ad9a3fe693f95ea07e6b79d04ea90ce4b400..a6cc817ccd87f62ae87b4cb560bbcaa8e23bfd20 100644 (file)
@@ -690,7 +690,8 @@ struct bch_sb_field_ext {
        x(cached_backpointers,          BCH_VERSION(1, 21))             \
        x(stripe_backpointers,          BCH_VERSION(1, 22))             \
        x(stripe_lru,                   BCH_VERSION(1, 23))             \
-       x(casefolding,                  BCH_VERSION(1, 24))
+       x(casefolding,                  BCH_VERSION(1, 24))             \
+       x(extent_flags,                 BCH_VERSION(1, 25))
 
 enum bcachefs_metadata_version {
        bcachefs_metadata_version_min = 9,
index 9e19bc37aa72cc215055a81d894e621c6543d2f3..0d9a8198e95ea0abaa8f895000d6d5ed9347677f 100644 (file)
        x(EIO,                          mark_stripe)                            \
        x(EIO,                          stripe_reconstruct)                     \
        x(EIO,                          key_type_error)                         \
+       x(EIO,                          extent_poisened)                        \
        x(EIO,                          no_device_to_read_from)                 \
        x(EIO,                          missing_indirect_extent)                \
        x(EIO,                          invalidate_stripe_to_dev)               \
index ec653109de5b05b2ac9b53efb01e95cee77afabe..d9bdf433c118ac0095891a734bdb8a69fcc17e04 100644 (file)
 #include "trace.h"
 #include "util.h"
 
+static const char * const bch2_extent_flags_strs[] = {
+#define x(n, v)        [BCH_EXTENT_FLAG_##n] = #n,
+       BCH_EXTENT_FLAGS()
+#undef x
+       NULL,
+};
+
 static unsigned bch2_crc_field_size_max[] = {
        [BCH_EXTENT_ENTRY_crc32] = CRC32_SIZE_MAX,
        [BCH_EXTENT_ENTRY_crc64] = CRC64_SIZE_MAX,
@@ -127,6 +134,9 @@ int bch2_bkey_pick_read_device(struct bch_fs *c, struct bkey_s_c k,
        if (k.k->type == KEY_TYPE_error)
                return -BCH_ERR_key_type_error;
 
+       if (bch2_bkey_extent_ptrs_flags(ptrs) & BIT_ULL(BCH_EXTENT_FLAG_poisoned))
+               return -BCH_ERR_extent_poisened;
+
        rcu_read_lock();
        bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
                /*
@@ -1225,6 +1235,10 @@ void bch2_bkey_ptrs_to_text(struct printbuf *out, struct bch_fs *c,
                        bch2_extent_rebalance_to_text(out, c, &entry->rebalance);
                        break;
 
+               case BCH_EXTENT_ENTRY_flags:
+                       prt_bitflags(out, bch2_extent_flags_strs, entry->flags.flags);
+                       break;
+
                default:
                        prt_printf(out, "(invalid extent entry %.16llx)", *((u64 *) entry));
                        return;
@@ -1386,6 +1400,11 @@ int bch2_bkey_ptrs_validate(struct bch_fs *c, struct bkey_s_c k,
 #endif
                        break;
                }
+               case BCH_EXTENT_ENTRY_flags:
+                       bkey_fsck_err_on(entry != ptrs.start,
+                                        c, extent_flags_not_at_start,
+                                        "extent flags entry not at start");
+                       break;
                }
        }
 
@@ -1452,6 +1471,28 @@ void bch2_ptr_swab(struct bkey_s k)
        }
 }
 
+int bch2_bkey_extent_flags_set(struct bch_fs *c, struct bkey_i *k, u64 flags)
+{
+       int ret = bch2_request_incompat_feature(c, bcachefs_metadata_version_extent_flags);
+       if (ret)
+               return ret;
+
+       struct bkey_ptrs ptrs = bch2_bkey_ptrs(bkey_i_to_s(k));
+
+       if (ptrs.start != ptrs.end &&
+           extent_entry_type(ptrs.start) == BCH_EXTENT_ENTRY_flags) {
+               ptrs.start->flags.flags = flags;
+       } else {
+               struct bch_extent_flags f = {
+                       .type   = BIT(BCH_EXTENT_ENTRY_flags),
+                       .flags  = flags,
+               };
+               __extent_entry_insert(k, ptrs.start, (union bch_extent_entry *) &f);
+       }
+
+       return 0;
+}
+
 /* Generic extent code: */
 
 int bch2_cut_front_s(struct bpos where, struct bkey_s k)
@@ -1497,8 +1538,8 @@ int bch2_cut_front_s(struct bpos where, struct bkey_s k)
                                entry->crc128.offset += sub;
                                break;
                        case BCH_EXTENT_ENTRY_stripe_ptr:
-                               break;
                        case BCH_EXTENT_ENTRY_rebalance:
+                       case BCH_EXTENT_ENTRY_flags:
                                break;
                        }
 
index ed160aaa9546a87e813e164804948edbcbdb7e08..c50c4f353bab2814d045d60ee4cf66da42bdd9ab 100644 (file)
@@ -753,4 +753,19 @@ static inline void bch2_key_resize(struct bkey *k, unsigned new_size)
        k->size = new_size;
 }
 
+static inline u64 bch2_bkey_extent_ptrs_flags(struct bkey_ptrs_c ptrs)
+{
+       if (ptrs.start != ptrs.end &&
+           extent_entry_type(ptrs.start) == BCH_EXTENT_ENTRY_flags)
+               return ptrs.start->flags.flags;
+       return 0;
+}
+
+static inline u64 bch2_bkey_extent_flags(struct bkey_s_c k)
+{
+       return bch2_bkey_extent_ptrs_flags(bch2_bkey_ptrs_c(k));
+}
+
+int bch2_bkey_extent_flags_set(struct bch_fs *, struct bkey_i *, u64);
+
 #endif /* _BCACHEFS_EXTENTS_H */
index c198dfc376d6c3f2c68b0f4aa273e0da4a8b1294..74c0252cbd984d9b901fee020f63c4c84314eb5d 100644 (file)
@@ -79,8 +79,9 @@
        x(crc64,                2)              \
        x(crc128,               3)              \
        x(stripe_ptr,           4)              \
-       x(rebalance,            5)
-#define BCH_EXTENT_ENTRY_MAX   6
+       x(rebalance,            5)              \
+       x(flags,                6)
+#define BCH_EXTENT_ENTRY_MAX   7
 
 enum bch_extent_entry_type {
 #define x(f, n) BCH_EXTENT_ENTRY_##f = n,
@@ -201,6 +202,25 @@ struct bch_extent_stripe_ptr {
 #endif
 };
 
+#define BCH_EXTENT_FLAGS()             \
+       x(poisoned,             0)
+
+enum bch_extent_flags_e {
+#define x(n, v)        BCH_EXTENT_FLAG_##n = v,
+       BCH_EXTENT_FLAGS()
+#undef x
+};
+
+struct bch_extent_flags {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u64                   type:7,
+                               flags:57;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+       __u64                   flags:57,
+                               type:7;
+#endif
+};
+
 /* bch_extent_rebalance: */
 #include "rebalance_format.h"
 
index cdafd877b8a1df9e1279f46431ba06c0e10bf511..67455beb8358a088ebfe9a49b508cee5d24d5fb3 100644 (file)
@@ -179,6 +179,7 @@ enum bch_fsck_flags {
        x(ptr_crc_redundant,                                    160,    0)              \
        x(ptr_crc_nonce_mismatch,                               162,    0)              \
        x(ptr_stripe_redundant,                                 163,    0)              \
+       x(extent_flags_not_at_start,                            306,    0)              \
        x(reservation_key_nr_replicas_invalid,                  164,    0)              \
        x(reflink_v_refcount_wrong,                             165,    FSCK_AUTOFIX)   \
        x(reflink_v_pos_bad,                                    292,    0)              \
@@ -316,7 +317,7 @@ enum bch_fsck_flags {
        x(directory_size_mismatch,                              303,    FSCK_AUTOFIX)   \
        x(dirent_cf_name_too_big,                               304,    0)              \
        x(dirent_stray_data_after_cf_name,                      305,    0)              \
-       x(MAX,                                                  306,    0)
+       x(MAX,                                                  307,    0)
 
 enum bch_sb_error_id {
 #define x(t, n, ...) BCH_FSCK_ERR_##t = n,