Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(time): Add syscall support for utime* #838

Merged
merged 3 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion kernel/src/arch/x86_64/pci/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::init::initcall::INITCALL_SUBSYS;
use crate::mm::PhysAddr;

use acpi::mcfg::Mcfg;
use log::{error, warn};
use log::warn;
use system_error::SystemError;
use unified_init::macros::unified_init;

Expand Down
10 changes: 10 additions & 0 deletions kernel/src/filesystem/fat/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1472,6 +1472,16 @@ impl IndexNode for LockedFATInode {
fn metadata(&self) -> Result<Metadata, SystemError> {
return Ok(self.0.lock().metadata.clone());
}
fn set_metadata(&self, metadata: &Metadata) -> Result<(), SystemError> {
let inode = &mut self.0.lock();
inode.metadata.atime = metadata.atime;
inode.metadata.mtime = metadata.mtime;
inode.metadata.ctime = metadata.ctime;
inode.metadata.mode = metadata.mode;
inode.metadata.uid = metadata.uid;
inode.metadata.gid = metadata.gid;
Ok(())
}
fn resize(&self, len: usize) -> Result<(), SystemError> {
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
let fs: &Arc<FATFileSystem> = &guard.fs.upgrade().unwrap();
Expand Down
93 changes: 88 additions & 5 deletions kernel/src/filesystem/vfs/open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ use alloc::sync::Arc;
use log::warn;
use system_error::SystemError;

use crate::{
driver::base::block::SeekFrom, process::ProcessManager,
syscall::user_access::check_and_clone_cstr,
};

use super::{
fcntl::AtFlags,
file::{File, FileMode},
syscall::{ModeType, OpenHow, OpenHowResolve},
utils::{rsplit_path, user_path_at},
FileType, IndexNode, MAX_PATHLEN, ROOT_INODE, VFS_MAX_FOLLOW_SYMLINK_TIMES,
};
use crate::filesystem::vfs::syscall::UtimensFlags;
use crate::time::{syscall::PosixTimeval, PosixTimeSpec};
use crate::{
driver::base::block::SeekFrom, process::ProcessManager,
syscall::user_access::check_and_clone_cstr,
};
use alloc::string::String;

pub(super) fn do_faccessat(
dirfd: i32,
Expand Down Expand Up @@ -147,3 +149,84 @@ fn do_sys_openat2(

return r;
}

/// On Linux, futimens() is a library function implemented on top of
/// the utimensat() system call. To support this, the Linux
/// utimensat() system call implements a nonstandard feature: if
/// pathname is NULL, then the call modifies the timestamps of the
/// file referred to by the file descriptor dirfd (which may refer to
/// any type of file).
pub fn do_utimensat(
dirfd: i32,
pathname: Option<String>,
times: Option<[PosixTimeSpec; 2]>,
flags: UtimensFlags,
) -> Result<usize, SystemError> {
const UTIME_NOW: i64 = (1i64 << 30) - 1i64;
const UTIME_OMIT: i64 = (1i64 << 30) - 2i64;
// log::debug!("do_utimensat: dirfd:{}, pathname:{:?}, times:{:?}, flags:{:?}", dirfd, pathname, times, flags);
let inode = match pathname {
Some(path) => {
let (inode_begin, path) =
user_path_at(&ProcessManager::current_pcb(), dirfd, path.as_str())?;
let inode = if flags.contains(UtimensFlags::AT_SYMLINK_NOFOLLOW) {
inode_begin.lookup(path.as_str())?
} else {
inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?
};
inode
}
None => {
let binding = ProcessManager::current_pcb().fd_table();
let fd_table_guard = binding.write();
let file = fd_table_guard
.get_file_by_fd(dirfd)
.ok_or(SystemError::EBADF)?;
file.inode()
}
};
let now = PosixTimeSpec::now();
let mut meta = inode.metadata()?;

if let Some([atime, mtime]) = times {
if atime.tv_nsec == UTIME_NOW {
meta.atime = now;
} else if atime.tv_nsec != UTIME_OMIT {
meta.atime = atime;
}
if mtime.tv_nsec == UTIME_NOW {
meta.mtime = now;
} else if mtime.tv_nsec != UTIME_OMIT {
meta.mtime = mtime;
}
inode.set_metadata(&meta).unwrap();
} else {
meta.atime = now;
meta.mtime = now;
inode.set_metadata(&meta).unwrap();
}
return Ok(0);
}

pub fn do_utimes(path: &str, times: Option<[PosixTimeval; 2]>) -> Result<usize, SystemError> {
// log::debug!("do_utimes: path:{:?}, times:{:?}", path, times);
let (inode_begin, path) = user_path_at(
&ProcessManager::current_pcb(),
AtFlags::AT_FDCWD.bits(),
path,
)?;
let inode = inode_begin.lookup_follow_symlink(path.as_str(), VFS_MAX_FOLLOW_SYMLINK_TIMES)?;
let mut meta = inode.metadata()?;

if let Some([atime, mtime]) = times {
meta.atime = PosixTimeSpec::from(atime);
meta.mtime = PosixTimeSpec::from(mtime);
inode.set_metadata(&meta)?;
} else {
let now = PosixTimeSpec::now();
meta.atime = now;
meta.mtime = now;
inode.set_metadata(&meta)?;
}
return Ok(0);
}
49 changes: 47 additions & 2 deletions kernel/src/filesystem/vfs/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ use crate::{
user_access::{self, check_and_clone_cstr, UserBufferWriter},
Syscall,
},
time::PosixTimeSpec,
time::{syscall::PosixTimeval, PosixTimeSpec},
};

use super::{
core::{do_mkdir_at, do_remove_dir, do_unlink_at},
fcntl::{AtFlags, FcntlCommand, FD_CLOEXEC},
file::{File, FileMode},
open::{do_faccessat, do_fchmodat, do_sys_open},
open::{do_faccessat, do_fchmodat, do_sys_open, do_utimensat, do_utimes},
utils::{rsplit_path, user_path_at},
Dirent, FileType, IndexNode, SuperBlock, FSMAKER, MAX_PATHLEN, ROOT_INODE,
VFS_MAX_FOLLOW_SYMLINK_TIMES,
Expand Down Expand Up @@ -323,6 +323,13 @@ bitflags! {
}
}

bitflags! {
pub struct UtimensFlags: u32 {
/// 不需要解释符号链接
const AT_SYMLINK_NOFOLLOW = 0x100;
}
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct PosixStatfs {
Expand Down Expand Up @@ -1620,6 +1627,44 @@ impl Syscall {
)?;
return Ok(());
}

pub fn sys_utimensat(
dirfd: i32,
pathname: *const u8,
times: *const PosixTimeSpec,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里传入的裸指针需要像其他的系统调用那样,用userbuffer结构体去校验合法性&读写

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

flags: u32,
) -> Result<usize, SystemError> {
let pathname = if pathname.is_null() {
None
} else {
let pathname = check_and_clone_cstr(pathname, Some(MAX_PATHLEN))?;
Some(pathname)
};
let flags = UtimensFlags::from_bits(flags).ok_or(SystemError::EINVAL)?;
let times = if times.is_null() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感觉好像不用判断空的,因为如果空指针的话userbuffer会报错

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里是允许times为空的

None
} else {
let atime = unsafe { times.read() };
let mtime = unsafe { times.add(1).read() };
Some([atime, mtime])
};
do_utimensat(dirfd, pathname, times, flags)
}

pub fn sys_utimes(
pathname: *const u8,
times: *const PosixTimeval,
) -> Result<usize, SystemError> {
let pathname = check_and_clone_cstr(pathname, Some(MAX_PATHLEN))?;
let times = if times.is_null() {
None
} else {
let atime = unsafe { times.read() };
let mtime = unsafe { times.add(1).read() };
Some([atime, mtime])
};
do_utimes(&pathname, times)
}
}

#[repr(C)]
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#[cfg(test)]
#[macro_use]
extern crate std;

#[cfg(target_os = "none")]
Chiichen marked this conversation as resolved.
Show resolved Hide resolved
use core::panic::PanicInfo;

/// 导出x86_64架构相关的代码,命名为arch模块
Expand Down Expand Up @@ -87,7 +87,7 @@ extern crate uefi;
extern crate uefi_raw;

use crate::mm::allocator::kernel_allocator::KernelAllocator;

#[cfg(target_os = "none")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这两个#[cfg(target_os = "none")]的作用是什么,kernel会有非none的target_os吗

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

panic函数的实现带有#[cfg(target_os = "none")], 而这里的ProcessManager是在panic函数中使用,为什么不使用这个条件编译呢

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

但是target_os = "none"这个条件在kernel里是恒为真的,你加不加都不会产生实质影响

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这是为了消除cargo clippy的一个warning,确实是加不加都可以

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这是为了消除cargo clippy的一个warning,确实是加不加都可以

那我觉得就没必要硬加了,确实有warning的话把这个lint禁掉吧

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

use crate::process::ProcessManager;

#[cfg(all(feature = "backtrace", target_arch = "x86_64"))]
Expand Down
21 changes: 19 additions & 2 deletions kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::{
filesystem::vfs::{
fcntl::{AtFlags, FcntlCommand},
file::FileMode,
syscall::{ModeType, PosixKstat},
syscall::{ModeType, PosixKstat, UtimensFlags},
MAX_PATHLEN,
},
libs::align::page_align_up,
Expand Down Expand Up @@ -1103,7 +1103,24 @@ impl Syscall {

Self::shmctl(id, cmd, user_buf, from_user)
}

SYS_UTIMENSAT => Self::sys_utimensat(
args[0] as i32,
args[1] as *const u8,
args[2] as *const PosixTimeSpec,
args[3] as u32,
),
#[cfg(target_arch = "x86_64")]
SYS_FUTIMESAT => {
let flags = UtimensFlags::empty();
Self::sys_utimensat(
args[0] as i32,
args[1] as *const u8,
args[2] as *const PosixTimeSpec,
flags.bits(),
)
}
#[cfg(target_arch = "x86_64")]
SYS_UTIMES => Self::sys_utimes(args[0] as *const u8, args[1] as *const PosixTimeval),
Comment on lines +1112 to +1123
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里条件编译的作用是什么,如果是架构特有的系统调用应该放在arch/<x86/riscv>/syscall下,不用条件编译

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

其它的系统调用不也是使用这种条件编译的方式吗?arch/<x86/riscv>/syscall目录不是系统调用实现的存放位置吧

Copy link
Member

@Chiichen Chiichen Jun 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有两种情况,一种情况是这个系统调用是架构相关的,比如 SYS_RT_SIGRETURN,第二种情况是定义的系统调用是通用的系统调用,条件编译是因为目前只有X86下有实现,但是系统调用本身是架构无关的。你这两个系统调用SYS_UTIMENSAT 和 SYS_FUTIMESAT,在都是一个逻辑Self::sys_utimensat,但是一个条件编译一个不条件编译,所以才想知道你写条件编译的目的

_ => panic!("Unsupported syscall ID: {}", syscall_num),
};

Expand Down
10 changes: 10 additions & 0 deletions kernel/src/time/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use core::{
};

use crate::arch::CurrentTimeArch;
use crate::time::syscall::PosixTimeval;

use self::timekeeping::getnstimeofday;

Expand Down Expand Up @@ -114,6 +115,15 @@ impl From<Duration> for PosixTimeSpec {
}
}

