]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/super-io.c
Update bcachefs sources to 91e6c3e0d5 bcachefs: Gap buffer for journal keys
[bcachefs-tools-debian] / libbcachefs / super-io.c
index e17ce91c8486fac640f321d583fd8df8e03b4e1a..15241a56f2036a91cdfa38f6e57178d8b5bfb643 100644 (file)
@@ -10,6 +10,7 @@
 #include "io.h"
 #include "journal.h"
 #include "journal_io.h"
+#include "journal_sb.h"
 #include "journal_seq_blacklist.h"
 #include "replicas.h"
 #include "quota.h"
@@ -20,6 +21,8 @@
 #include <linux/backing-dev.h>
 #include <linux/sort.h>
 
+#include <trace/events/bcachefs.h>
+
 const char * const bch2_sb_fields[] = {
 #define x(name, nr)    #name,
        BCH_SB_FIELDS()
@@ -247,17 +250,19 @@ static int validate_sb_layout(struct bch_sb_layout *layout, struct printbuf *out
        return 0;
 }
 
-static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out)
+static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out,
+                           int rw)
 {
        struct bch_sb *sb = disk_sb->sb;
        struct bch_sb_field *f;
        struct bch_sb_field_members *mi;
+       enum bch_opt_id opt_id;
        u32 version, version_min;
        u16 block_size;
        int ret;
 
        version         = le16_to_cpu(sb->version);
-       version_min     = version >= bcachefs_metadata_version_new_versioning
+       version_min     = version >= bcachefs_metadata_version_bkey_renumber
                ? le16_to_cpu(sb->version_min)
                : version;
 
@@ -323,6 +328,33 @@ static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out)
                return -EINVAL;
        }
 
+       if (rw == READ) {
+               /*
+                * Been seeing a bug where these are getting inexplicably
+                * zeroed, so we'r now validating them, but we have to be
+                * careful not to preven people's filesystems from mounting:
+                */
+               if (!BCH_SB_JOURNAL_FLUSH_DELAY(sb))
+                       SET_BCH_SB_JOURNAL_FLUSH_DELAY(sb, 1000);
+               if (!BCH_SB_JOURNAL_RECLAIM_DELAY(sb))
+                       SET_BCH_SB_JOURNAL_RECLAIM_DELAY(sb, 1000);
+       }
+
+       for (opt_id = 0; opt_id < bch2_opts_nr; opt_id++) {
+               const struct bch_option *opt = bch2_opt_table + opt_id;
+
+               if (opt->get_sb != BCH2_NO_SB_OPT) {
+                       u64 v = bch2_opt_from_sb(sb, opt_id);
+
+                       pr_buf(out, "Invalid option ");
+                       ret = bch2_opt_validate(opt, v, out);
+                       if (ret)
+                               return ret;
+
+                       printbuf_reset(out);
+               }
+       }
+
        /* validate layout */
        ret = validate_sb_layout(&sb->layout, out);
        if (ret)
@@ -424,7 +456,7 @@ static void __copy_super(struct bch_sb_handle *dst_handle, struct bch_sb *src)
        memcpy(dst->compat,     src->compat,    sizeof(dst->compat));
 
        for (i = 0; i < BCH_SB_FIELD_NR; i++) {
-               if (i == BCH_SB_FIELD_journal)
+               if ((1U << i) & BCH_SINGLE_DEVICE_SB_FIELDS)
                        continue;
 
                src_f = bch2_sb_field_get(src, i);
@@ -513,7 +545,7 @@ reread:
        }
 
        version         = le16_to_cpu(sb->sb->version);
-       version_min     = version >= bcachefs_metadata_version_new_versioning
+       version_min     = version >= bcachefs_metadata_version_bkey_renumber
                ? le16_to_cpu(sb->sb->version_min)
                : version;
 
@@ -674,7 +706,7 @@ got_super:
        ret = 0;
        sb->have_layout = true;
 
