Thank you for the update.
If you don't mind, can I apply this directly into your patch?
---
fsck/dir.c | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/fsck/dir.c b/fsck/dir.c
index 7ea49ba8ff07..d599d88e9665 100644
--- a/fsck/dir.c
+++ b/fsck/dir.c
@@ -710,18 +710,23 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry
*de)
child = calloc(BLOCK_SZ, 1);
ASSERT(child);
- if (found_hardlink && found_hardlink->to_ino ) {
- /* If we found this devino in the cache, we're creating a hard
link */
+ if (found_hardlink && found_hardlink->to_ino) {
+ /*
+ * If we found this devino in the cache, we're creating a
+ * hard link.
+ */
get_node_info(sbi, found_hardlink->to_ino, &hardlink_ni);
if (hardlink_ni.blk_addr == NULL_ADDR) {
- MSG(0, "No original inode for hard link to_ino=%x\n",
found_hardlink->to_ino);
+ MSG(1, "No original inode for hard link to_ino=%x\n",
+ found_hardlink->to_ino);
return -1;
}
/* Use previously-recorded inode */
de->ino = found_hardlink->to_ino;
blkaddr = hardlink_ni.blk_addr;
- MSG(0, "Creating \"%s\" as hard link to inode %d\n", de->path,
de->ino);
+ MSG(1, "Info: Creating \"%s\" as hard link to inode %d\n",
+ de->path, de->ino);
} else {
f2fs_alloc_nid(sbi, &de->ino);
}
@@ -741,11 +746,13 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry
*de)
if (found_hardlink) {
if (!found_hardlink->to_ino) {
- MSG(0, "Adding inode %d from %s to hardlink cache\n",
de->ino, de->path);
+ MSG(2, "Adding inode %d from %s to hardlink cache\n",
+ de->ino, de->path);
found_hardlink->to_ino = de->ino;
} else {
/* Replace child with original block */
free(child);
+
child = calloc(BLOCK_SZ, 1);
ASSERT(child);
@@ -753,8 +760,10 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry
*de)
ASSERT(ret >= 0);
/* Increment links and skip to writing block */
- child->i.i_links++;
- MSG(0, "Number of links on inode %d is now %d\n",
de->ino, child->i.i_links);
+ child->i.i_links = cpu_to_le32(
+ le32_to_cpu(child->i.i_links) + 1);
+ MSG(2, "Number of links on inode %d is now %d\n",
+ de->ino, le32_to_cpu(child->i.i_links));
goto write_child_dir;
}
}
@@ -774,10 +783,14 @@ write_child_dir:
update_free_segments(sbi);
MSG(1, "Info: Create %s -> %s\n"
" -- ino=%x, type=%x, mode=%x, uid=%x, "
- "gid=%x, cap=%"PRIx64", size=%lu, pino=%x\n",
+ "gid=%x, cap=%"PRIx64", size=%lu, link=%u "
+ "blocks=%"PRIx64" pino=%x\n",
de->full_path, de->path,
de->ino, de->file_type, de->mode,
- de->uid, de->gid, de->capabilities, de->size, de->pino);
+ de->uid, de->gid, de->capabilities, de->size,
+ le32_to_cpu(child->i.i_links),
+ le64_to_cpu(child->i.i_blocks),
+ de->pino);
free_child_dir:
free(child);
free_parent_dir:
--
2.29.2.576.ga3fc446d84-goog
On 12/10, Jordan Webb wrote:
> If sload.f2fs encounters a file with nr_links > 1, it will mark it
> as a possible hard link by remembering the original device and
> inode. When sload.f2fs creates the file, it will check if it has
> already created a file for the same original device and inode. If
> so, it will add the original inode to the directory and increment
> the number of links to it, instead of writing a new inode.
>
> This allows sload.f2fs to accurately reproduce a directory tree that
> contains hard links, such as those created by ostree. Without this
> patch, directory trees containing hard links result in the content of
> the files being duplicated.
>
> This is version 2 of the patch; it has been rebased against the dev
> branch and includes a fix from Jaegeuk Kim to avoid building data
> contents twice on hard linked files.
>
> Co-authored-by: Jaegeuk Kim <[email protected]>
> Signed-off-by: Jordan Webb <[email protected]>
> ---
> fsck/dir.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++-
> fsck/f2fs.h | 10 +++++++
> fsck/fsck.h | 2 ++
> fsck/segment.c | 11 ++++++++
> fsck/sload.c | 9 +++++++
> 5 files changed, 104 insertions(+), 1 deletion(-)
>
> diff --git a/fsck/dir.c b/fsck/dir.c
> index dc03c98..37b32f1 100644
> --- a/fsck/dir.c
> +++ b/fsck/dir.c
> @@ -15,6 +15,7 @@
> */
> #include "fsck.h"
> #include "node.h"
> +#include <search.h>
>
> static int room_for_filename(const u8 *bitmap, int slots, int max_slots)
> {
> @@ -634,10 +635,42 @@ int convert_inline_dentry(struct f2fs_sb_info *sbi,
> struct f2fs_node *node,
> return 0;
> }
>
> +static int cmp_from_devino(const void *a, const void *b) {
> + u64 devino_a = ((struct hardlink_cache_entry*) a)->from_devino;
> + u64 devino_b = ((struct hardlink_cache_entry*) b)->from_devino;
> +
> + return (devino_a > devino_b) - (devino_a < devino_b);
> +}
> +
> +struct hardlink_cache_entry *f2fs_search_hardlink(struct f2fs_sb_info *sbi,
> + struct dentry *de)
> +{
> + struct hardlink_cache_entry *find_hardlink = NULL;
> + struct hardlink_cache_entry *found_hardlink = NULL;
> + void *search_result;
> +
> + /* This might be a hardlink, try to find it in the cache */
> + find_hardlink = calloc(1, sizeof(struct hardlink_cache_entry));
> + find_hardlink->from_devino = de->from_devino;
> +
> + search_result = tsearch(find_hardlink, &(sbi->hardlink_cache),
> cmp_from_devino);
> + ASSERT(search_result != 0);
> +
> + found_hardlink = *(struct hardlink_cache_entry**) search_result;
> + ASSERT(find_hardlink->from_devino == found_hardlink->from_devino);
> +
> + /* If it was already in the cache, free the entry we just created */
> + if (found_hardlink != find_hardlink)
> + free(find_hardlink);
> +
> + return found_hardlink;
> +}
> +
> int f2fs_create(struct f2fs_sb_info *sbi, struct dentry *de)
> {
> struct f2fs_node *parent, *child;
> - struct node_info ni;
> + struct hardlink_cache_entry *found_hardlink = NULL;
> + struct node_info ni, hardlink_ni;
> struct f2fs_summary sum;
> block_t blkaddr = NULL_ADDR;
> int ret;
> @@ -671,10 +704,27 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry
> *de)
> goto free_parent_dir;
> }
>
> + if (de->from_devino)
> + found_hardlink = f2fs_search_hardlink(sbi, de);
> +
> child = calloc(BLOCK_SZ, 1);
> ASSERT(child);
>
> + if (found_hardlink && found_hardlink->to_ino ) {
> + /* If we found this devino in the cache, we're creating a hard
> link */
> + get_node_info(sbi, found_hardlink->to_ino, &hardlink_ni);
> + if (hardlink_ni.blk_addr == NULL_ADDR) {
> + MSG(0, "No original inode for hard link to_ino=%x\n",
> found_hardlink->to_ino);
> + return -1;
> + }
> +
> + /* Use previously-recorded inode */
> + de->ino = found_hardlink->to_ino;
> + blkaddr = hardlink_ni.blk_addr;
> + MSG(0, "Creating \"%s\" as hard link to inode %d\n", de->path,
> de->ino);
> + } else {
> f2fs_alloc_nid(sbi, &de->ino);
> + }
>
> init_inode_block(sbi, child, de);
>
> @@ -689,6 +739,26 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry
> *de)
> goto free_child_dir;
> }
>
> + if (found_hardlink) {
> + if (!found_hardlink->to_ino) {
> + MSG(0, "Adding inode %d from %s to hardlink cache\n",
> de->ino, de->path);
> + found_hardlink->to_ino = de->ino;
> + } else {
> + /* Replace child with original block */
> + free(child);
> + child = calloc(BLOCK_SZ, 1);
> + ASSERT(child);
> +
> + ret = dev_read_block(child, blkaddr);
> + ASSERT(ret >= 0);
> +
> + /* Increment links and skip to writing block */
> + child->i.i_links++;
> + MSG(0, "Number of links on inode %d is now %d\n",
> de->ino, child->i.i_links);
> + goto write_child_dir;
> + }
> + }
> +
> /* write child */
> set_summary(&sum, de->ino, 0, ni.version);
> ret = reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_NODE, 1);
> @@ -697,6 +767,7 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry
> *de)
> /* update nat info */
> update_nat_blkaddr(sbi, de->ino, de->ino, blkaddr);
>
> +write_child_dir:
> ret = dev_write_block(child, blkaddr);
> ASSERT(ret >= 0);
>
> diff --git a/fsck/f2fs.h b/fsck/f2fs.h
> index 76e8272..9c6b0e4 100644
> --- a/fsck/f2fs.h
> +++ b/fsck/f2fs.h
> @@ -221,6 +221,7 @@ struct dentry {
> uint64_t capabilities;
> nid_t ino;
> nid_t pino;
> + u64 from_devino;
> };
>
> /* different from dnode_of_data in kernel */
> @@ -234,6 +235,12 @@ struct dnode_of_data {
> int idirty, ndirty;
> };
>
> +struct hardlink_cache_entry {
> + u64 from_devino;
> + nid_t to_ino;
> + int nbuild;
> +};
> +
> struct f2fs_sb_info {
> struct f2fs_fsck *fsck;
>
> @@ -276,6 +283,9 @@ struct f2fs_sb_info {
>
> /* true if late_build_segment_manger() is called */
> bool seg_manager_done;
> +
> + /* keep track of hardlinks so we can recreate them */
> + void *hardlink_cache;
> };
>
> static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info
> *sbi)
> diff --git a/fsck/fsck.h b/fsck/fsck.h
> index c5e85fe..037aea9 100644
> --- a/fsck/fsck.h
> +++ b/fsck/fsck.h
> @@ -296,6 +296,8 @@ int f2fs_find_path(struct f2fs_sb_info *, char *, nid_t
> *);
> nid_t f2fs_lookup(struct f2fs_sb_info *, struct f2fs_node *, u8 *, int);
> int f2fs_add_link(struct f2fs_sb_info *, struct f2fs_node *,
> const unsigned char *, int, nid_t, int, block_t, int);
> +struct hardlink_cache_entry *f2fs_search_hardlink(struct f2fs_sb_info *sbi,
> + struct dentry *de);
>
> /* xattr.c */
> void *read_all_xattrs(struct f2fs_sb_info *, struct f2fs_node *);
> diff --git a/fsck/segment.c b/fsck/segment.c
> index 0487f41..878fb85 100644
> --- a/fsck/segment.c
> +++ b/fsck/segment.c
> @@ -351,6 +351,17 @@ int f2fs_build_file(struct f2fs_sb_info *sbi, struct
> dentry *de)
> if (de->ino == 0)
> return -1;
>
> + if (de->from_devino) {
> + struct hardlink_cache_entry *found_hardlink;
> +
> + found_hardlink = f2fs_search_hardlink(sbi, de);
> + if (found_hardlink && found_hardlink->to_ino &&
> + found_hardlink->nbuild)
> + return 0;
> +
> + found_hardlink->nbuild++;
> + }
> +
> fd = open(de->full_path, O_RDONLY);
> if (fd < 0) {
> MSG(0, "Skip: Fail to open %s\n", de->full_path);
> diff --git a/fsck/sload.c b/fsck/sload.c
> index 14012fb..f3a6c12 100644
> --- a/fsck/sload.c
> +++ b/fsck/sload.c
> @@ -148,6 +148,12 @@ static void set_inode_metadata(struct dentry *de)
> }
>
> if (S_ISREG(stat.st_mode)) {
> + if (stat.st_nlink > 1) {
> + /* This file might have multiple links to it, so
> remember device and inode */
> + de->from_devino = stat.st_dev;
> + de->from_devino <<= 32;
> + de->from_devino |= stat.st_ino;
> + }
> de->file_type = F2FS_FT_REG_FILE;
> } else if (S_ISDIR(stat.st_mode)) {
> de->file_type = F2FS_FT_DIR;
> @@ -333,6 +339,9 @@ int f2fs_sload(struct f2fs_sb_info *sbi)
> /* flush NAT/SIT journal entries */
> flush_journal_entries(sbi);
>
> + /* initialize empty hardlink cache */
> + sbi->hardlink_cache = 0;
> +
> ret = build_directory(sbi, c.from_dir, "/",
> c.target_out_dir, F2FS_ROOT_INO(sbi));
> if (ret) {
> --
> 2.24.3 (Apple Git-128)
>
>
>
>
> _______________________________________________
> Linux-f2fs-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel