Skip to content

Bug: Hard link implementation creates different inode numbers #210

@Ivanbeethoven

Description

@Ivanbeethoven

Summary

The do_link function in the overlayfs implementation incorrectly allocates new inode numbers for hard links instead of reusing the source file's inode number, violating POSIX hard link semantics.

Problem

When creating a hard link using the do_link function (lines 1506-1605), the code always allocates a new inode number:

// Line 1583-1585
let path = format!("{}/{}", new_parent.path, name);
let ino = self.alloc_inode(&path)?;  // ❌ Wrong: allocates NEW inode
let child_ri = parent_real_inode.link(ctx, src_ino, name)?;

Expected vs Actual Behavior

Aspect Expected Actual
Source file inode 100 100
Hard link inode 100 (same) 101 (different)
POSIX compliance

Impact

  • File system integrity: Applications checking st_ino will see different inodes for the same file
  • Backup tools: rsync, tar and similar tools will fail to detect hard links
  • Deduplication: Storage space will be incorrectly calculated
  • Application bugs: Any software relying on inode equality for hard link detection will malfunction

Root Cause

The issue is in the None branch of the match statement where a completely new OverlayInode is created with a new inode number instead of reusing the source file's inode.

Fix Required

Replace:

let ino = self.alloc_inode(&path)?;

With:

let ino = src_node.inode;  // Reuse source inode number

Note: This fix requires careful handling of the inode store's path mapping and reference counting to avoid conflicts.

Reproduction

// Create file
let file_entry = fs.create(parent, "file.txt", args)?;
let original_ino = file_entry.inode;

// Create hard link
fs.link(original_ino, parent, "link.txt")?;
let link_entry = fs.lookup(parent, "link.txt")?;

// BUG: These should be equal but are different
assert_eq!(original_ino, link_entry.inode); // ❌ Fails

This is a critical bug that breaks fundamental filesystem semantics and should be prioritized for fixing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions