X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=cmd_migrate.c;h=cde1fce4397c725baafa3326d10d54799b65ed5f;hb=b7453196fe82ee70a3ec657847e974450fdac8ad;hp=82fa0f125be3400a965475db7587a301a93a189a;hpb=565b4a74d6c25c78b0d2b82d9529595fc6269308;p=bcachefs-tools-debian diff --git a/cmd_migrate.c b/cmd_migrate.c index 82fa0f1..cde1fce 100644 --- a/cmd_migrate.c +++ b/cmd_migrate.c @@ -1,15 +1,15 @@ -#include +#include #include #include #include #include +#include #include #include #include #include #include #include -#include #include #include @@ -24,15 +24,23 @@ #include #include #include -#include "btree_update.h" -#include "buckets.h" -#include "dirent.h" -#include "fs.h" -#include "inode.h" -#include "io.h" -#include "str_hash.h" -#include "super.h" -#include "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/errcode.h" +#include "libbcachefs/fs-common.h" +#include "libbcachefs/inode.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) { @@ -57,7 +65,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; @@ -96,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) @@ -104,7 +111,7 @@ static void mark_unreserved_space(struct bch_fs *c, ranges extents) b = sector_to_bucket(ca, i.start >> 9); do { - bucket_cmpxchg(&ca->buckets[b], new, new.nouse = 1); + set_bit(b, ca->buckets_nouse); b++; } while (bucket_to_sector(ca, b) << 9 < i.end); } @@ -117,41 +124,27 @@ 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); + 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->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->i_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.i_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, @@ -160,20 +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; - struct bkey_inode_buf packed; - int ret; - bch2_inode_init(c, &new_inode, uid, gid, mode, rdev); - bch2_inode_pack(&packed, &new_inode); + bch2_inode_init_early(c, &new_inode); - ret = bch2_inode_create(c, &packed.inode.k_i, 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)); - - new_inode.inum = packed.inode.k.p.inode; - create_dirent(c, parent, name, new_inode.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) { @@ -209,9 +201,9 @@ static const struct xattr_handler *xattr_resolve_name(const char **name) static void copy_times(struct bch_fs *c, struct bch_inode_unpacked *dst, struct stat *src) { - dst->i_atime = timespec_to_bch2_time(c, src->st_atim); - dst->i_mtime = timespec_to_bch2_time(c, src->st_mtim); - dst->i_ctime = timespec_to_bch2_time(c, src->st_ctim); + dst->bi_atime = timespec_to_bch2_time(c, src->st_atim); + dst->bi_mtime = timespec_to_bch2_time(c, src->st_mtim); + dst->bi_ctime = timespec_to_bch2_time(c, src->st_ctim); } static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst, @@ -224,7 +216,8 @@ static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst, if (attrs_size < 0) die("listxattr error: %m"); - for (const char *next, *attr = attrs; + char *next, *attr; + for (attr = attrs; attr < attrs + attrs_size; attr = next) { next = attr + strlen(attr) + 1; @@ -236,55 +229,68 @@ 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->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)); } } +#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 disk_reservation res; struct bch_write_op op; - struct bio_vec bv; + struct bio_vec bv[WRITE_DATA_BUF / PAGE_SIZE]; struct closure cl; 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, &bv, 1); - op.wbio.bio.bi_iter.bi_size = len; - bch2_bio_map(&op.wbio.bio, buf); + bio_init(&op.wbio.bio, NULL, bv, ARRAY_SIZE(bv), 0); + bch2_bio_map(&op.wbio.bio, buf, len); - int ret = bch2_disk_reservation_get(c, &res, len >> 9, 0); + 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; + + 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)); - bch2_write_op_init(&op, c, res, c->write_points, - POS(dst_inode->inum, dst_offset >> 9), NULL, 0); closure_call(&op.cl, bch2_write, NULL, &cl); - closure_sync(&cl); - dst_inode->i_sectors += len >> 9; + 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; } } @@ -306,8 +312,8 @@ 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); + BKEY_PADDED_ONSTACK(k, BKEY_EXTENT_VAL_U64s_MAX) k; + u64 b = sector_to_bucket(ca, physical); struct disk_reservation res; unsigned sectors; int ret; @@ -317,31 +323,29 @@ static void link_data(struct bch_fs *c, struct bch_inode_unpacked *dst, length); e = bkey_extent_init(&k.k); - e->k.p.inode = dst->inum; + 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 = ca->buckets[b].mark.gen, + .gen = *bucket_gen(ca, b), }); - ret = bch2_disk_reservation_get(c, &res, sectors, + 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, extent_i_to_s_c(e), false); + bch2_err_str(ret)); - 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); - dst->i_sectors += sectors; + dst->bi_sectors += sectors; logical += sectors; physical += sectors; length -= sectors; @@ -359,18 +363,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); @@ -379,20 +384,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; } @@ -432,6 +437,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; @@ -454,7 +460,7 @@ static void copy_dir(struct copy_fs_state *s, stat.st_mode, stat.st_rdev); if (dst_inum) - *dst_inum = inode.inum; + *dst_inum = inode.bi_inum; copy_times(c, &inode, &stat); copy_xattrs(c, &inode, d->d_name); @@ -468,14 +474,15 @@ static void copy_dir(struct copy_fs_state *s, close(fd); break; case DT_REG: - inode.i_size = stat.st_size; + 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: - inode.i_size = stat.st_size; + inode.bi_size = stat.st_size; copy_link(c, &inode, d->d_name); break; @@ -524,7 +531,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| @@ -556,7 +563,7 @@ static void reserve_old_fs_space(struct bch_fs *c, dst = create_file(c, root_inode, "old_migrated_filesystem", 0, 0, S_IFREG|0400, 0); - dst.i_size = bucket_to_sector(ca, ca->mi.nbuckets) << 9; + dst.bi_size = bucket_to_sector(ca, ca->mi.nbuckets) << 9; ranges_sort_merge(extents); @@ -572,9 +579,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, BCACHE_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"); @@ -596,23 +604,26 @@ 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); } -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; } } @@ -631,7 +642,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 "); + "Report bugs to "); } static const struct option migrate_opts[] = { @@ -640,37 +651,12 @@ static const struct option migrate_opts[] = { { NULL } }; -int cmd_migrate(int argc, char *argv[]) +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) { - 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); @@ -680,117 +666,145 @@ int cmd_migrate(int argc, char *argv[]) if (!S_ISDIR(stat.st_mode)) die("%s is not a directory", fs_path); - struct dev_opts dev = { 0 }; + 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); - block_size = min_t(unsigned, stat.st_blksize, - get_blocksize(dev.path, dev.fd) << 9); + opt_set(fs_opts, block_size, get_blocksize(dev.bdev->bd_buffered_fd)); - 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); + + 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_pick_bucket_size(format_opts, &dev); + bch2_check_bucket_size(fs_opts, &dev); + u64 bcachefs_inum; ranges extents = reserve_new_fs_space(file_path, - block_size, 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); - - if (format_opts.encrypted && !no_passphrase) { - format_opts.passphrase = read_passphrase("Enter passphrase: "); - - if (isatty(STDIN_FILENO)) { - char *pass2 = - read_passphrase("Enter same passphrase again: "); - - if (strcmp(format_opts.passphrase, pass2)) { - memzero_explicit(format_opts.passphrase, - strlen(format_opts.passphrase)); - memzero_explicit(pass2, strlen(pass2)); - die("Passphrases do not match"); - } - - memzero_explicit(pass2, strlen(pass2)); - free(pass2); - } - } + 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); - 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 }; - const char *err; - opts.sb = sb_offset; - opts.nostart = true; - opts.noexcl = true; + opt_set(opts, sb, sb_offset); + opt_set(opts, nostart, true); + opt_set(opts, noexcl, true); + opt_set(opts, buckets_nouse, true); - err = bch2_fs_open(path, 1, opts, &c); - if (err) - die("Error opening new filesystem: %s", err); + c = bch2_fs_open(path, 1, opts); + if (IS_ERR(c)) + die("Error opening new filesystem: %s", bch2_err_str(PTR_ERR(c))); mark_unreserved_space(c, extents); - 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); bch2_fs_stop(c); printf("Migrate complete, running fsck:\n"); - opts.nostart = false; - opts.nochanges = true; + opt_set(opts, nostart, false); + opt_set(opts, nochanges, true); - err = bch2_fs_open(path, 1, opts, &c); - if (err) - die("Error opening new filesystem: %s", err); + c = bch2_fs_open(path, 1, opts); + if (IS_ERR(c)) + die("Error opening new filesystem: %s", bch2_err_str(PTR_ERR(c))); 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; + + 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) { + 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 filesystem to migrate"); + + if (format_opts.encrypted && !no_passphrase) + format_opts.passphrase = read_passphrase_twice("Enter passphrase: "); + + 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 "); + "Report bugs to "); } int cmd_migrate_superblock(int argc, char *argv[]) @@ -826,7 +840,8 @@ int cmd_migrate_superblock(int argc, char *argv[]) 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++) + unsigned i; + for (i = 0; i < sb->layout.nr_superblocks; i++) if (le64_to_cpu(sb->layout.sb_offset[i]) == BCH_SB_SECTOR) die("Superblock layout already has default superblock");