]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - cmd_migrate.c
Makefile, fsck: Use libexec instead of lib
[bcachefs-tools-debian] / cmd_migrate.c
index 5914e46d6fc8440b3f84b1bbe86dd8f95fd1bac3..07fc145290034ae9eed9706d86caada62c116202 100644 (file)
@@ -3,13 +3,13 @@
 #include <fcntl.h>
 #include <getopt.h>
 #include <string.h>
+#include <sys/xattr.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
 #include <sys/vfs.h>
 #include <unistd.h>
-#include <attr/xattr.h>
 
 #include <linux/fiemap.h>
 #include <linux/fs.h>
 #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/errcode.h"
+#include "libbcachefs/fs-common.h"
 #include "libbcachefs/inode.h"
-#include "libbcachefs/io.h"
+#include "libbcachefs/io_write.h"
+#include "libbcachefs/replicas.h"
 #include "libbcachefs/str_hash.h"
 #include "libbcachefs/super.h"
 #include "libbcachefs/xattr.h"
 
+/* XXX cut and pasted from fsck.c */
+#define QSTR(n) { { { .len = strlen(n) } }, .name = n }
+
 static char *dev_t_to_path(dev_t dev)
 {
        char link[PATH_MAX], *p;
@@ -97,7 +104,6 @@ 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) {
-               struct bucket_mark new;
                u64 b;
 
                if (i.start == i.end)
@@ -105,8 +111,7 @@ static void mark_unreserved_space(struct bch_fs *c, ranges extents)
 
                b = sector_to_bucket(ca, i.start >> 9);
                do {
-                       struct bucket *g = bucket(ca, b);
-                       bucket_cmpxchg(g, new, new.nouse = 1);
+                       set_bit(b, ca->buckets_nouse);
                        b++;
                } while (bucket_to_sector(ca, b) << 9 < i.end);
        }
