Fix some mount-related bugs

This commit is contained in:
Chen Chengjun 2025-11-20 09:18:46 +00:00 committed by Tate, Hongliang Tian
parent 8096249765
commit 6df2af2e17
3 changed files with 78 additions and 8 deletions

View File

@ -101,16 +101,18 @@ impl Dentry {
DentryFlags::from_bits(flags).unwrap()
}
/// Checks if this dentry is a descendant (child, grandchild, or
/// great-grandchild, etc.) of another dentry.
pub(super) fn is_descendant_of(&self, ancestor: &Arc<Self>) -> bool {
let mut parent = self.parent();
while let Some(p) = parent {
if Arc::ptr_eq(&p, ancestor) {
/// Checks if this dentry is a descendant of or the same as the given
/// ancestor dentry.
pub(super) fn is_equal_or_descendant_of(&self, ancestor: &Arc<Self>) -> bool {
let mut current = Some(self.this());
while let Some(node) = current {
if Arc::ptr_eq(&node, ancestor) {
return true;
}
parent = p.parent();
current = node.parent();
}
false
}

View File

@ -326,7 +326,7 @@ impl Mount {
let old_children = old_mount.children.read();
for old_child_mount in old_children.values() {
let mountpoint = old_child_mount.mountpoint().unwrap();
if !mountpoint.is_descendant_of(root_dentry) {
if !mountpoint.is_equal_or_descendant_of(old_mount.root_dentry()) {
continue;
}
let new_child_mount =

View File

@ -190,3 +190,71 @@ FN_TEST(setns_newns)
TEST_SUCC(rmdir(SETNS_MNT));
}
END_TEST()
#define COMPLEX_BASE "/test0"
#define COMPLEX_CONTENT "/test0/content"
#define COMPLEX_FILE "/test0/content/hello.txt"
FN_TEST(complex_mount_tree_unshare)
{
// Setup: Create directory structure
CHECK_WITH(mkdir(COMPLEX_BASE, 0755), _ret >= 0 || errno == EEXIST);
// Mount tmpfs on test0 (first layer)
TEST_SUCC(mount("none", COMPLEX_BASE, "tmpfs", 0, ""));
// Mount tmpfs on test0 again (second layer, stacked mount)
TEST_SUCC(mount("none", COMPLEX_BASE, "tmpfs", 0, ""));
// Recreate content directory on the new mount
TEST_SUCC(mkdir(COMPLEX_CONTENT, 0755));
// Mount tmpfs on test0/content (third layer)
TEST_SUCC(mount("none", COMPLEX_CONTENT, "tmpfs", 0, ""));
// Create file with content
int fd = TEST_SUCC(open(COMPLEX_FILE, O_CREAT | O_WRONLY, 0644));
TEST_SUCC(write(fd, "hello world\n", 12));
TEST_SUCC(close(fd));
// Verify file exists in parent
TEST_SUCC(access(COMPLEX_FILE, F_OK));
// Fork and unshare in child
pid_t pid = TEST_SUCC(fork());
if (pid == 0) {
TEST_SUCC(unshare(CLONE_NEWNS));
// Try to read the file created in the parent's mount tree
int fd = CHECK(open(COMPLEX_FILE, O_RDONLY));
char buf[32] = { 0 };
TEST_SUCC(read(fd, buf, sizeof(buf) - 1));
TEST_SUCC(close(fd));
// Verify the content
CHECK_WITH(strcmp(buf, "hello world\n"), _ret == 0);
// Verify we can still access the nested mount structure
TEST_SUCC(access(COMPLEX_CONTENT, F_OK));
TEST_SUCC(access(COMPLEX_BASE, F_OK));
exit(0);
} else {
int status;
TEST_SUCC(waitpid(pid, &status, 0));
TEST_RES(WIFEXITED(status) && WEXITSTATUS(status), _ret == 0);
// Verify parent's mount tree is unchanged
TEST_SUCC(access(COMPLEX_FILE, F_OK));
// Teardown: Unmount in reverse order
TEST_SUCC(umount(COMPLEX_CONTENT));
TEST_SUCC(rmdir(COMPLEX_CONTENT));
TEST_SUCC(umount(COMPLEX_BASE));
TEST_SUCC(umount(COMPLEX_BASE));
TEST_SUCC(rmdir(COMPLEX_BASE));
}
}
END_TEST()