impl From<PosixTimeval> for PosixTimeSpec {
fn from(value: PosixTimeval) -> Self {
PosixTimeSpec {
tv_sec: value.tv_sec,
tv_nsec: value.tv_usec as i64 * 1000,
}
}
}

impl From<PosixTimeSpec> for Duration {
fn from(val: PosixTimeSpec) -> Self {
Duration::from_micros(val.tv_sec as u64 * 1000000 + val.tv_nsec as u64 / 1000)
Expand Down
1 change: 1 addition & 0 deletions user/apps/test_utimensat/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test_utimensat
20 changes: 20 additions & 0 deletions user/apps/test_utimensat/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
ifeq ($(ARCH), x86_64)
CROSS_COMPILE=x86_64-linux-musl-
else ifeq ($(ARCH), riscv64)
CROSS_COMPILE=riscv64-linux-musl-
endif

CC=$(CROSS_COMPILE)gcc

.PHONY: all
all: main.c
$(CC) -static -o test_utimensat main.c

.PHONY: install clean
install: all
mv test_utimensat $(DADK_CURRENT_BUILD_DIR)/test_utimensat

clean:
rm test_utimensat *.o

fmt:
12 changes: 12 additions & 0 deletions user/apps/test_utimensat/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>


int main(){
int res = utimensat(AT_FDCWD, "/bin/about.elf", NULL, 0);
printf("utimensat res = %d\n", res);
}
23 changes: 23 additions & 0 deletions user/dadk/config/test_utimensat_0_1_0.dadk
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "test_utimensat",
"version": "0.1.0",
"description": "test_utimensat",
"task_type": {
"BuildFromSource": {
"Local": {
"path": "apps/test_utimensat"
}
}
},
"depends": [],
"build": {
"build_command": "make install"
},
"install": {
"in_dragonos_path": "/bin"
},
"clean": {
"clean_command": "make clean"
},
"target_arch": ["x86_64"]
}
Loading