mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-01-23 00:07:07 +03:00
cmd_migrate fixes
when linking existing data, we weren't creating alloc btree keys - also, we were calculating the wrong bucket...
This commit is contained in:
parent
1ef243e3ad
commit
a9f5937a97
187
cmd_migrate.c
187
cmd_migrate.c
@ -58,7 +58,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;
|
||||
@ -245,12 +245,17 @@ static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
}
|
||||
}
|
||||
|
||||
static char buf[1 << 20] __aligned(PAGE_SIZE);
|
||||
static const size_t buf_pages = sizeof(buf) / 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[buf_pages];
|
||||
} o;
|
||||
struct closure cl;
|
||||
|
||||
BUG_ON(dst_offset & (block_bytes(c) - 1));
|
||||
@ -258,37 +263,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, 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_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);
|
||||
|
||||
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,
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -311,7 +317,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;
|
||||
@ -330,6 +336,8 @@ static void link_data(struct bch_fs *c, struct bch_inode_unpacked *dst,
|
||||
.gen = bucket(ca, b)->mark.gen,
|
||||
});
|
||||
|
||||
set_bit(b, ca->buckets_dirty);
|
||||
|
||||
ret = bch2_disk_reservation_get(c, &res, sectors, 1,
|
||||
BCH_DISK_RESERVATION_NOFAIL);
|
||||
if (ret)
|
||||
@ -364,18 +372,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);
|
||||
@ -384,20 +393,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;
|
||||
}
|
||||
|
||||
@ -476,7 +485,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:
|
||||
@ -603,6 +613,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)
|
||||
@ -645,37 +657,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);
|
||||
|
||||
@ -690,26 +675,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]);
|
||||
|
||||
@ -718,22 +701,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 };
|
||||
@ -766,9 +733,59 @@ 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"
|
||||
|
12
tools-util.c
12
tools-util.c
@ -82,10 +82,16 @@ void *xrealloc(void *p, size_t size)
|
||||
|
||||
void xpread(int fd, void *buf, size_t count, off_t offset)
|
||||
{
|
||||
ssize_t r = pread(fd, buf, count, offset);
|
||||
while (count) {
|
||||
ssize_t r = pread(fd, buf, count, offset);
|
||||
|
||||
if (r != count)
|
||||
die("read error (ret %zi)", r);
|
||||
if (r < 0)
|
||||
die("read error: %m");
|
||||
if (!r)
|
||||
die("pread error: unexpected eof");
|
||||
count -= r;
|
||||
offset += r;
|
||||
}
|
||||
}
|
||||
|
||||
void xpwrite(int fd, const void *buf, size_t count, off_t offset)
|
||||
|
Loading…
Reference in New Issue
Block a user