]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - cmd_migrate.c
Improved the show-super group and target printing
[bcachefs-tools-debian] / cmd_migrate.c
index 1c449554b3cb29feb8d53846efca988b4b55c412..9523dbdd16d78f6fd0ec1feff7cb649599419cbe 100644 (file)
 #include <linux/generic-radix-tree.h>
 #include <linux/xattr.h>
 #include "libbcachefs/bcachefs.h"
+#include "libbcachefs/alloc_background.h"
+#include "libbcachefs/alloc_foreground.h"
 #include "libbcachefs/btree_update.h"
 #include "libbcachefs/buckets.h"
 #include "libbcachefs/dirent.h"
 #include "libbcachefs/fs.h"
 #include "libbcachefs/inode.h"
 #include "libbcachefs/io.h"
+#include "libbcachefs/replicas.h"
 #include "libbcachefs/str_hash.h"
 #include "libbcachefs/super.h"
 #include "libbcachefs/xattr.h"
@@ -58,7 +61,7 @@ static char *dev_t_to_path(dev_t dev)
        return mprintf("/dev/%s", p);
 }
 
-static bool path_is_fs_root(char *path)
+static bool path_is_fs_root(const char *path)
 {
        char *line = NULL, *p, *mount;
        size_t n = 0;
@@ -119,7 +122,8 @@ static void update_inode(struct bch_fs *c,
        int ret;
 
        bch2_inode_pack(&packed, inode);
-       ret = bch2_btree_update(c, BTREE_ID_INODES, &packed.inode.k_i, NULL);
+       ret = bch2_btree_insert(c, BTREE_ID_INODES, &packed.inode.k_i,
+                               NULL, NULL, 0);
        if (ret)
                die("error creating file: %s", strerror(-ret));
 }
@@ -237,19 +241,24 @@ static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst,
 
                const struct xattr_handler *h = xattr_resolve_name(&attr);
 
-               int ret = __bch2_xattr_set(c, dst->bi_inum, &hash_info, attr,
-                                          val, val_size, 0, h->flags, NULL);
+               int ret = bch2_trans_do(c, NULL, BTREE_INSERT_ATOMIC,
+                               bch2_xattr_set(&trans, dst->bi_inum, &hash_info, attr,
+                                              val, val_size, h->flags, 0));
                if (ret < 0)
                        die("error creating xattr: %s", strerror(-ret));
        }
 }
 
