bcachefs: Cached pointers should not be erasure coded
authorKent Overstreet <kent.overstreet@linux.dev>
Wed, 22 Feb 2023 00:22:44 +0000 (19:22 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:54 +0000 (17:09 -0400)
There's no reason to erasure code cached pointers: we'll always have
another copy, and it'll be cheaper to read the other copy than do a
reconstruct read. And erasure coded cached pointers would add
complications that we'd rather not have to deal with, so let's make sure
to disallow them.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/data_update.c
fs/bcachefs/extents.c
fs/bcachefs/extents.h

index c3adc7b32e19ace54344a67a8b8f35d1b50602c9..c98a393f49168ddd9ed6216ad97f94bec50d1a80 100644 (file)
@@ -97,8 +97,10 @@ static void bch2_bkey_mark_dev_cached(struct bkey_s k, unsigned dev)
        struct bch_extent_ptr *ptr;
 
        bkey_for_each_ptr(ptrs, ptr)
-               if (ptr->dev == dev)
-                       ptr->cached = true;
+               if (ptr->dev == dev) {
+                       bch2_extent_ptr_set_cached(k, ptr);
+                       return;
+               }
 }
 
 static int __bch2_data_update_index_update(struct btree_trans *trans,
index 4b865949768f5f6b9649f42645e1336805192ad9..2e41545dc1e9574b673cd7c81451481b63fb38a3 100644 (file)
@@ -950,6 +950,29 @@ bool bch2_extent_has_ptr(struct bkey_s_c k1, struct extent_ptr_decoded p1,
        return false;
 }
 
+void bch2_extent_ptr_set_cached(struct bkey_s k, struct bch_extent_ptr *ptr)
+{
+       struct bkey_ptrs ptrs = bch2_bkey_ptrs(k);
+       union bch_extent_entry *entry;
+       union bch_extent_entry *ec = NULL;
+
+       bkey_extent_entry_for_each(ptrs, entry) {
+               if (&entry->ptr == ptr) {
+                       ptr->cached = true;
+                       if (ec)
+                               extent_entry_drop(k, ec);
+                       return;
+               }
+
+               if (extent_entry_is_stripe_ptr(entry))
+                       ec = entry;
+               else if (extent_entry_is_ptr(entry))
+                       ec = NULL;
+       }
+
+       BUG();
+}
+
 /*
  * bch_extent_normalize - clean up an extent, dropping stale pointers etc.
  *
@@ -1093,7 +1116,7 @@ int bch2_bkey_ptrs_invalid(const struct bch_fs *c, struct bkey_s_c k,
        unsigned size_ondisk = k.k->size;
        unsigned nonce = UINT_MAX;
        unsigned nr_ptrs = 0;
-       bool unwritten = false;
+       bool unwritten = false, have_ec = false;
        int ret;
 
        if (bkey_is_btree_ptr(k.k))
@@ -1129,7 +1152,13 @@ int bch2_bkey_ptrs_invalid(const struct bch_fs *c, struct bkey_s_c k,
                                return -BCH_ERR_invalid_bkey;
                        }
 
+                       if (entry->ptr.cached && have_ec) {
+                               prt_printf(err, "cached, erasure coded ptr");
+                               return -BCH_ERR_invalid_bkey;
+                       }
+
                        unwritten = entry->ptr.unwritten;
+                       have_ec = false;
                        nr_ptrs++;
                        break;
                case BCH_EXTENT_ENTRY_crc32:
@@ -1165,6 +1194,7 @@ int bch2_bkey_ptrs_invalid(const struct bch_fs *c, struct bkey_s_c k,
                        }
                        break;
                case BCH_EXTENT_ENTRY_stripe_ptr:
+                       have_ec = true;
                        break;
                }
        }
index 1d8f3b309b074ba40394e2fd954744a658b4336f..c52a098328572b5170cd578b9392366faadf35a8 100644 (file)
@@ -655,6 +655,8 @@ bool bch2_bkey_matches_ptr(struct bch_fs *, struct bkey_s_c,
 bool bch2_extents_match(struct bkey_s_c, struct bkey_s_c);
 bool bch2_extent_has_ptr(struct bkey_s_c, struct extent_ptr_decoded, struct bkey_s_c);
 
+void bch2_extent_ptr_set_cached(struct bkey_s, struct bch_extent_ptr *);
+
 bool bch2_extent_normalize(struct bch_fs *, struct bkey_s);
 void bch2_bkey_ptrs_to_text(struct printbuf *, struct bch_fs *,
                            struct bkey_s_c);