summaryrefslogtreecommitdiff
path: root/c_src/cmd_migrate.c
diff options
context:
space:
mode:
Diffstat (limited to 'c_src/cmd_migrate.c')
-rw-r--r--c_src/cmd_migrate.c116
1 files changed, 76 insertions, 40 deletions
diff --git a/c_src/cmd_migrate.c b/c_src/cmd_migrate.c
index aa17a160..4e4fbcba 100644
--- a/c_src/cmd_migrate.c
+++ b/c_src/cmd_migrate.c
@@ -86,6 +86,15 @@ found:
return ret;
}
+static void mark_nouse_range(struct bch_dev *ca, u64 sector_from, u64 sector_to)
+{
+ u64 b = sector_to_bucket(ca, sector_from);
+ do {
+ set_bit(b, ca->buckets_nouse);
+ b++;
+ } while (bucket_to_sector(ca, b) < sector_to);
+}
+
static void mark_unreserved_space(struct bch_fs *c, ranges extents)
{
struct bch_dev *ca = c->devs[0];
@@ -93,17 +102,16 @@ static void mark_unreserved_space(struct bch_fs *c, ranges extents)
struct range i;
for_each_hole(iter, extents, bucket_to_sector(ca, ca->mi.nbuckets) << 9, i) {
- u64 b;
-
if (i.start == i.end)
return;
- b = sector_to_bucket(ca, i.start >> 9);
- do {
- set_bit(b, ca->buckets_nouse);
- b++;
- } while (bucket_to_sector(ca, b) << 9 < i.end);
+ mark_nouse_range(ca, i.start >> 9,
+ round_up(i.end, 1 << 9) >> 9);
}
+
+ /* Also be sure to mark the space for the default sb layout */
+ unsigned sb_size = 1U << ca->disk_sb.sb->layout.sb_max_size_bits;
+ mark_nouse_range(ca, 0, BCH_SB_SECTOR + sb_size * 2);
}
static ranges reserve_new_fs_space(const char *file_path, unsigned block_size,
@@ -279,7 +287,7 @@ static int migrate_fs(const char *fs_path,
.dev = stat.st_dev,
.extents = extents,
.type = BCH_MIGRATE_migrate,
- .reserve_start = roundup((format_opts.superblock_size * 2 + 8) << 9,
+ .reserve_start = roundup((format_opts.superblock_size * 2 + BCH_SB_SECTOR) << 9,
bucket_bytes(c->devs[0])),
};
@@ -381,6 +389,28 @@ static void migrate_superblock_usage(void)
"Report bugs to <linux-bcachefs@vger.kernel.org>");
}
+static void add_default_sb_layout(struct bch_sb* sb, unsigned *out_sb_size)
+{
+ unsigned sb_size = 1U << sb->layout.sb_max_size_bits;
+ if (out_sb_size)
+ *out_sb_size = sb_size;
+
+ if (sb->layout.nr_superblocks >= ARRAY_SIZE(sb->layout.sb_offset))
+ die("Can't add superblock: no space left in superblock layout");
+
+ for (unsigned i = 0; i < sb->layout.nr_superblocks; i++)
+ if (le64_to_cpu(sb->layout.sb_offset[i]) == BCH_SB_SECTOR ||
+ le64_to_cpu(sb->layout.sb_offset[i]) == BCH_SB_SECTOR + sb_size)
+ die("Superblock layout already has default superblocks");
+
+ memmove(&sb->layout.sb_offset[2],
+ &sb->layout.sb_offset[0],
+ sb->layout.nr_superblocks * sizeof(u64));
+ sb->layout.nr_superblocks += 2;
+ sb->layout.sb_offset[0] = cpu_to_le64(BCH_SB_SECTOR);
+ sb->layout.sb_offset[1] = cpu_to_le64(BCH_SB_SECTOR + sb_size);
+}
+
int cmd_migrate_superblock(int argc, char *argv[])
{
static const struct option longopts[] = {
@@ -414,34 +444,23 @@ int cmd_migrate_superblock(int argc, char *argv[])
if (!sb_offset)
die("Please specify offset of existing superblock");
- int fd = xopen(devs.data[0], O_RDWR);
+ int fd = xopen(devs.data[0], O_RDWR | O_EXCL);
struct bch_sb *sb = __bch2_super_read(fd, sb_offset);
- unsigned sb_size = 1U << sb->layout.sb_max_size_bits;
+ unsigned sb_size;
+ /* Check for invocation errors early */
+ add_default_sb_layout(sb, &sb_size);
- if (sb->layout.nr_superblocks >= ARRAY_SIZE(sb->layout.sb_offset))
- die("Can't add superblock: no space left in superblock layout");
-
- for (unsigned i = 0; i < sb->layout.nr_superblocks; i++)
- if (le64_to_cpu(sb->layout.sb_offset[i]) == BCH_SB_SECTOR ||
- le64_to_cpu(sb->layout.sb_offset[i]) == BCH_SB_SECTOR + sb_size)
- die("Superblock layout already has default superblocks");
-
- memmove(&sb->layout.sb_offset[2],
- &sb->layout.sb_offset[0],
- sb->layout.nr_superblocks * sizeof(u64));
- sb->layout.nr_superblocks += 2;
- sb->layout.sb_offset[0] = cpu_to_le64(BCH_SB_SECTOR);
- sb->layout.sb_offset[1] = cpu_to_le64(BCH_SB_SECTOR + sb_size);
+ /* Rewrite first 0-3.5k bytes with zeroes, ensuring we blow away
+ * the old superblock */
+ // TODO: fix the "Superblock write was silently dropped" warning properly
+ static const char zeroes[(BCH_SB_SECTOR << 9) + sizeof(struct bch_sb)];
+ xpwrite(fd, zeroes, ARRAY_SIZE(zeroes), 0, "zeroing start of disk");
- /* also write first 0-3.5k bytes with zeroes, ensure we blow away old
- * superblock */
- static const char zeroes[BCH_SB_SECTOR << 9];
- xpwrite(fd, zeroes, BCH_SB_SECTOR << 9, 0, "zeroing start of disk");
-
- bch2_super_write(fd, sb);
xclose(fd);
- /* mark new superblocks */
+ /* We start a normal FS instance with the sb buckets temporarily
+ * prohibited from allocation, performing any recovery/upgrade/downgrade
+ * as needed, and only then change the superblock layout */
struct bch_opts opts = bch2_opts_empty();
opt_set(opts, nostart, true);
@@ -454,29 +473,46 @@ int cmd_migrate_superblock(int argc, char *argv[])
die("error opening filesystem: %s", bch2_err_str(ret));
struct bch_dev *ca = c->devs[0];
- for (u64 b = 0; bucket_to_sector(ca, b) < BCH_SB_SECTOR + sb_size * 2; b++)
- set_bit(b, ca->buckets_nouse);
+ mark_nouse_range(ca, 0, BCH_SB_SECTOR + sb_size * 2);
ret = bch2_fs_start(c);
if (ret)
die("Error starting filesystem: %s", bch2_err_str(ret));
+ BUG_ON(1U << ca->disk_sb.sb->layout.sb_max_size_bits != sb_size);
+
+ /* Here the FS is already RW.
+ * Apply the superblock layout changes first, everything else can be
+ * repaired on a subsequent recovery */
+ add_default_sb_layout(ca->disk_sb.sb, NULL);
+ ret = bch2_write_super(c);
+ if (ret)
+ die("Error writing superblock: %s", bch2_err_str(ret));
+
+ /* Now explicitly mark the new sb buckets in FS metadata */
+ ret = bch2_trans_mark_dev_sb(c, ca, BTREE_TRIGGER_transactional);
+ if (ret)
+ die("Error marking superblock buckets: %s", bch2_err_str(ret));
+
bch2_fs_stop(c);
+#if CONFIG_BCACHEFS_DEBUG
+ /* Verify that filesystem is clean and consistent */
+
opts = bch2_opts_empty();
opt_set(opts, fsck, true);
opt_set(opts, fix_errors, true);
-
- /*
- * Hack: the free space counters are coming out wrong after marking the
- * new superblock, but it's just the device counters so it's
- * inconsequential:
- */
+ opt_set(opts, nochanges, true);
c = bch2_fs_open(&devs, &opts);
ret = PTR_ERR_OR_ZERO(c);
if (ret)
- die("error opening filesystem: %s", bch2_err_str(ret));
+ die("error checking filesystem: %s", bch2_err_str(ret));
+
+ if (test_bit(BCH_FS_errors, &c->flags) || test_bit(BCH_FS_errors_fixed, &c->flags))
+ die("Filesystem has errors after migration");
+
bch2_fs_stop(c);
+#endif
return 0;
}