+static char buf[1 << 20] __aligned(PAGE_SIZE);
+
 static void write_data(struct bch_fs *c,
                       struct bch_inode_unpacked *dst_inode,
                       u64 dst_offset, void *buf, size_t len)
 {
-       struct bch_write_op op;
-       struct bio_vec bv;
+       struct {
+               struct bch_write_op op;
+               struct bio_vec bv[sizeof(buf) / PAGE_SIZE];
+       } o;
        struct closure cl;
 
        BUG_ON(dst_offset       & (block_bytes(c) - 1));
@@ -257,36 +266,38 @@ static void write_data(struct bch_fs *c,
 
        closure_init_stack(&cl);
 
-       bio_init(&op.wbio.bio, &bv, 1);
-       op.wbio.bio.bi_iter.bi_size = len;
-       bch2_bio_map(&op.wbio.bio, buf);
+       bio_init(&o.op.wbio.bio, o.bv, ARRAY_SIZE(o.bv));
+       o.op.wbio.bio.bi_iter.bi_size = len;
+       bch2_bio_map(&o.op.wbio.bio, buf);
 
-       bch2_write_op_init(&op, c);
+       bch2_write_op_init(&o.op, c, bch2_opts_to_inode_opts(c->opts));
+       o.op.write_point        = writepoint_hashed(0);
+       o.op.nr_replicas        = 1;
+       o.op.pos                = POS(dst_inode->bi_inum, dst_offset >> 9);
 
-       op.write_point  = writepoint_hashed(0);
-       op.pos          = POS(dst_inode->bi_inum, dst_offset >> 9);
-
-       int ret = bch2_disk_reservation_get(c, &op.res, len >> 9, 0);
+       int ret = bch2_disk_reservation_get(c, &o.op.res, len >> 9,
+                                           c->opts.data_replicas, 0);
        if (ret)
                die("error reserving space in new filesystem: %s", strerror(-ret));
 
-       closure_call(&op.cl, bch2_write, NULL, &cl);
+       closure_call(&o.op.cl, bch2_write, NULL, &cl);
        closure_sync(&cl);
 
        dst_inode->bi_sectors += len >> 9;
 }
 
-static char buf[1 << 20] __aligned(PAGE_SIZE);
-
 static void copy_data(struct bch_fs *c,
                      struct bch_inode_unpacked *dst_inode,
                      int src_fd, u64 start, u64 end)
 {
        while (start < end) {
                unsigned len = min_t(u64, end - start, sizeof(buf));
+               unsigned pad = round_up(len, block_bytes(c)) - len;
 
                xpread(src_fd, buf, len, start);
-               write_data(c, dst_inode, start, buf, len);
+               memset(buf + len, 0, pad);
+
+               write_data(c, dst_inode, start, buf, len + pad);
                start += len;
        }
 }
@@ -309,7 +320,7 @@ static void link_data(struct bch_fs *c, struct bch_inode_unpacked *dst,
        while (length) {
                struct bkey_i_extent *e;
                BKEY_PADDED(k) k;
-               u64 b = sector_to_bucket(ca, physical >> 9);
+               u64 b = sector_to_bucket(ca, physical);
                struct disk_reservation res;
                unsigned sectors;
                int ret;
@@ -328,17 +339,19 @@ static void link_data(struct bch_fs *c, struct bch_inode_unpacked *dst,
                                        .gen = bucket(ca, b)->mark.gen,
                                  });
 
-               ret = bch2_disk_reservation_get(c, &res, sectors,
+               set_bit(b, ca->buckets_dirty);
+
+               ret = bch2_disk_reservation_get(c, &res, sectors, 1,
                                                BCH_DISK_RESERVATION_NOFAIL);
                if (ret)
                        die("error reserving space in new filesystem: %s",
                            strerror(-ret));
 
-               bch2_check_mark_super(c, BCH_DATA_USER,
-                                     bch2_bkey_devs(extent_i_to_s_c(e).s_c));
+               bch2_mark_bkey_replicas(c, BCH_DATA_USER,
+                                       extent_i_to_s_c(e).s_c);
 
                ret = bch2_btree_insert(c, BTREE_ID_EXTENTS, &e->k_i,
-                                       &res, NULL, NULL, 0);
+                                       &res, NULL, 0);
                if (ret)
                        die("btree insert error %s", strerror(-ret));
 
@@ -362,18 +375,19 @@ static void copy_link(struct bch_fs *c, struct bch_inode_unpacked *dst,
 }
 
 static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst,
-                     int src, char *src_path, ranges *extents)
+                     int src_fd, u64 src_size,
+                     char *src_path, ranges *extents)
 {
        struct fiemap_iter iter;
        struct fiemap_extent e;
 
-       fiemap_for_each(src, iter, e)
+       fiemap_for_each(src_fd, iter, e)
                if (e.fe_flags & FIEMAP_EXTENT_UNKNOWN) {
-                       fsync(src);
+                       fsync(src_fd);
                        break;
                }
 
-       fiemap_for_each(src, iter, e) {
+       fiemap_for_each(src_fd, iter, e) {
                if ((e.fe_logical       & (block_bytes(c) - 1)) ||
                    (e.fe_length        & (block_bytes(c) - 1)))
                        die("Unaligned extent in %s - can't handle", src_path);
@@ -382,20 +396,20 @@ static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst,
                                  FIEMAP_EXTENT_ENCODED|
                                  FIEMAP_EXTENT_NOT_ALIGNED|
                                  FIEMAP_EXTENT_DATA_INLINE)) {
-                       copy_data(c, dst,
-                                 src,
-                                 round_down(e.fe_logical, block_bytes(c)),
-                                 round_up(e.fe_logical + e.fe_length,
-                                          block_bytes(c)));
+                       copy_data(c, dst, src_fd, e.fe_logical,
+                                 min(src_size - e.fe_logical,
+                                     e.fe_length));
                        continue;
                }
 
+               /*
+                * if the data is below 1 MB, copy it so it doesn't conflict
+                * with bcachefs's potentially larger superblock:
+                */
                if (e.fe_physical < 1 << 20) {
-                       copy_data(c, dst,
-                                 src,
-                                 round_down(e.fe_logical, block_bytes(c)),
-                                 round_up(e.fe_logical + e.fe_length,
-                                          block_bytes(c)));
+                       copy_data(c, dst, src_fd, e.fe_logical,
+                                 min(src_size - e.fe_logical,
+                                     e.fe_length));
                        continue;
                }
 
@@ -474,7 +488,8 @@ static void copy_dir(struct copy_fs_state *s,
                        inode.bi_size = stat.st_size;
 
                        fd = xopen(d->d_name, O_RDONLY|O_NOATIME);
-                       copy_file(c, &inode, fd, child_path, &s->extents);
+                       copy_file(c, &inode, fd, stat.st_size,
+                                 child_path, &s->extents);
                        close(fd);
                        break;
                case DT_LNK:
@@ -601,6 +616,8 @@ static void copy_fs(struct bch_fs *c, int src_fd, const char *src_path,
 
        darray_free(s.extents);
        genradix_free(&s.hardlinks);
+
+       bch2_alloc_write(c);
 }
 
 static void find_superblock_space(ranges extents, struct dev_opts *dev)
@@ -643,37 +660,10 @@ static const struct option migrate_opts[] = {
        { NULL }
 };
 
-int cmd_migrate(int argc, char *argv[])
+static int migrate_fs(const char *fs_path,
+                     struct format_opts format_opts,
+                     bool force)
 {
-       struct format_opts format_opts = format_opts_default();
-       char *fs_path = NULL;
-       unsigned block_size;
-       bool no_passphrase = false, force = false;
-       int opt;
-
-       while ((opt = getopt_long(argc, argv, "f:Fh",
-                                 migrate_opts, NULL)) != -1)
-               switch (opt) {
-               case 'f':
-                       fs_path = optarg;
-                       break;
-               case 'e':
-                       format_opts.encrypted = true;
-                       break;
-               case 'p':
-                       no_passphrase = true;
-                       break;
-               case 'F':
-                       force = true;
-                       break;
-               case 'h':
-                       migrate_usage();
-                       exit(EXIT_SUCCESS);
-               }
-
-       if (!fs_path)
-               die("Please specify a filesytem to migrate");
-
        if (!path_is_fs_root(fs_path))
                die("%s is not a filysestem root", fs_path);
 
@@ -688,26 +678,24 @@ int cmd_migrate(int argc, char *argv[])
        dev.path = dev_t_to_path(stat.st_dev);
        dev.fd = xopen(dev.path, O_RDWR);
 
-       block_size = min_t(unsigned, stat.st_blksize,
-                          get_blocksize(dev.path, dev.fd) << 9);
-
+       unsigned block_size = get_blocksize(dev.path, dev.fd) << 9;
        BUG_ON(!is_power_of_2(block_size) || block_size < 512);
        format_opts.block_size = block_size >> 9;
 
-       u64 bcachefs_inum;
        char *file_path = mprintf("%s/bcachefs", fs_path);
+       printf("Creating new filesystem on %s in space reserved at %s\n",
+              dev.path, file_path);
 
        bch2_pick_bucket_size(format_opts, &dev);
 
+       u64 bcachefs_inum;
        ranges extents = reserve_new_fs_space(file_path,
-                               block_size, get_size(dev.path, dev.fd) / 5,
+                               format_opts.block_size << 9,
+                               get_size(dev.path, dev.fd) / 5,
                                &bcachefs_inum, stat.st_dev, force);
 
        find_superblock_space(extents, &dev);
 
-       if (format_opts.encrypted && !no_passphrase)
-               format_opts.passphrase = read_passphrase_twice("Enter passphrase: ");
-
        struct bch_sb *sb = bch2_format(format_opts, &dev, 1);
        u64 sb_offset = le64_to_cpu(sb->layout.sb_offset[0]);
 
@@ -716,22 +704,6 @@ int cmd_migrate(int argc, char *argv[])
 
        free(sb);
 
-       printf("Creating new filesystem on %s in space reserved at %s\n"
-              "To mount, run\n"
-              "  mount -t bcachefs -o sb=%llu %s dir\n"
-              "\n"
-              "After verifying that the new filesystem is correct, to create a\n"
-              "superblock at the default offset and finish the migration run\n"
-              "  bcachefs migrate_superblock -d %s -o %llu\n"
-              "\n"
-              "The new filesystem will have a file at /old_migrated_filestem\n"
-              "referencing all disk space that might be used by the existing\n"
-              "filesystem. That file can be deleted once the old filesystem is\n"
-              "no longer needed (and should be deleted prior to running\n"
-              "bcachefs migrate_superblock)\n",
-              dev.path, file_path, sb_offset, dev.path,
-              dev.path, sb_offset);
-
        struct bch_opts opts = bch2_opts_empty();
        struct bch_fs *c = NULL;
        char *path[1] = { dev.path };
@@ -764,13 +736,63 @@ int cmd_migrate(int argc, char *argv[])
 
        bch2_fs_stop(c);
        printf("fsck complete\n");
+
+       printf("To mount the new filesystem, run\n"
+              "  mount -t bcachefs -o sb=%llu %s dir\n"
+              "\n"
+              "After verifying that the new filesystem is correct, to create a\n"
+              "superblock at the default offset and finish the migration run\n"
+              "  bcachefs migrate-superblock -d %s -o %llu\n"
+              "\n"
+              "The new filesystem will have a file at /old_migrated_filestem\n"
+              "referencing all disk space that might be used by the existing\n"
+              "filesystem. That file can be deleted once the old filesystem is\n"
+              "no longer needed (and should be deleted prior to running\n"
+              "bcachefs migrate-superblock)\n",
+              sb_offset, dev.path, dev.path, sb_offset);
        return 0;
 }
 
+int cmd_migrate(int argc, char *argv[])
+{
+       struct format_opts format_opts = format_opts_default();
+       char *fs_path = NULL;
+       bool no_passphrase = false, force = false;
+       int opt;
+
+       while ((opt = getopt_long(argc, argv, "f:Fh",
+                                 migrate_opts, NULL)) != -1)
+               switch (opt) {
+               case 'f':
+                       fs_path = optarg;
+                       break;
+               case 'e':
+                       format_opts.encrypted = true;
+                       break;
+               case 'p':
+                       no_passphrase = true;
+                       break;
+               case 'F':
+                       force = true;
+                       break;
+               case 'h':
+                       migrate_usage();
+                       exit(EXIT_SUCCESS);
+               }
+
+       if (!fs_path)
+               die("Please specify a filesytem to migrate");
+
+       if (format_opts.encrypted && !no_passphrase)
+               format_opts.passphrase = read_passphrase_twice("Enter passphrase: ");
+
+       return migrate_fs(fs_path, format_opts, force);
+}
+
 static void migrate_superblock_usage(void)
 {
-       puts("bcachefs migrate_superblock - create default superblock after migrating\n"
-            "Usage: bcachefs migrate_superblock [OPTION]...\n"
+       puts("bcachefs migrate-superblock - create default superblock after migrating\n"
+            "Usage: bcachefs migrate-superblock [OPTION]...\n"
             "\n"
             "Options:\n"
             "  -d device     Device to create superblock for\n"