summaryrefslogtreecommitdiff
path: root/c_src
diff options
context:
space:
mode:
Diffstat (limited to 'c_src')
-rw-r--r--c_src/posix_to_bcachefs.c44
-rw-r--r--c_src/posix_to_bcachefs.h2
2 files changed, 37 insertions, 9 deletions
diff --git a/c_src/posix_to_bcachefs.c b/c_src/posix_to_bcachefs.c
index ca44db32..e80a3564 100644
--- a/c_src/posix_to_bcachefs.c
+++ b/c_src/posix_to_bcachefs.c
@@ -14,6 +14,18 @@
#include "libbcachefs/str_hash.h"
#include "libbcachefs/xattr.h"
+struct hardlink {
+ struct rhash_head hash;
+ u64 src, dst;
+};
+
+static const struct rhashtable_params hardlink_params = {
+ .head_offset = offsetof(struct hardlink, hash),
+ .key_offset = offsetof(struct hardlink, src),
+ .key_len = sizeof(u64),
+ .automatic_shrinking = true,
+};
+
static int unlink_and_rm(struct bch_fs *c,
subvol_inum dir_inum,
struct bch_inode_unpacked *dir,
@@ -747,15 +759,24 @@ static int copy_dir(struct bch_fs *c,
if (s->type == BCH_MIGRATE_migrate && stat.st_dev != s->dev)
die("%s does not have correct st_dev!", child_path);
- u64 *dst_inum_p = S_ISREG(stat.st_mode)
- ? genradix_ptr_alloc(&s->hardlinks, stat.st_ino, GFP_KERNEL)
- : NULL;
+ struct hardlink *h = NULL;
+ if (S_ISREG(stat.st_mode) && stat.st_nlink > 1) {
+ u64 ino = stat.st_ino;
+ h = rhashtable_lookup_fast(&s->hardlinks, &ino, hardlink_params);
+ if (!h) {
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ h->src = ino;
+ int ret = rhashtable_lookup_insert_fast(&s->hardlinks, &h->hash,
+ hardlink_params);
+ BUG_ON(ret);
+ }
+ }
subvol_inum dst_dir_inum = { 1, dst->bi_inum };
- if (dst_inum_p && *dst_inum_p) {
+ if (h && h->dst) {
ret = create_or_update_link(c, dst_dir_inum, dst, d->d_name,
- (subvol_inum) { 1, *dst_inum_p }, S_IFREG);
+ (subvol_inum) { 1, h->dst}, S_IFREG);
if (ret)
goto err;
goto next;
@@ -767,8 +788,8 @@ static int copy_dir(struct bch_fs *c,
subvol_inum dst_child_inum = { 1, inode.bi_inum };
- if (dst_inum_p)
- *dst_inum_p = inode.bi_inum;
+ if (h)
+ h->dst = inode.bi_inum;
copy_xattrs(c, &inode, d->d_name);
@@ -857,6 +878,8 @@ int copy_fs(struct bch_fs *c, struct copy_fs_state *s,
if (s->type == BCH_MIGRATE_migrate)
syncfs(src_fd);
+ BUG_ON(rhashtable_init(&s->hardlinks, &hardlink_params));
+
struct bch_inode_unpacked root_inode;
int ret = bch2_inode_find_by_inum(c, (subvol_inum) { 1, BCACHEFS_ROOT_INO },
&root_inode);
@@ -883,7 +906,12 @@ int copy_fs(struct bch_fs *c, struct copy_fs_state *s,
update_inode(c, &root_inode);
darray_exit(&s->extents);
- genradix_free(&s->hardlinks);
+ /*
+ * We're currently leaking s->hardlinks: we want to convert this back to
+ * a radix tree, when we have a radix tree that supports real 64 bit
+ * integer keys
+ */
+ //genradix_free(&s->hardlinks);
CLASS(printbuf, buf)();
printbuf_tabstop_push(&buf, 24);
diff --git a/c_src/posix_to_bcachefs.h b/c_src/posix_to_bcachefs.h
index 3fc586d8..65e5de1f 100644
--- a/c_src/posix_to_bcachefs.h
+++ b/c_src/posix_to_bcachefs.h
@@ -33,7 +33,7 @@ struct copy_fs_state {
u64 bcachefs_inum;
dev_t dev;
- GENRADIX(u64) hardlinks;
+ struct rhashtable hardlinks;
ranges extents;
enum bch_migrate_type type;
unsigned verbosity;