-       ret = bch2_sb_validate(sb, &err);
+       ret = bch2_sb_validate(sb, &err, READ);
        if (ret) {
                printk(KERN_ERR "bcachefs (%s): error validating superblock: %s",
                       path, err.buf);
@@ -767,6 +799,8 @@ int bch2_write_super(struct bch_fs *c)
        unsigned degraded_flags = BCH_FORCE_IF_DEGRADED;
        int ret = 0;
 
+       trace_write_super(c, _RET_IP_);
+
        if (c->opts.very_degraded)
                degraded_flags |= BCH_FORCE_IF_LOST;
 
@@ -790,7 +824,7 @@ int bch2_write_super(struct bch_fs *c)
        for_each_online_member(ca, c, i) {
                printbuf_reset(&err);
 
-               ret = bch2_sb_validate(&ca->disk_sb, &err);
+               ret = bch2_sb_validate(&ca->disk_sb, &err, WRITE);
                if (ret) {
                        bch2_fs_inconsistent(c, "sb invalid before write: %s", err.buf);
                        percpu_ref_put(&ca->io_ref);
@@ -801,6 +835,13 @@ int bch2_write_super(struct bch_fs *c)
        if (c->opts.nochanges)
                goto out;
 
+       /*
+        * Defer writing the superblock until filesystem initialization is
+        * complete - don't write out a partly initialized superblock:
+        */
+       if (!BCH_SB_INITIALIZED(c->disk_sb.sb))
+               goto out;
+
        for_each_online_member(ca, c, i) {
                __set_bit(ca->dev_idx, sb_written.d);
                ca->sb_write_error = 0;
@@ -898,85 +939,6 @@ void __bch2_check_set_feature(struct bch_fs *c, unsigned feat)
        mutex_unlock(&c->sb_lock);
 }
 
-/* BCH_SB_FIELD_journal: */
-
-static int u64_cmp(const void *_l, const void *_r)
-{
-       u64 l = *((const u64 *) _l), r = *((const u64 *) _r);
-
-       return l < r ? -1 : l > r ? 1 : 0;
-}
-
-static int bch2_sb_journal_validate(struct bch_sb *sb,
-                                   struct bch_sb_field *f,
-                                   struct printbuf *err)
-{
-       struct bch_sb_field_journal *journal = field_to_type(f, journal);
-       struct bch_member *m = bch2_sb_get_members(sb)->members + sb->dev_idx;
-       int ret = -EINVAL;
-       unsigned nr;
-       unsigned i;
-       u64 *b;
-
-       nr = bch2_nr_journal_buckets(journal);
-       if (!nr)
-               return 0;
-
-       b = kmalloc_array(sizeof(u64), nr, GFP_KERNEL);
-       if (!b)
-               return -ENOMEM;
-
-       for (i = 0; i < nr; i++)
-               b[i] = le64_to_cpu(journal->buckets[i]);
-
-       sort(b, nr, sizeof(u64), u64_cmp, NULL);
-
-       if (!b[0]) {
-               pr_buf(err, "journal bucket at sector 0");
-               goto err;
-       }
-
-       if (b[0] < le16_to_cpu(m->first_bucket)) {
-               pr_buf(err, "journal bucket %llu before first bucket %u",
-                      b[0], le16_to_cpu(m->first_bucket));
-               goto err;
-       }
-
-       if (b[nr - 1] >= le64_to_cpu(m->nbuckets)) {
-               pr_buf(err, "journal bucket %llu past end of device (nbuckets %llu)",
-                      b[nr - 1], le64_to_cpu(m->nbuckets));
-               goto err;
-       }
-
-       for (i = 0; i + 1 < nr; i++)
-               if (b[i] == b[i + 1]) {
-                       pr_buf(err, "duplicate journal buckets %llu", b[i]);
-                       goto err;
-               }
-
-       ret = 0;
-err:
-       kfree(b);
-       return ret;
-}
-
-static void bch2_sb_journal_to_text(struct printbuf *out, struct bch_sb *sb,
-                                   struct bch_sb_field *f)
-{
-       struct bch_sb_field_journal *journal = field_to_type(f, journal);
-       unsigned i, nr = bch2_nr_journal_buckets(journal);
-
-       pr_buf(out, "Buckets: ");
-       for (i = 0; i < nr; i++)
-               pr_buf(out, " %llu", le64_to_cpu(journal->buckets[i]));
-       pr_newline(out);
-}
-
-static const struct bch_sb_field_ops bch_sb_field_ops_journal = {
-       .validate       = bch2_sb_journal_validate,
-       .to_text        = bch2_sb_journal_to_text,
-};
-
 /* BCH_SB_FIELD_members: */
 
 static int bch2_sb_members_validate(struct bch_sb *sb,
@@ -1130,6 +1092,11 @@ static void bch2_sb_members_to_text(struct printbuf *out, struct bch_sb *sb,
                pr_buf(out, "%llu", BCH_MEMBER_DISCARD(m));
                pr_newline(out);
 
+               pr_buf(out, "Freespace initialized:");
+               pr_tab(out);
+               pr_buf(out, "%llu", BCH_MEMBER_FREESPACE_INITIALIZED(m));
+               pr_newline(out);
+
                pr_indent_pop(out, 2);
        }
 }
@@ -1549,12 +1516,12 @@ void bch2_sb_to_text(struct printbuf *out, struct bch_sb *sb,
 
        pr_buf(out, "Version:");
        pr_tab(out);
-       pr_buf(out, "%u", le16_to_cpu(sb->version));
+       pr_buf(out, "%s", bch2_metadata_versions[le16_to_cpu(sb->version)]);
        pr_newline(out);
 
        pr_buf(out, "Oldest version on disk:");
        pr_tab(out);
-       pr_buf(out, "%u", le16_to_cpu(sb->version_min));
+       pr_buf(out, "%s", bch2_metadata_versions[le16_to_cpu(sb->version_min)]);
        pr_newline(out);
 
        pr_buf(out, "Created:");