diff options
Diffstat (limited to 'c_src/posix_to_bcachefs.c')
-rw-r--r-- | c_src/posix_to_bcachefs.c | 579 |
1 files changed, 503 insertions, 76 deletions
diff --git a/c_src/posix_to_bcachefs.c b/c_src/posix_to_bcachefs.c index 68d7e992..62f10b3d 100644 --- a/c_src/posix_to_bcachefs.c +++ b/c_src/posix_to_bcachefs.c @@ -7,12 +7,40 @@ #include "posix_to_bcachefs.h" #include "libbcachefs/alloc_foreground.h" #include "libbcachefs/buckets.h" +#include "libbcachefs/io_misc.h" +#include "libbcachefs/io_read.h" #include "libbcachefs/io_write.h" #include "libbcachefs/namei.h" #include "libbcachefs/str_hash.h" #include "libbcachefs/xattr.h" -void update_inode(struct bch_fs *c, +static int unlink_and_rm(struct bch_fs *c, + subvol_inum dir_inum, + struct bch_inode_unpacked *dir, + const char *child_name) +{ + struct qstr child_name_q = QSTR_INIT(child_name, strlen(child_name)); + + struct bch_inode_unpacked child; + int ret = bch2_trans_commit_do(c, NULL, NULL, + BCH_TRANS_COMMIT_no_enospc, + bch2_unlink_trans(trans, dir_inum, dir, &child, &child_name_q, false)); + bch_err_msg(c, ret, "unlinking %s", child_name); + if (ret) + return ret; + + if (!(child.bi_flags & BCH_INODE_unlinked)) + return 0; + + subvol_inum child_inum = dir_inum; + child_inum.inum = child.bi_inum; + + ret = bch2_inode_rm(c, child_inum); + bch_err_msg(c, ret, "deleting %s", child_name); + return ret; +} + +static void update_inode(struct bch_fs *c, struct bch_inode_unpacked *inode) { struct bkey_inode_buf packed; @@ -26,43 +54,87 @@ void update_inode(struct bch_fs *c, die("error updating inode: %s", bch2_err_str(ret)); } -void create_link(struct bch_fs *c, - struct bch_inode_unpacked *parent, - const char *name, u64 inum, mode_t mode) +static int create_or_update_link(struct bch_fs *c, + subvol_inum dir_inum, + struct bch_inode_unpacked *dir, + const char *name, subvol_inum inum, mode_t mode) { + struct bch_hash_info dir_hash = bch2_hash_info_init(c, dir); + struct qstr qstr = QSTR(name); - struct bch_inode_unpacked parent_u; + struct bch_inode_unpacked dir_u; struct bch_inode_unpacked inode; - int ret = bch2_trans_commit_do(c, NULL, NULL, 0, - bch2_link_trans(trans, - (subvol_inum) { 1, parent->bi_inum }, &parent_u, - (subvol_inum) { 1, inum }, &inode, &qstr)); + subvol_inum old_inum; + int ret = bch2_dirent_lookup(c, dir_inum, &dir_hash, &qstr, &old_inum); + if (bch2_err_matches(ret, ENOENT)) + goto create; if (ret) - die("error creating hardlink: %s", bch2_err_str(ret)); + return ret; + + if (subvol_inum_eq(inum, old_inum)) + return 0; + + ret = unlink_and_rm(c, dir_inum, dir, name); + if (ret) + return ret; +create: + ret = bch2_trans_commit_do(c, NULL, NULL, 0, + bch2_link_trans(trans, + dir_inum, &dir_u, + inum, &inode, &qstr)); + bch_err_msg(c, ret, "error creating hardlink %s", name); + return ret; } -struct bch_inode_unpacked create_file(struct bch_fs *c, - struct bch_inode_unpacked *parent, - const char *name, - uid_t uid, gid_t gid, - mode_t mode, dev_t rdev) +static struct bch_inode_unpacked create_or_update_file(struct bch_fs *c, + subvol_inum dir_inum, + struct bch_inode_unpacked *dir, + const char *name, + uid_t uid, gid_t gid, + mode_t mode, dev_t rdev) { - struct qstr qstr = QSTR(name); - struct bch_inode_unpacked new_inode; + struct bch_hash_info dir_hash = bch2_hash_info_init(c, dir); - bch2_inode_init_early(c, &new_inode); + struct qstr qname = QSTR(name); + struct bch_inode_unpacked child_inode; + subvol_inum child_inum; - int ret = bch2_trans_commit_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 %s: %s", name, bch2_err_str(ret)); + int ret = bch2_dirent_lookup(c, dir_inum, &dir_hash, + &qname, &child_inum); + if (!ret) { + /* Already exists, update */ + + ret = bch2_inode_find_by_inum(c, child_inum, &child_inode); + bch_err_fn(c, ret); + if (ret) + die("error looking up %s: %s", name, bch2_err_str(ret)); - return new_inode; + BUG_ON(mode_to_type(child_inode.bi_mode) != + mode_to_type(mode)); + + child_inode.bi_mode = mode; + child_inode.bi_uid = uid; + child_inode.bi_gid = gid; + child_inode.bi_dev = rdev; + + ret = bch2_trans_run(c, bch2_fsck_write_inode(trans, &child_inode)); + if (ret) + die("error updating up %s: %s", name, bch2_err_str(ret)); + } else { + bch2_inode_init_early(c, &child_inode); + + int ret = bch2_trans_commit_do(c, NULL, NULL, 0, + bch2_create_trans(trans, + dir_inum, dir, + &child_inode, &qname, + uid, gid, mode, rdev, NULL, NULL, + (subvol_inum) {}, 0)); + if (ret) + die("error creating %s: %s", name, bch2_err_str(ret)); + } + + return child_inode; } #define for_each_xattr_handler(handlers, handler) \ @@ -93,7 +165,7 @@ static const struct xattr_handler *xattr_resolve_name(char **name) return ERR_PTR(-EOPNOTSUPP); } -void copy_times(struct bch_fs *c, struct bch_inode_unpacked *dst, +static void copy_times(struct bch_fs *c, struct bch_inode_unpacked *dst, struct stat *src) { dst->bi_atime = timespec_to_bch2_time(c, src->st_atim); @@ -101,7 +173,7 @@ void copy_times(struct bch_fs *c, struct bch_inode_unpacked *dst, dst->bi_ctime = timespec_to_bch2_time(c, src->st_ctim); } -void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst, +static void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst, char *src) { struct bch_hash_info hash_info = bch2_hash_info_init(c, dst); @@ -139,11 +211,51 @@ void copy_xattrs(struct bch_fs *c, struct bch_inode_unpacked *dst, #define WRITE_DATA_BUF (1 << 20) -static char buf[WRITE_DATA_BUF] __aligned(PAGE_SIZE); +static char src_buf[WRITE_DATA_BUF] __aligned(PAGE_SIZE); +static char dst_buf[WRITE_DATA_BUF] __aligned(PAGE_SIZE); + +static void read_data_endio(struct bio *bio) +{ + closure_put(bio->bi_private); +} + +static void read_data(struct bch_fs *c, + subvol_inum inum, + struct bch_inode_unpacked *inode, + u64 offset, void *buf, size_t len) +{ + BUG_ON(offset & (block_bytes(c) - 1)); + BUG_ON(len & (block_bytes(c) - 1)); + BUG_ON(len > WRITE_DATA_BUF); + + struct closure cl; + closure_init_stack(&cl); + + struct bch_read_bio rbio; + struct bio_vec bv[WRITE_DATA_BUF / PAGE_SIZE]; + + bio_init(&rbio.bio, NULL, bv, ARRAY_SIZE(bv), 0); + rbio.bio.bi_opf = REQ_OP_READ|REQ_SYNC; + rbio.bio.bi_iter.bi_sector = offset >> 9; + rbio.bio.bi_private = &cl; + bch2_bio_map(&rbio.bio, buf, len); + + struct bch_io_opts opts; + bch2_inode_opts_get(&opts, c, inode); + + rbio_init(&rbio.bio, c, opts, read_data_endio); + + closure_get(&cl); + bch2_read(c, &rbio, inum); + closure_sync(&cl); + + if (rbio.ret) + die("read error: %s", bch2_err_str(rbio.ret)); +} static void write_data(struct bch_fs *c, struct bch_inode_unpacked *dst_inode, - u64 dst_offset, void *buf, size_t len) + u64 dst_offset, void *buf, size_t len, u64 new_i_size) { struct bch_write_op op; struct bio_vec bv[WRITE_DATA_BUF / PAGE_SIZE]; @@ -161,6 +273,7 @@ static void write_data(struct bch_fs *c, op.subvol = 1; op.pos = SPOS(dst_inode->bi_inum, dst_offset >> 9, U32_MAX); op.flags |= BCH_WRITE_sync|BCH_WRITE_only_specified_devs; + op.new_i_size = new_i_size; int ret = bch2_disk_reservation_get(c, &op.res, len >> 9, c->opts.data_replicas, 0); @@ -170,7 +283,7 @@ static void write_data(struct bch_fs *c, closure_call(&op.cl, bch2_write, NULL, NULL); BUG_ON(!(op.flags & BCH_WRITE_submitted)); - dst_inode->bi_sectors += len >> 9; + dst_inode->bi_sectors += op.i_sectors_delta; if (op.error) die("write error: %s", bch2_err_str(op.error)); @@ -181,13 +294,13 @@ static void copy_data(struct bch_fs *c, int src_fd, u64 start, u64 end) { while (start < end) { - unsigned len = min_t(u64, end - start, sizeof(buf)); + unsigned len = min_t(u64, end - start, sizeof(src_buf)); unsigned pad = round_up(len, block_bytes(c)) - len; - xpread(src_fd, buf, len, start); - memset(buf + len, 0, pad); + xpread(src_fd, src_buf, len, start); + memset(src_buf + len, 0, pad); - write_data(c, dst_inode, start, buf, len + pad); + write_data(c, dst_inode, start, src_buf, len + pad, start + len); start += len; } } @@ -249,24 +362,32 @@ static void link_data(struct bch_fs *c, struct bch_inode_unpacked *dst, } } -void copy_link(struct bch_fs *c, struct bch_inode_unpacked *dst, +static void copy_link(struct bch_fs *c, + subvol_inum dst_inum, + struct bch_inode_unpacked *dst, char *src) { - ssize_t i; - ssize_t ret = readlink(src, buf, sizeof(buf)); + s64 i_sectors_delta = 0; + int ret = bch2_fpunch(c, dst_inum, 0, U64_MAX, &i_sectors_delta); + if (ret) + die("bch2_fpunch error: %s", bch2_err_str(ret)); + + dst->bi_sectors += i_sectors_delta; + + ret = readlink(src, src_buf, sizeof(src_buf)); if (ret < 0) die("readlink error: %m"); - for (i = ret; i < round_up(ret, block_bytes(c)); i++) - buf[i] = 0; + for (unsigned i = ret; i < round_up(ret, block_bytes(c)); i++) + src_buf[i] = 0; - write_data(c, dst, 0, buf, round_up(ret, block_bytes(c))); + write_data(c, dst, 0, src_buf, round_up(ret, block_bytes(c)), ret); } -static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst, - int src_fd, u64 src_size, - char *src_path, struct copy_fs_state *s, - u64 reserve_start) +static void link_file_data(struct bch_fs *c, + struct copy_fs_state *s, + struct bch_inode_unpacked *dst, + int src_fd, char *src_path, u64 src_size) { struct fiemap_iter iter; struct fiemap_extent e; @@ -279,10 +400,14 @@ static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst, fiemap_iter_exit(&iter); fiemap_for_each(src_fd, iter, e) { + s->total_input += e.fe_length; + u64 src_max = roundup(src_size, block_bytes(c)); e.fe_length = min(e.fe_length, src_max - e.fe_logical); + unsigned visible_len = min(src_size - e.fe_logical, e.fe_length); + 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); @@ -292,16 +417,16 @@ static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst, FIEMAP_EXTENT_NOT_ALIGNED| FIEMAP_EXTENT_DATA_INLINE))) { copy_data(c, dst, src_fd, e.fe_logical, - e.fe_logical + min(src_size - e.fe_logical, - e.fe_length)); + e.fe_logical + visible_len); + s->total_wrote += visible_len; continue; } /* If the data is in bcachefs's superblock region, copy it: */ - if (e.fe_physical < reserve_start) { + if (e.fe_physical < s->reserve_start) { copy_data(c, dst, src_fd, e.fe_logical, - e.fe_logical + min(src_size - e.fe_logical, - e.fe_length)); + e.fe_logical + visible_len); + s->total_wrote += visible_len; continue; } @@ -310,10 +435,146 @@ static void copy_file(struct bch_fs *c, struct bch_inode_unpacked *dst, range_add(&s->extents, e.fe_physical, e.fe_length); link_data(c, dst, e.fe_logical, e.fe_physical, e.fe_length); + s->total_linked += e.fe_length; } fiemap_iter_exit(&iter); } +static struct range align_range(struct range r, unsigned bs) +{ + r.start = round_down(r.start, bs); + r.end = round_up(r.end, bs); + return r; +} + +struct range seek_data(int fd, u64 i_size, loff_t o) +{ + s64 s = lseek(fd, o, SEEK_DATA); + if (s < 0 && errno == ENXIO) + return (struct range) {}; + if (s < 0) + die("lseek error: %m"); + + s64 e = lseek(fd, s, SEEK_HOLE); + if (e < 0 && errno == ENXIO) + e = i_size; + if (e < 0) + die("lseek error: %m"); + + return (struct range) { s, e }; +} + +static struct range seek_data_aligned(int fd, u64 i_size, loff_t o, unsigned bs) +{ + struct range r = align_range(seek_data(fd, i_size, o), bs); + if (!r.end) + return r; + + while (true) { + struct range n = align_range(seek_data(fd, i_size, r.end), bs); + if (!n.end || r.end < n.start) + break; + + r.end = n.end; + } + + return r; +} + +struct range seek_mismatch(const char *buf1, const char *buf2, + unsigned o, unsigned len) +{ + while (o < len && buf1[o] == buf2[o]) + o++; + + if (o == len) + return (struct range) {}; + + unsigned s = o; + while (o < len && buf1[o] != buf2[o]) + o++; + + return (struct range) { s, o }; +} + +static struct range seek_mismatch_aligned(const char *buf1, const char *buf2, + unsigned offset, unsigned len, + unsigned bs) +{ + struct range r = align_range(seek_mismatch(buf1, buf2, offset, len), bs); + if (r.end) + while (true) { + struct range n = align_range(seek_mismatch(buf1, buf2, r.end, len), bs); + if (!n.end || r.end < n.start) + break; + + r.end = n.end; + } + + return r; +} + +static void copy_sync_file_range(struct bch_fs *c, + struct copy_fs_state *s, + subvol_inum dst_inum, + struct bch_inode_unpacked *dst, + int src_fd, u64 src_size, + struct range r) +{ + while (r.start != r.end) { + BUG_ON(r.start > r.end); + + unsigned b = min(r.end - r.start, WRITE_DATA_BUF); + + memset(src_buf, 0, b); + xpread(src_fd, src_buf, min(b, src_size - r.start), r.start); + + read_data(c, dst_inum, dst, r.start, dst_buf, b); + + struct range m = {}; + while ((m = seek_mismatch_aligned(src_buf, dst_buf, + m.end, b, c->opts.block_size)).end) { + write_data(c, dst, r.start + m.start, + src_buf + m.start, m.end - m.start, min_t(u64, m.end, src_size)); + s->total_wrote += m.end - m.start; + } + + r.start += b; + } +} + +static void copy_sync_file_data(struct bch_fs *c, + struct copy_fs_state *s, + subvol_inum dst_inum, + struct bch_inode_unpacked *dst, + int src_fd, u64 src_size) +{ + s64 i_sectors_delta = 0; + + struct range next, prev = {}; + + while ((next = seek_data_aligned(src_fd, src_size, prev.end, c->opts.block_size)).end) { + if (next.start) { + BUG_ON(prev.end >= next.start); + + int ret = bch2_fpunch(c, dst_inum, prev.end >> 9, next.start >> 9, &i_sectors_delta); + if (ret) + die("bch2_fpunch error: %s", bch2_err_str(ret)); + } + + copy_sync_file_range(c, s, dst_inum, dst, src_fd, src_size, next); + + s->total_input += next.end - next.start; + + prev = next; + } + + /* end of file, truncate remaining */ + int ret = bch2_fpunch(c, dst_inum, prev.end >> 9, U64_MAX, &i_sectors_delta); + if (ret) + die("bch2_fpunch error: %s", bch2_err_str(ret)); +} + static int dirent_cmp(const void *_l, const void *_r) { const struct dirent *l = _l; @@ -323,15 +584,131 @@ static int dirent_cmp(const void *_l, const void *_r) strcmp(l->d_name, r->d_name); } -static void copy_dir(struct copy_fs_state *s, - struct bch_fs *c, - struct bch_inode_unpacked *dst, - int src_fd, const char *src_path, - u64 reserve_start) +typedef DARRAY(struct dirent) dirents; + +struct readdir_out { + struct dir_context ctx; + dirents *dirents; +}; + +static int readdir_actor(struct dir_context *ctx, const char *name, int name_len, + loff_t pos, u64 inum, unsigned type) +{ + struct readdir_out *out = container_of(ctx, struct readdir_out, ctx); + + struct dirent d = { + .d_ino = inum, + .d_type = type, + }; + memcpy(d.d_name, name, name_len); + d.d_name[name_len] = '\0'; + + return darray_push(out->dirents, d); +} + +static int simple_readdir(struct bch_fs *c, + subvol_inum dir_inum, + struct bch_inode_unpacked *dir, + dirents *dirents) +{ + darray_init(dirents); + + struct bch_hash_info hash_info = bch2_hash_info_init(c, dir); + struct readdir_out dst_dirents = { .ctx.actor = readdir_actor, .dirents = dirents }; + + int ret = bch2_readdir(c, dir_inum, &hash_info, &dst_dirents.ctx); + bch_err_fn(c, ret); + if (ret) { + darray_exit(dirents); + return ret; + } + + sort(dirents->data, dirents->nr, sizeof(dirents->data[0]), dirent_cmp, NULL); + return 0; +} + +static int recursive_remove(struct bch_fs *c, + subvol_inum dir_inum, + struct bch_inode_unpacked *dir, + struct dirent *d) { + subvol_inum child_inum = dir_inum; + child_inum.inum = d->d_ino; + + struct bch_inode_unpacked child; + int ret = bch2_inode_find_by_inum(c, child_inum, &child); + bch_err_msg(c, ret, "looking up inode for %s", d->d_name); + if (ret) + return ret; + + if (S_ISDIR(child.bi_mode)) { + dirents child_dirents; + ret = simple_readdir(c, child_inum, &child, &child_dirents); + if (ret) + return ret; + + darray_for_each(child_dirents, i) { + ret = recursive_remove(c, child_inum, &child, i); + if (ret) { + darray_exit(&child_dirents); + return ret; + } + } + + darray_exit(&child_dirents); + } + + return unlink_and_rm(c, dir_inum, dir, d->d_name); +} + +static int delete_non_matching_dirents(struct bch_fs *c, + struct copy_fs_state *s, + subvol_inum dst_dir_inum, + struct bch_inode_unpacked *dst_dir, + dirents src_dirents) +{ + /* Assumes single subvolume */ + + dirents dst_dirents; + int ret = simple_readdir(c, dst_dir_inum, dst_dir, &dst_dirents); + if (ret) + return ret; + + struct dirent *src_d = src_dirents.data; + darray_for_each(dst_dirents, dst_d) { + while (src_d < &darray_top(src_dirents) && + dirent_cmp(src_d, dst_d) < 0) + src_d++; + + if (src_d == &darray_top(src_dirents) || + dirent_cmp(src_d, dst_d)) { + if (subvol_inum_eq(dst_dir_inum, BCACHEFS_ROOT_SUBVOL_INUM) && + !strcmp(dst_d->d_name, "lost+found")) + continue; + + if (s->verbosity > 1) + printf("deleting %s\n", dst_d->d_name); + + ret = recursive_remove(c, dst_dir_inum, dst_dir, dst_d); + if (ret) + goto err; + } + } +err: + darray_exit(&dst_dirents); + return ret; +} + +static int copy_dir(struct bch_fs *c, + struct copy_fs_state *s, + struct bch_inode_unpacked *dst, + int src_fd, const char *src_path) +{ + lseek(src_fd, 0, SEEK_SET); + DIR *dir = fdopendir(src_fd); struct dirent *d; - DARRAY(struct dirent) dirents = {}; + dirents dirents = {}; while ((errno = 0), (d = readdir(dir))) darray_push(&dirents, *d); @@ -341,6 +718,11 @@ static void copy_dir(struct copy_fs_state *s, sort(dirents.data, dirents.nr, sizeof(dirents.data[0]), dirent_cmp, NULL); + subvol_inum dir_inum = { 1, dst->bi_inum }; + int ret = delete_non_matching_dirents(c, s, dir_inum, dst, dirents); + if (ret) + goto err; + darray_for_each(dirents, d) { struct bch_inode_unpacked inode; int fd; @@ -359,48 +741,61 @@ static void copy_dir(struct copy_fs_state *s, if (BCH_MIGRATE_migrate == s->type && stat.st_ino == s->bcachefs_inum) continue; + s->total_files++; + char *child_path = mprintf("%s/%s", src_path, d->d_name); if (s->type == BCH_MIGRATE_migrate && stat.st_dev != s->dev) die("%s does not have correct st_dev!", child_path); - u64 *dst_inum = S_ISREG(stat.st_mode) + u64 *dst_inum_p = S_ISREG(stat.st_mode) ? genradix_ptr_alloc(&s->hardlinks, stat.st_ino, GFP_KERNEL) : NULL; - if (dst_inum && *dst_inum) { - create_link(c, dst, d->d_name, *dst_inum, S_IFREG); + subvol_inum dst_dir_inum = { 1, dst->bi_inum }; + + if (dst_inum_p && *dst_inum_p) { + ret = create_or_update_link(c, dst_dir_inum, dst, d->d_name, + (subvol_inum) { 1, *dst_inum_p }, S_IFREG); + if (ret) + goto err; goto next; } - inode = create_file(c, dst, d->d_name, + inode = create_or_update_file(c, dst_dir_inum, dst, d->d_name, stat.st_uid, stat.st_gid, stat.st_mode, stat.st_rdev); - if (dst_inum) - *dst_inum = inode.bi_inum; + subvol_inum dst_child_inum = { 1, inode.bi_inum }; - copy_xattrs(c, &inode, d->d_name); + if (dst_inum_p) + *dst_inum_p = inode.bi_inum; - /* copy xattrs */ + copy_xattrs(c, &inode, d->d_name); switch (mode_to_type(stat.st_mode)) { case DT_DIR: fd = xopen(d->d_name, O_RDONLY|O_NOATIME); - copy_dir(s, c, &inode, fd, child_path, reserve_start); + ret = copy_dir(c, s, &inode, fd, child_path); + if (ret) + goto err; break; case DT_REG: inode.bi_size = stat.st_size; fd = xopen(d->d_name, O_RDONLY|O_NOATIME); - copy_file(c, &inode, fd, stat.st_size, - child_path, s, reserve_start); + if (s->type == BCH_MIGRATE_migrate) + link_file_data(c, s, &inode, + fd, child_path, stat.st_size); + else + copy_sync_file_data(c, s, dst_child_inum, &inode, + fd, stat.st_size); xclose(fd); break; case DT_LNK: inode.bi_size = stat.st_size; - copy_link(c, &inode, d->d_name); + copy_link(c, dst_child_inum, &inode, d->d_name); break; case DT_FIFO: case DT_CHR: @@ -418,9 +813,10 @@ static void copy_dir(struct copy_fs_state *s, next: free(child_path); } - +err: darray_exit(&dirents); closedir(dir); + return ret; } static void reserve_old_fs_space(struct bch_fs *c, @@ -433,7 +829,9 @@ static void reserve_old_fs_space(struct bch_fs *c, struct hole_iter iter; struct range i; - dst = create_file(c, root_inode, "old_migrated_filesystem", + subvol_inum root_inum = { 1, root_inode->bi_inum }; + dst = create_or_update_file(c, root_inum, root_inode, + "old_migrated_filesystem", 0, 0, S_IFREG|0400, 0); dst.bi_size = bucket_to_sector(ca, ca->mi.nbuckets) << 9; @@ -451,8 +849,8 @@ static void reserve_old_fs_space(struct bch_fs *c, update_inode(c, &dst); } -void copy_fs(struct bch_fs *c, int src_fd, const char *src_path, - struct copy_fs_state *s, u64 reserve_start) +int copy_fs(struct bch_fs *c, struct copy_fs_state *s, + int src_fd, const char *src_path) { if (!S_ISDIR(xfstat(src_fd).st_mode)) die("%s is not a directory", src_path); @@ -463,8 +861,9 @@ void copy_fs(struct bch_fs *c, int src_fd, const char *src_path, struct bch_inode_unpacked root_inode; int ret = bch2_inode_find_by_inum(c, (subvol_inum) { 1, BCACHEFS_ROOT_INO }, &root_inode); + bch_err_msg(c, ret, "looking up root directory"); if (ret) - die("error looking up root directory: %s", bch2_err_str(ret)); + return ret; if (fchdir(src_fd)) die("fchdir error: %m"); @@ -474,13 +873,41 @@ void copy_fs(struct bch_fs *c, int src_fd, const char *src_path, copy_xattrs(c, &root_inode, "."); /* now, copy: */ - copy_dir(s, c, &root_inode, dup(src_fd), src_path, reserve_start); + ret = copy_dir(c, s, &root_inode, dup(src_fd), src_path); + bch_err_msg(c, ret, "copying filesystem"); + if (ret) + return ret; if (s->type == BCH_MIGRATE_migrate) - reserve_old_fs_space(c, &root_inode, &s->extents, reserve_start); + reserve_old_fs_space(c, &root_inode, &s->extents, s->reserve_start); update_inode(c, &root_inode); darray_exit(&s->extents); genradix_free(&s->hardlinks); + + CLASS(printbuf, buf)(); + printbuf_tabstop_push(&buf, 24); + printbuf_tabstop_push(&buf, 16); + prt_printf(&buf, "Total files:\t%llu\r\n", s->total_files); + prt_str_indented(&buf, "Total input:\t"); + prt_human_readable_u64(&buf, s->total_input); + prt_printf(&buf, "\r\n"); + + if (s->total_wrote) { + prt_str_indented(&buf, "Wrote:\t"); + prt_human_readable_u64(&buf, s->total_wrote); + prt_printf(&buf, "\r\n"); + } + + if (s->total_linked) { + prt_str(&buf, "Linked:\t"); + prt_human_readable_u64(&buf, s->total_linked); + prt_printf(&buf, "\r\n"); + } + + prt_newline(&buf); + + fputs(buf.buf, stdout); + return 0; } |