Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 53 additions & 20 deletions data/loongarch_musl/etc/init.d/rcS
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,25 @@ run_oscomp_tests_if_present() {
# 检测到官方测试脚本就非交互地依次执行,跑完主动关机。
[ -d /tests ] || return 1

# 官方测试二进制硬编码了 ELF 解释器路径(如 /lib64/ld-linux-*.so.*)。
# 我们是 musl rootfs,把测试镜像里的 glibc loader/库软链到常见 ABI libdir 以便加载。
if [ -d /tests/glibc/lib ]; then
prepare_glibc_libs() {
# 官方 glibc 测试二进制硬编码了 ELF 解释器路径(如 /lib64/ld-linux-*.so.*)。
# 默认先跑 musl 分组;后续支持 glibc 时再启用这段准备逻辑。
[ -d /tests/glibc/lib ] || return 0
[ -d /lib ] || /bin/mkdir -p /lib
[ -d /lib64 ] || /bin/mkdir -p /lib64
for f in /tests/glibc/lib/ld-linux-*.so.*; do
[ -f "$f" ] || continue
base="${f##*/}"
/bin/ln -sf "$f" "/lib/$base"
/bin/ln -sf "$f" "/lib64/$base"
[ -e "/lib/$base" ] || /bin/ln -s "$f" "/lib/$base"
[ -e "/lib64/$base" ] || /bin/ln -s "$f" "/lib64/$base"
done
for base in libc.so.6 libm.so.6 libpthread.so.0 libdl.so.2 librt.so.1 libresolv.so.2; do
if [ -f "/tests/glibc/lib/$base" ]; then
/bin/ln -sf "/tests/glibc/lib/$base" "/lib/$base"
/bin/ln -sf "/tests/glibc/lib/$base" "/lib64/$base"
[ -e "/lib/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib/$base"
[ -e "/lib64/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib64/$base"
Comment thread
a6d9a6m marked this conversation as resolved.
Outdated
fi
done
fi
}

scripts=""
add_script() {
Expand All @@ -84,21 +85,53 @@ run_oscomp_tests_if_present() {
scripts="$scripts $1"
}

# 1) /tests 根下的脚本。
for f in /tests/*_testcode.sh; do
[ -f "$f" ] || continue
add_script "$f"
done

# 2) 下一层:/tests/*/*,匹配官方镜像布局 /tests/glibc/*.sh、/tests/musl/*.sh。
for d in /tests/*; do
[ -d "$d" ] || continue
[ "$d" = "/tests/tests" ] && continue
for f in "$d"/*_testcode.sh; do
add_scripts_in_dir() {
dir="$1"
[ -d "$dir" ] || return 0
for f in "$dir"/*_testcode.sh; do
[ -f "$f" ] || continue
add_script "$f"
done
done
}

add_other_suite_scripts() {
for d in /tests/*; do
[ -d "$d" ] || continue
[ "$d" = "/tests/tests" ] && continue
[ "$d" = "/tests/musl" ] && continue
[ "$d" = "/tests/glibc" ] && continue
add_scripts_in_dir "$d"
done
}

# 默认只跑 musl 分组,避免当前尚未完整支持的 glibc/Linux ABI 卡住启动链路。
# 后续支持 glibc 后,可在 rootfs 中设置 OSCOMP_TEST_LIBC=glibc 或 all 复用同一入口。
oscomp_test_libc="${OSCOMP_TEST_LIBC:-musl}"
[ "${OSCOMP_RUN_GLIBC:-0}" = "1" ] && oscomp_test_libc="all"

case "$oscomp_test_libc" in
musl|MUSL|"")
add_scripts_in_dir /tests/musl
if [ -d /tests/glibc ]; then
echo "[OSCOMP] glibc test scripts skipped; set OSCOMP_TEST_LIBC=glibc/all to enable"
fi
;;
glibc|GLIBC)
prepare_glibc_libs
add_scripts_in_dir /tests/glibc
;;
all|ALL|both|BOTH)
add_scripts_in_dir /tests
add_scripts_in_dir /tests/musl
prepare_glibc_libs
add_scripts_in_dir /tests/glibc
add_other_suite_scripts
;;
*)
echo "[OSCOMP] unknown OSCOMP_TEST_LIBC=$oscomp_test_libc; defaulting to musl"
add_scripts_in_dir /tests/musl
;;
esac
[ -n "$scripts" ] || return 1

echo "[OSCOMP] detected test scripts under /tests; running in rcS"
Expand Down
69 changes: 51 additions & 18 deletions data/risc-v_musl/etc/init.d/rcS
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,22 @@ run_oscomp_tests_if_present() {
# 检测到官方测试脚本就非交互地依次执行,跑完主动关机。
[ -d /tests ] || return 1

# 官方测试二进制硬编码了 ELF 解释器路径(如 /lib/ld-linux-*.so.*)。
# 我们是 musl rootfs,把测试镜像里的 glibc loader/库软链到 /lib 以便加载。
if [ -d /tests/glibc/lib ]; then
prepare_glibc_libs() {
# 官方 glibc 测试二进制硬编码了 ELF 解释器路径(如 /lib/ld-linux-*.so.*)。
# 默认先跑 musl 分组;后续支持 glibc 时再启用这段准备逻辑。
[ -d /tests/glibc/lib ] || return 0
[ -d /lib ] || /bin/mkdir -p /lib
for f in /tests/glibc/lib/ld-linux-*.so.*; do
[ -f "$f" ] || continue
base="${f##*/}"
/bin/ln -sf "$f" "/lib/$base"
[ -e "/lib/$base" ] || /bin/ln -s "$f" "/lib/$base"
done
for base in libc.so.6 libm.so.6 libpthread.so.0 libdl.so.2 librt.so.1 libresolv.so.2; do
if [ -f "/tests/glibc/lib/$base" ]; then
/bin/ln -sf "/tests/glibc/lib/$base" "/lib/$base"
[ -e "/lib/$base" ] || /bin/ln -s "/tests/glibc/lib/$base" "/lib/$base"
Comment thread
a6d9a6m marked this conversation as resolved.
Outdated
fi
done
fi
}

scripts=""
add_script() {
Expand All @@ -81,21 +82,53 @@ run_oscomp_tests_if_present() {
scripts="$scripts $1"
}

# 1) /tests 根下的脚本。
for f in /tests/*_testcode.sh; do
[ -f "$f" ] || continue
add_script "$f"
done

# 2) 下一层:/tests/*/*,匹配官方镜像布局 /tests/glibc/*.sh、/tests/musl/*.sh。
for d in /tests/*; do
[ -d "$d" ] || continue
[ "$d" = "/tests/tests" ] && continue
for f in "$d"/*_testcode.sh; do
add_scripts_in_dir() {
dir="$1"
[ -d "$dir" ] || return 0
for f in "$dir"/*_testcode.sh; do
[ -f "$f" ] || continue
add_script "$f"
done
done
}

add_other_suite_scripts() {
for d in /tests/*; do
[ -d "$d" ] || continue
[ "$d" = "/tests/tests" ] && continue
[ "$d" = "/tests/musl" ] && continue
[ "$d" = "/tests/glibc" ] && continue
add_scripts_in_dir "$d"
done
}

# 默认只跑 musl 分组,避免当前尚未完整支持的 glibc/Linux ABI 卡住启动链路。
# 后续支持 glibc 后,可在 rootfs 中设置 OSCOMP_TEST_LIBC=glibc 或 all 复用同一入口。
oscomp_test_libc="${OSCOMP_TEST_LIBC:-musl}"
[ "${OSCOMP_RUN_GLIBC:-0}" = "1" ] && oscomp_test_libc="all"

case "$oscomp_test_libc" in
musl|MUSL|"")
add_scripts_in_dir /tests/musl
if [ -d /tests/glibc ]; then
echo "[OSCOMP] glibc test scripts skipped; set OSCOMP_TEST_LIBC=glibc/all to enable"
fi
;;
glibc|GLIBC)
prepare_glibc_libs
add_scripts_in_dir /tests/glibc
;;
all|ALL|both|BOTH)
add_scripts_in_dir /tests
add_scripts_in_dir /tests/musl
prepare_glibc_libs
add_scripts_in_dir /tests/glibc
add_other_suite_scripts
;;
*)
echo "[OSCOMP] unknown OSCOMP_TEST_LIBC=$oscomp_test_libc; defaulting to musl"
add_scripts_in_dir /tests/musl
;;
esac
[ -n "$scripts" ] || return 1

echo "[OSCOMP] detected test scripts under /tests; running in rcS"
Expand Down
69 changes: 63 additions & 6 deletions os/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

use std::env;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::os::unix::fs::symlink;
use std::path::{Path, PathBuf};
use std::process::Command;

Expand Down Expand Up @@ -162,7 +164,11 @@ fn main() {

// 检查依赖
println!("cargo:rerun-if-changed={}", data_dir.display());
let dependencies = vec![data_dir.clone(), user_bin_dir];
let dependencies = vec![
data_dir.clone(),
user_bin_dir,
PathBuf::from(&manifest_dir).join("build.rs"),
];

let force_rebuild = match fs::read_to_string(&arch_stamp) {
Ok(saved) => saved.trim() != arch_key,
Expand Down Expand Up @@ -375,7 +381,24 @@ fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path)
);
}

// 3. 创建 /home/user/bin 目录并复制 user/bin
// 3. 预创建启动和评测需要的顶层目录,避免内核启动阶段写 rootfs。
for (dir, mode) in [
("dev", 0o755),
("proc", 0o755),
("sys", 0o755),
("tmp", 0o1777),
("tests", 0o755),
("lib", 0o755),
("lib64", 0o755),
] {
let path = temp_root.join(dir);
fs::create_dir_all(&path).unwrap_or_else(|_| panic!("Failed to create /{}", dir));
fs::set_permissions(&path, fs::Permissions::from_mode(mode))
.unwrap_or_else(|_| panic!("Failed to set permissions on /{}", dir));
}
create_glibc_runtime_symlinks(&temp_root);

// 4. 创建 /home/user/bin 目录并复制 user/bin
let home_user_bin = temp_root.join("home").join("user").join("bin");
fs::create_dir_all(&home_user_bin).expect("Failed to create home/user/bin");

Expand All @@ -385,7 +408,7 @@ fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path)
println!("cargo:warning=[build.rs] Copied user/bin to /home/user/bin");
}

// 4. 创建空镜像
// 5. 创建空镜像
let dd_status = Command::new("dd")
.arg("if=/dev/zero")
.arg(format!("of={}", path.display()))
Expand All @@ -400,13 +423,18 @@ fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path)
panic!("Failed to create disk image");
}

// 5. 使用 mkfs.ext4 -d 选项从临时目录创建文件系统
// 6. 使用 mkfs.ext4 -d 选项从临时目录创建文件系统。
// 保持 feature 集合保守,降低 ext4_rs 写路径和目录索引/校验特性的耦合。
let mkfs_status = Command::new("mkfs.ext4")
.arg("-F")
.arg("-b")
.arg("4096")
.arg("-m")
.arg("0")
.arg("-I")
.arg("256")
.arg("-O")
.arg("64bit,^has_journal,^resize_inode,^dir_index,^metadata_csum")
.arg("-d")
.arg(&temp_root) // 使用临时目录作为根
.arg(path)
Expand All @@ -419,10 +447,39 @@ fn create_full_ext4_image(path: &PathBuf, data_dir: &Path, project_root: &Path)
panic!("Failed to format ext4 image with data!");
}

// 6. 清理临时目录
// 7. 清理临时目录
fs::remove_dir_all(&temp_root).ok();

println!("cargo:warning=[build.rs] Full ext4 image created successfully (1GB).");
println!("cargo:warning=[build.rs] Full ext4 image created successfully (4GB).");
}

fn create_glibc_runtime_symlinks(temp_root: &Path) {
for name in [
"ld-linux-riscv64-lp64d.so.1",
"ld-linux-loongarch-lp64d.so.1",
"libc.so.6",
"libm.so.6",
"libpthread.so.0",
"libdl.so.2",
"librt.so.1",
"libresolv.so.2",
] {
for libdir in ["lib", "lib64"] {
let link_path = temp_root.join(libdir).join(name);
if link_path.exists() || link_path.is_symlink() {
continue;
}
let target = format!("/tests/glibc/lib/{}", name);
if let Err(e) = symlink(&target, &link_path) {
println!(
"cargo:warning=[build.rs] Failed to create symlink {} -> {}: {}",
link_path.display(),
target,
e
);
}
}
}
}

/// 递归复制目录
Expand Down
32 changes: 30 additions & 2 deletions os/src/fs/ext4/inode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,31 @@ impl Ext4Inode {
_ => InodeType::File,
}
}

fn read_fast_symlink_target(&self, size: usize) -> Result<Option<String>, FsError> {
const FAST_SYMLINK_MAX_LEN: usize = 15 * core::mem::size_of::<u32>();

if size > FAST_SYMLINK_MAX_LEN {
return Ok(None);
}

let fs = self.fs.lock();
let inode_ref = fs.get_inode_ref(self.ino);
let inode = &inode_ref.inode;
if inode.blocks_count() != 0 {
return Ok(None);
}

let mut buf = Vec::with_capacity(FAST_SYMLINK_MAX_LEN);
for block_word in inode.block {
buf.extend_from_slice(&block_word.to_le_bytes());
}
buf.truncate(size);

String::from_utf8(buf)
.map(Some)
.map_err(|_| FsError::InvalidArgument)
}
Comment thread
a6d9a6m marked this conversation as resolved.
}

impl Inode for Ext4Inode {
Expand Down Expand Up @@ -749,8 +774,11 @@ impl Inode for Ext4Inode {
return Ok(String::new());
}

// 读取符号链接目标
// 符号链接的目标存储在inode的数据区(与普通文件相同的方式)
if let Some(target) = self.read_fast_symlink_target(size)? {
return Ok(target);
}

// 读取长符号链接目标。短符号链接已在上面从 inode 的 i_block 内联区读取。
let fs = self.fs.lock();
let mut buf = alloc::vec![0u8; size];

Expand Down
11 changes: 3 additions & 8 deletions os/src/fs/sysfs/builders/kernel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use alloc::string::ToString;
use alloc::sync::Arc;

use crate::fs::sysfs::inode::{SysfsAttr, SysfsInode};
use crate::uapi::uts_namespace::{UTS_RELEASE, UTS_VERSION};
use crate::vfs::{FileMode, FsError, Inode};

/// 构建内核信息 sysfs 树
Expand All @@ -17,10 +18,7 @@ pub fn build_kernel_info(root: &Arc<SysfsInode>) -> Result<(), FsError> {
let version_attr = SysfsAttr {
name: "version".to_string(),
mode: FileMode::from_bits_truncate(0o444),
show: Arc::new(|| {
// TODO: 从内核配置获取编译时间
Ok("#1 SMP Mon Jan 1 00:00:00 UTC 2025\n".to_string())
}),
show: Arc::new(|| Ok(alloc::format!("{}\n", UTS_VERSION))),
store: None,
};
kernel_dir.add_child("version", SysfsInode::new_attribute(version_attr))?;
Expand All @@ -29,10 +27,7 @@ pub fn build_kernel_info(root: &Arc<SysfsInode>) -> Result<(), FsError> {
let osrelease_attr = SysfsAttr {
name: "osrelease".to_string(),
mode: FileMode::from_bits_truncate(0o444),
show: Arc::new(|| {
// TODO: 从内核配置获取版本号
Ok("0.1.0\n".to_string())
}),
show: Arc::new(|| Ok(alloc::format!("{}\n", UTS_RELEASE))),
store: None,
};
kernel_dir.add_child("osrelease", SysfsInode::new_attribute(osrelease_attr))?;
Expand Down
Loading
Loading