@@ -119,42 +124,27 @@ static void update_inode(struct bch_fs *c,
        int ret;
 
        bch2_inode_pack(&packed, inode);
-       ret = bch2_btree_insert(c, BTREE_ID_INODES, &packed.inode.k_i,
-                               NULL, NULL, NULL, 0);
+       packed.inode.k.p.snapshot = U32_MAX;
+       ret = bch2_btree_insert(c, BTREE_ID_inodes, &packed.inode.k_i,
+                               NULL, 0);
        if (ret)
-               die("error creating file: %s", strerror(-ret));
-}
-
-static void create_dirent(struct bch_fs *c,
-                         struct bch_inode_unpacked *parent,
-                         const char *name, u64 inum, mode_t mode)
-{
-       struct bch_hash_info parent_hash_info = bch2_hash_info_init(c, parent);
-       struct qstr qname = { { { .len = strlen(name), } }, .name = name };
-
-       int ret = bch2_dirent_create(c, parent->bi_inum, &parent_hash_info,
-                                    mode_to_type(mode), &qname,
-                                    inum, NULL, BCH_HASH_SET_MUST_CREATE);
-       if (ret)
-               die("error creating file: %s", strerror(-ret));
-
-       if (S_ISDIR(mode))
-               parent->bi_nlink++;
+               die("error updating inode: %s", bch2_err_str(ret));
 }
 
 static void create_link(struct bch_fs *c,
                        struct bch_inode_unpacked *parent,
                        const char *name, u64 inum, mode_t mode)
 {
+       struct qstr qstr = QSTR(name);
+       struct bch_inode_unpacked parent_u;
        struct bch_inode_unpacked inode;
-       int ret = bch2_inode_find_by_inum(c, inum, &inode);
-       if (ret)
-               die("error looking up hardlink: %s", strerror(-ret));
-
-       inode.bi_nlink++;
-       update_inode(c, &inode);
 
-       create_dirent(c, parent, name, inum, mode);
+       int ret = bch2_trans_do(c, NULL, NULL, 0,
+               bch2_link_trans(trans,
+                               (subvol_inum) { 1, parent->bi_inum }, &parent_u,
+                               (subvol_inum) { 1, inum }, &inode, &qstr));
+       if (ret)
+               die("error creating hardlink: %s", bch2_err_str(ret));
 }
 
 static struct bch_inode_unpacked create_file(struct bch_fs *c,
@@ -163,17 +153,19 @@ static struct bch_inode_unpacked create_file(struct bch_fs *c,
                                             uid_t uid, gid_t gid,
                                             mode_t mode, dev_t rdev)
 {
+       struct qstr qstr = QSTR(name);
        struct bch_inode_unpacked new_inode;
-       int ret;
 
-       bch2_inode_init(c, &new_inode, uid, gid, mode, rdev, parent);
+       bch2_inode_init_early(c, &new_inode);
 
-       ret = bch2_inode_create(c, &new_inode, BLOCKDEV_INODE_MAX, 0,
-                               &c->unused_inode_hint);
+       int ret = bch2_trans_do(c, NULL, NULL, 0,
+               bch2_create_trans(trans,
+                                 (subvol_inum) { 1, parent->bi_inum }, parent,
+                                 &new_inode, &qstr,
+                                 uid, gid, mode, rdev, NULL, NULL,
+                                 (subvol_inum) {}, 0));
        if (ret)
-               die("error creating file: %s", strerror(-ret));
-
-       create_dirent(c, parent, name, new_inode.bi_inum, mode);
+               die("error creating %s: %s", name, bch2_err_str(ret));
 
        return new_inode;
 }
@@ -184,13 +176,13 @@ static struct bch_inode_unpacked create_file(struct bch_fs *c,
                        (handler) != NULL;                      \
                        (handler) = *(handlers)++)
 
-static const struct xattr_handler *xattr_resolve_name(const char **name)
+static const struct xattr_handler *xattr_resolve_name(char **name)
 {
        const struct xattr_handler **handlers = bch2_xattr_handlers;
        const struct xattr_handler *handler;
 
        for_each_xattr_handler(handlers, handler) {
-               const char *n;
+               char *n;
 
                n = strcmp_prefix(*name, xattr_prefix(handler));
                if (n) {
@@ -224,7 +216,7 @@ static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst,
        if (attrs_size < 0)
                die("listxattr error: %m");
 
-       const char *next, *attr;
+       char *next, *attr;
        for (attr = attrs;
             attr < attrs + attrs_size;
             attr = next) {
@@ -237,50 +229,55 @@ static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst,
                        die("error getting xattr val: %m");
 
                const struct xattr_handler *h = xattr_resolve_name(&attr);
+               struct bch_inode_unpacked inode_u;
 
-               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, NULL, 0,
+                               bch2_xattr_set(trans,
+                                              (subvol_inum) { 1, dst->bi_inum },
+                                              &inode_u, &hash_info, attr,
+                                              val, val_size, h->flags, 0));
                if (ret < 0)
-                       die("error creating xattr: %s", strerror(-ret));
+                       die("error creating xattr: %s", bch2_err_str(ret));
        }
 }
 
-static char buf[1 << 20] __aligned(PAGE_SIZE);
-static const size_t buf_pages = sizeof(buf) / PAGE_SIZE;
+#define WRITE_DATA_BUF (1 << 20)
+
+static char buf[WRITE_DATA_BUF] __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 {
-               struct bch_write_op op;
-               struct bio_vec bv[buf_pages];
-       } o;
-       struct closure cl;
+       struct bch_write_op op;
+       struct bio_vec bv[WRITE_DATA_BUF / PAGE_SIZE];
 
        BUG_ON(dst_offset       & (block_bytes(c) - 1));
        BUG_ON(len              & (block_bytes(c) - 1));
+       BUG_ON(len > WRITE_DATA_BUF);
 
-       closure_init_stack(&cl);
+       bio_init(&op.wbio.bio, NULL, bv, ARRAY_SIZE(bv), 0);
+       bch2_bio_map(&op.wbio.bio, buf, len);
 
-       bio_init(&o.op.wbio.bio, o.bv, buf_pages);
-       o.op.wbio.bio.bi_iter.bi_size = len;
-       bch2_bio_map(&o.op.wbio.bio, buf);
+       bch2_write_op_init(&op, c, bch2_opts_to_inode_opts(c->opts));
+       op.write_point  = writepoint_hashed(0);
+       op.nr_replicas  = 1;
+       op.subvol       = 1;
+       op.pos          = SPOS(dst_inode->bi_inum, dst_offset >> 9, U32_MAX);
+       op.flags |= BCH_WRITE_SYNC;
 
-       bch2_write_op_init(&o.op, c);
-       o.op.write_point        = writepoint_hashed(0);
-       o.op.nr_replicas        = 1;
-       o.op.pos                = POS(dst_inode->bi_inum, dst_offset >> 9);
-
-       int ret = bch2_disk_reservation_get(c, &o.op.res, len >> 9,
+       int ret = bch2_disk_reservation_get(c, &op.res, len >> 9,
                                            c->opts.data_replicas, 0);
        if (ret)
-               die("error reserving space in new filesystem: %s", strerror(-ret));
+               die("error reserving space in new filesystem: %s", bch2_err_str(ret));
 
-       closure_call(&o.op.cl, bch2_write, NULL, &cl);
-       closure_sync(&cl);
+       closure_call(&op.cl, bch2_write, NULL, NULL);
 
+       BUG_ON(!(op.flags & BCH_WRITE_DONE));
        dst_inode->bi_sectors += len >> 9;
+
+       if (op.error)
+               die("write error: %s", bch2_err_str(op.error));
 }
 
 static void copy_data(struct bch_fs *c,
@@ -316,7 +313,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;
+               BKEY_PADDED_ONSTACK(k, BKEY_EXTENT_VAL_U64s_MAX) k;
                u64 b = sector_to_bucket(ca, physical);
                struct disk_reservation res;
                unsigned sectors;
@@ -329,28 +326,23 @@ static void link_data(struct bch_fs *c, struct bch_inode_unpacked *dst,
                e = bkey_extent_init(&k.k);
                e->k.p.inode    = dst->bi_inum;
                e->k.p.offset   = logical + sectors;
+               e->k.p.snapshot = U32_MAX;
                e->k.size       = sectors;
-               extent_ptr_append(e, (struct bch_extent_ptr) {
+               bch2_bkey_append_ptr(&e->k_i, (struct bch_extent_ptr) {
                                        .offset = physical,
                                        .dev = 0,
-                                       .gen = bucket(ca, b)->mark.gen,
+                                       .gen = *bucket_gen(ca, b),
                                  });
 
-               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_err_str(ret));
 
-               bch2_check_mark_super(c, BCH_DATA_USER,
-                                     bch2_bkey_devs(extent_i_to_s_c(e).s_c));
-
-               ret = bch2_btree_insert(c, BTREE_ID_EXTENTS, &e->k_i,
-                                       &res, NULL, NULL, 0);
+               ret = bch2_btree_insert(c, BTREE_ID_extents, &e->k_i, &res, 0);
                if (ret)
-                       die("btree insert error %s", strerror(-ret));
+                       die("btree insert error %s", bch2_err_str(ret));
 
                bch2_disk_reservation_put(c, &res);
 
@@ -383,8 +375,13 @@ static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst,
                        fsync(src_fd);
                        break;
                }
+       fiemap_iter_exit(&iter);
 
        fiemap_for_each(src_fd, iter, e) {
+               u64 src_max = roundup(src_size, block_bytes(c));
+
+               e.fe_length = min(e.fe_length, src_max - e.fe_logical);
+
                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);
@@ -416,6 +413,7 @@ static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst,
                range_add(extents, e.fe_physical, e.fe_length);
                link_data(c, dst, e.fe_logical, e.fe_physical, e.fe_length);
        }
+       fiemap_iter_exit(&iter);
 }
 
 struct copy_fs_state {
@@ -446,6 +444,7 @@ static void copy_dir(struct copy_fs_state *s,
 
                if (!strcmp(d->d_name, ".") ||
                    !strcmp(d->d_name, "..") ||
+                   !strcmp(d->d_name, "lost+found") ||
                    stat.st_ino == s->bcachefs_inum)
                        continue;
 
@@ -512,6 +511,7 @@ next:
 
        if (errno)
                die("readdir error: %m");
+       closedir(dir);
 }
 
 static ranges reserve_new_fs_space(const char *file_path, unsigned block_size,
@@ -539,7 +539,7 @@ static ranges reserve_new_fs_space(const char *file_path, unsigned block_size,
 
        struct fiemap_iter iter;
        struct fiemap_extent e;
-       ranges extents = { NULL };
+       ranges extents = { 0 };
 
        fiemap_for_each(fd, iter, e) {
                if (e.fe_flags & (FIEMAP_EXTENT_UNKNOWN|
@@ -554,6 +554,7 @@ static ranges reserve_new_fs_space(const char *file_path, unsigned block_size,
 
                range_add(&extents, e.fe_physical, e.fe_length);
        }
+       fiemap_iter_exit(&iter);
        close(fd);
 
        ranges_sort_merge(&extents);
@@ -587,9 +588,10 @@ static void copy_fs(struct bch_fs *c, int src_fd, const char *src_path,
        syncfs(src_fd);
 
        struct bch_inode_unpacked root_inode;
-       int ret = bch2_inode_find_by_inum(c, BCACHEFS_ROOT_INO, &root_inode);
+       int ret = bch2_inode_find_by_inum(c, (subvol_inum) { 1, BCACHEFS_ROOT_INO },
+                                         &root_inode);
        if (ret)
-               die("error looking up root directory: %s", strerror(-ret));
+               die("error looking up root directory: %s", bch2_err_str(ret));
 
        if (fchdir(src_fd))
                die("chdir error: %m");
@@ -611,25 +613,24 @@ static void copy_fs(struct bch_fs *c, int src_fd, const char *src_path,
 
        update_inode(c, &root_inode);
 
-       darray_free(s.extents);
+       darray_exit(&s.extents);
        genradix_free(&s.hardlinks);
-
-       bch2_alloc_write(c);
 }
 
-static void find_superblock_space(ranges extents, struct dev_opts *dev)
+static void find_superblock_space(ranges extents,
+                                 struct format_opts opts,
+                                 struct dev_opts *dev)
 {
-       struct range *i;
-
-       darray_foreach(i, extents) {
+       darray_for_each(extents, i) {
                u64 start = round_up(max(256ULL << 10, i->start),
                                     dev->bucket_size << 9);
                u64 end = round_down(i->end,
                                     dev->bucket_size << 9);
 
-               if (start + (128 << 10) <= end) {
+               /* Need space for two superblocks: */
+               if (start + (opts.superblock_size << 9) * 2 <= end) {
                        dev->sb_offset  = start >> 9;
-                       dev->sb_end     = dev->sb_offset + 256;
+                       dev->sb_end     = dev->sb_offset + opts.superblock_size * 2;
                        return;
                }
        }
@@ -648,7 +649,7 @@ static void migrate_usage(void)
             "      --no_passphrase    Don't encrypt master encryption key\n"
             "  -F                     Force, even if metadata file already exists\n"
             "  -h                     Display this help and exit\n"
-            "Report bugs to <linux-bcache@vger.kernel.org>");
+            "Report bugs to <linux-bcachefs@vger.kernel.org>");
 }
 
 static const struct option migrate_opts[] = {
@@ -657,8 +658,10 @@ static const struct option migrate_opts[] = {
        { NULL }
 };
 
-static int migrate_fs(const char *fs_path,
-                     struct format_opts format_opts,
+static int migrate_fs(const char               *fs_path,
+                     struct bch_opt_strs       fs_opt_strs,
+                     struct bch_opts           fs_opts,
+                     struct format_opts        format_opts,
                      bool force)
 {
        if (!path_is_fs_root(fs_path))
@@ -673,31 +676,34 @@ static int migrate_fs(const char *fs_path,
        struct dev_opts dev = dev_opts_default();
 
        dev.path = dev_t_to_path(stat.st_dev);
-       dev.fd = xopen(dev.path, O_RDWR);
+       dev.bdev = blkdev_get_by_path(dev.path, BLK_OPEN_READ|BLK_OPEN_WRITE, &dev, NULL);
 
-       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;
+       opt_set(fs_opts, block_size, get_blocksize(dev.bdev->bd_buffered_fd));
 
        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);
+       dev.size        = get_size(dev.bdev->bd_buffered_fd);
+       dev.bucket_size = bch2_pick_bucket_size(fs_opts, &dev);
+       dev.nbuckets    = dev.size / dev.bucket_size;
+
+       bch2_check_bucket_size(fs_opts, &dev);
 
        u64 bcachefs_inum;
        ranges extents = reserve_new_fs_space(file_path,
-                               format_opts.block_size << 9,
-                               get_size(dev.path, dev.fd) / 5,
+                               fs_opts.block_size >> 9,
+                               get_size(dev.bdev->bd_buffered_fd) / 5,
                                &bcachefs_inum, stat.st_dev, force);
 
-       find_superblock_space(extents, &dev);
+       find_superblock_space(extents, format_opts, &dev);
 
-       struct bch_sb *sb = bch2_format(format_opts, &dev, 1);
+       struct bch_sb *sb = bch2_format(fs_opt_strs,
+                                       fs_opts,format_opts, &dev, 1);
        u64 sb_offset = le64_to_cpu(sb->layout.sb_offset[0]);
 
        if (format_opts.passphrase)
-               bch2_add_key(sb, format_opts.passphrase);
+               bch2_add_key(sb, "user", "user", format_opts.passphrase);
 
        free(sb);
 
@@ -708,16 +714,17 @@ static int migrate_fs(const char *fs_path,
        opt_set(opts, sb,       sb_offset);
        opt_set(opts, nostart,  true);
        opt_set(opts, noexcl,   true);
+       opt_set(opts, buckets_nouse, true);
 
        c = bch2_fs_open(path, 1, opts);
        if (IS_ERR(c))
-               die("Error opening new filesystem: %s", strerror(-PTR_ERR(c)));
+               die("Error opening new filesystem: %s", bch2_err_str(PTR_ERR(c)));
 
        mark_unreserved_space(c, extents);
 
-       const char *err = bch2_fs_start(c);
-       if (err)
-               die("Error starting new filesystem: %s", err);
+       int ret = bch2_fs_start(c);
+       if (ret)
+               die("Error starting new filesystem: %s", bch2_err_str(ret));
 
        copy_fs(c, fs_fd, fs_path, bcachefs_inum, &extents);
 
@@ -729,7 +736,7 @@ static int migrate_fs(const char *fs_path,
 
        c = bch2_fs_open(path, 1, opts);
        if (IS_ERR(c))
-               die("Error opening new filesystem: %s", strerror(-PTR_ERR(c)));
+               die("Error opening new filesystem: %s", bch2_err_str(PTR_ERR(c)));
 
        bch2_fs_stop(c);
        printf("fsck complete\n");
@@ -739,13 +746,13 @@ static int migrate_fs(const char *fs_path,
               "\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"
+              "  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",
+              "bcachefs migrate-superblock)\n",
               sb_offset, dev.path, dev.path, sb_offset);
        return 0;
 }
@@ -757,6 +764,10 @@ int cmd_migrate(int argc, char *argv[])
        bool no_passphrase = false, force = false;
        int opt;
 
+       struct bch_opt_strs fs_opt_strs =
+               bch2_cmdline_opts_get(&argc, argv, OPT_FORMAT);
+       struct bch_opts fs_opts = bch2_parse_opts(fs_opt_strs);
+
        while ((opt = getopt_long(argc, argv, "f:Fh",
                                  migrate_opts, NULL)) != -1)
                switch (opt) {
@@ -778,24 +789,29 @@ int cmd_migrate(int argc, char *argv[])
                }
 
        if (!fs_path)
-               die("Please specify a filesytem to migrate");
+               die("Please specify a filesystem to migrate");
 
        if (format_opts.encrypted && !no_passphrase)
                format_opts.passphrase = read_passphrase_twice("Enter passphrase: ");
 
-       return migrate_fs(fs_path, format_opts, force);
+       int ret = migrate_fs(fs_path,
+                            fs_opt_strs,
+                            fs_opts,
+                            format_opts, force);
+       bch2_opt_strs_free(&fs_opt_strs);
+       return ret;
 }
 
 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"
             "  -o offset     Offset of existing superblock\n"
             "  -h            Display this help and exit\n"
-            "Report bugs to <linux-bcache@vger.kernel.org>");
+            "Report bugs to <linux-bcachefs@vger.kernel.org>");
 }
 
 int cmd_migrate_superblock(int argc, char *argv[])