Skip to content

Commit da291e9

Browse files
committed
Change vfs::open syscall to an openat-like syscall + Fixed a bug in Dentry::create_and_fetch_file where the returned dentry was the parent and not the child
1 parent ea27dc3 commit da291e9

File tree

10 files changed

+105
-42
lines changed

10 files changed

+105
-42
lines changed

kernel/src/fs/ramfs/interface.rs

+21-12
Original file line numberDiff line numberDiff line change
@@ -451,9 +451,10 @@ fn readdir(
451451
offset: vfs::file::Offset,
452452
) -> Result<vfs::dirent::DirectoryEntry, vfs::file::ReaddirError> {
453453
let file_data = file
454-
.inode
454+
.dentry
455455
.as_ref()
456-
.expect("Open file without inode")
456+
.expect("Open file without dentry")
457+
.inode()
457458
.data
458459
.downcast_ref::<Spinlock<InodeDirectory>>()
459460
.expect("Inode is not a ramfs inode");
@@ -471,22 +472,26 @@ fn write(
471472
buf: &[u8],
472473
offset: vfs::file::Offset,
473474
) -> Result<usize, vfs::file::WriteError> {
474-
let file_data = file
475-
.inode
475+
let inode = file
476+
.dentry
476477
.as_ref()
477-
.expect("Open file without inode")
478+
.expect("Open file without dentry")
479+
.inode();
480+
let mut metadata = inode.state.lock();
481+
482+
let file_data = inode
478483
.data
479484
.downcast_ref::<Spinlock<InodeFile>>()
480485
.expect("Inode is not a ramfs inode");
486+
let mut locked_file = file_data.lock();
481487

482488
// Write the buffer to the file, and extend the file if necessary.
483-
let mut locked_file = file_data.lock();
484489
let content = locked_file.content_mut();
485490
let offset = offset.0;
486491

487492
if offset + buf.len() > content.len() {
488493
content.resize(offset + buf.len(), 0);
489-
file.inode.as_ref().unwrap().state.lock().size = content.len();
494+
metadata.size = content.len();
490495
}
491496

492497
// Write the buffer to the file and return the written size
@@ -500,15 +505,18 @@ fn read(
500505
buf: &mut [u8],
501506
offset: vfs::file::Offset,
502507
) -> Result<usize, vfs::file::ReadError> {
503-
let file_data = file
504-
.inode
508+
let inode = file
509+
.dentry
505510
.as_ref()
506-
.expect("Open file without inode")
511+
.expect("Open file without dentry")
512+
.inode();
513+
514+
let file_data = inode
507515
.data
508516
.downcast_ref::<Spinlock<InodeFile>>()
509517
.expect("Inode is not a ramfs inode");
510-
511518
let locked_file = file_data.lock();
519+
512520
let content = locked_file.content();
513521

514522
// Read the buffer from the file. If the read goes beyond the end of the
@@ -549,9 +557,10 @@ fn seek(
549557
}
550558
vfs::file::Whence::End => {
551559
let file_data = file
552-
.inode
560+
.dentry
553561
.as_ref()
554562
.expect("Open file without inode")
563+
.inode()
555564
.data
556565
.downcast_ref::<Spinlock<InodeFile>>()
557566
.expect("Inode is not a ramfs inode");

kernel/src/syscall/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ fn syscall(id: usize, a: usize, b: usize, c: usize, d: usize, e: usize) -> isize
9797
Some(Syscall::MmuMap) => mmu::map(a, b, c, d).map_err(Into::into),
9898
Some(Syscall::MmuUnmap) => mmu::unmap(a, b).map_err(Into::into),
9999
Some(Syscall::VideoFramebufferInfo) => video::framebuffer_info(a).map_err(Into::into),
100-
Some(Syscall::VfsOpen) => vfs::open(a, b).map_err(Into::into),
100+
Some(Syscall::VfsOpen) => vfs::open(a, b, c).map_err(Into::into),
101101
Some(Syscall::VfsClose) => vfs::close(a).map_err(Into::into),
102102
Some(Syscall::VfsRead) => vfs::read(a, b, c).map_err(Into::into),
103103
Some(Syscall::VfsWrite) => vfs::write(a, b, c).map_err(Into::into),

kernel/src/syscall/vfs.rs

+24-5
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,23 @@ use super::clock::Timespec;
1919
/// # Panics
2020
/// This function panics an inode does not have a corresponding superblock. This
2121
/// should never happen, and is a serious bug in the kernel if it does.
22-
pub fn open(path: usize, flags: usize) -> Result<usize, OpenError> {
22+
pub fn open(dir: usize, path: usize, flags: usize) -> Result<usize, OpenError> {
2323
let current_task = SCHEDULER.current_task();
2424
let root = current_task.root();
25-
let cwd = current_task.cwd();
25+
26+
// This is the dentry pointed by the file descriptor `dir`. If `dir` is
27+
// `AT_FDCWD`, the current working directory is used.
28+
let cwd = match dir {
29+
vfs::fd::Descriptor::AT_FDCWD => current_task.cwd(),
30+
_ => current_task
31+
.files()
32+
.lock()
33+
.get(vfs::fd::Descriptor(dir))
34+
.ok_or(OpenError::BadFileDescriptor)?
35+
.dentry
36+
.clone()
37+
.ok_or(OpenError::NotADirectory)?,
38+
};
2639

2740
let flags = vfs::file::OpenFlags::from_bits(flags).ok_or(OpenError::InvalidFlag)?;
2841
let ptr = user::Pointer::<SyscallString>::from_usize(path).ok_or(OpenError::BadAddress)?;
@@ -59,13 +72,16 @@ pub fn open(path: usize, flags: usize) -> Result<usize, OpenError> {
5972
}
6073

6174
let name = path.as_name().ok_or(OpenError::NoSuchFile)?.clone();
62-
Dentry::create_and_fetch_file(parent, name)?
75+
Dentry::create_and_fetch_file(&parent, name)?
6376
} else {
6477
return Err(OpenError::from(e));
6578
}
6679
}
6780
};
6881

82+
log::debug!("Opening file inode id {}", dentry.inode().id.0);
83+
log::debug!("name: {:?}", dentry.name());
84+
6985
let file = dentry.open(flags)?;
7086
let id = current_task
7187
.files()
@@ -85,6 +101,9 @@ pub enum OpenError {
85101
/// An invalid address was passed as an argument
86102
BadAddress,
87103

104+
/// An invalid file descriptor was passed as an argument
105+
BadFileDescriptor,
106+
88107
/// The path is invalid
89108
InvalidPath,
90109

@@ -338,8 +357,8 @@ pub fn write(fd: usize, buf: usize, len: usize) -> Result<usize, WriteError> {
338357

339358
// If the file is associated with an inode, mark it as dirty since the inode
340359
// may has been modified
341-
if let Some(inode) = &file.inode {
342-
inode.mark_dirty();
360+
if let Some(dentry) = &file.dentry {
361+
dentry.dirtying_inode();
343362
}
344363

345364
state.offset = offset;

kernel/src/vfs/dentry.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ impl Dentry {
5757
/// # Errors
5858
/// Currently, this function does not return any error. However, this may change
5959
/// in the future.
60-
pub fn open(&self, flags: OpenFlags) -> Result<File, OpenError> {
60+
pub fn open(self: &Arc<Self>, flags: OpenFlags) -> Result<File, OpenError> {
6161
Ok(file::File::new(FileCreateInfo {
6262
operation: self.inode.file_ops.clone(),
63-
inode: Some(self.inode.clone()),
63+
dentry: Some(self.clone()),
6464
open_flags: flags,
6565
data: Box::new(()),
6666
}))
@@ -190,12 +190,12 @@ impl Dentry {
190190
/// if this function fails to connect the created dentry to this dentry. This should
191191
/// never happen and is a serious kernel bug.
192192
pub fn create_and_fetch_file(
193-
dentry: Arc<Self>,
193+
dentry: &Arc<Self>,
194194
name: Name,
195195
) -> Result<Arc<Self>, CreateFetchError> {
196196
// Search for the file in the dentry cache and in the underlying filesystem.
197197
// If a file with the same name already exists, return an error.
198-
match Self::fetch(&dentry, &name) {
198+
match Self::fetch(dentry, &name) {
199199
Err(FetchError::NotFound) => {}
200200
Err(FetchError::NotADirectory) => return Err(CreateFetchError::NotADirectory),
201201
Err(FetchError::IoError) => return Err(CreateFetchError::IoError),
@@ -219,10 +219,10 @@ impl Dentry {
219219

220220
// If an entry with the same name was created in the meantime, we
221221
// simply return an error.
222-
match Self::connect_child(&dentry, child) {
222+
match Self::connect_child(dentry, Arc::clone(&child)) {
223223
Err(ConnectError::AlreadyConnected | ConnectError::NotADirectory) => unreachable!(),
224224
Err(ConnectError::AlreadyExists) => Err(CreateFetchError::AlreadyExists),
225-
Ok(_) => Ok(dentry),
225+
Ok(_) => Ok(child),
226226
}
227227
}
228228

@@ -349,12 +349,6 @@ impl Dentry {
349349
}
350350
}
351351

352-
impl Drop for Dentry {
353-
fn drop(&mut self) {
354-
log::debug!("Dentry dropped: {:?}", self.name());
355-
}
356-
}
357-
358352
/// Represents a dentry in the filesystem tree. This structure is used to
359353
/// contains fields that can be modified by the filesystem driver, like the
360354
/// children list or the dentr name. The [`Dentry`] structure contains fields

kernel/src/vfs/fd.rs

+15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ use super::file::File;
55
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
66
pub struct Descriptor(pub usize);
77

8+
impl Descriptor {
9+
pub const AT_FDCWD_DESCRIPTOR: Self = Self(Self::AT_FDCWD);
10+
pub const AT_FDCWD: usize = usize::MAX;
11+
12+
/// Create a new file descriptor from the given file descriptor number. If
13+
/// the number is `AT_FDCWD`, returns `None`, otherwise returns `Some`.
14+
#[must_use]
15+
pub const fn new(fd: usize) -> Option<Self> {
16+
match fd {
17+
Self::AT_FDCWD => None,
18+
_ => Some(Self(fd)),
19+
}
20+
}
21+
}
22+
823
/// A table of opened files. This is a simple array of 32 elements, where each
924
/// element is an optional reference to an opened file.
1025
///

kernel/src/vfs/file.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use super::{dirent::DirectoryEntry, inode::Inode};
1+
use super::{dentry::Dentry, dirent::DirectoryEntry};
22
use core::any::Any;
33

44
#[derive(Debug)]
55
pub struct File {
66
/// The inode opened by this file.
7-
pub inode: Option<Arc<Inode>>,
7+
pub dentry: Option<Arc<Dentry>>,
88

99
/// The operation table for this file.
1010
pub operation: Operation,
@@ -26,7 +26,7 @@ impl File {
2626
pub fn new(info: FileCreateInfo) -> Self {
2727
let state = OpenFileState { offset: Offset(0) };
2828
Self {
29-
inode: info.inode,
29+
dentry: info.dentry,
3030
operation: info.operation,
3131
open_flags: info.open_flags,
3232
state: Spinlock::new(state),
@@ -53,7 +53,7 @@ impl File {
5353

5454
#[derive(Debug)]
5555
pub struct FileCreateInfo {
56-
pub inode: Option<Arc<Inode>>,
56+
pub dentry: Option<Arc<Dentry>>,
5757
pub operation: Operation,
5858
pub open_flags: OpenFlags,
5959
pub data: Box<dyn Any + Send + Sync>,

kernel/src/vfs/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ fn fill_ramdisk() {
7878

7979
bitflags::bitflags! {
8080
/// Flags to control the behavior of the lookup operation.
81+
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
8182
pub struct LookupFlags: u32 {
8283
/// Return the parent of the last component of the path. If the path has
8384
/// only one component, return the parent of the current directory. If the
@@ -169,9 +170,10 @@ pub fn read_all(
169170
.map_err(|_| ReadAllError::OpenError)?;
170171

171172
let len = file
172-
.inode
173+
.dentry
173174
.as_ref()
174-
.expect("Regular open file without inode")
175+
.expect("Regular open file without dentry")
176+
.inode()
175177
.state
176178
.lock()
177179
.size;

kernel/src/vfs/pipe/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,14 @@ fn create_pair() -> (Arc<file::File>, Arc<file::File>) {
124124
operation: file::Operation::File(&PIPE_FILE_OPS),
125125
open_flags: file::OpenFlags::READ,
126126
data: Box::new(reader),
127-
inode: None,
127+
dentry: None,
128128
}));
129129

130130
let writer_file = Arc::new(file::File::new(file::FileCreateInfo {
131131
operation: file::Operation::File(&PIPE_FILE_OPS),
132132
open_flags: file::OpenFlags::WRITE,
133133
data: Box::new(writer),
134-
inode: None,
134+
dentry: None,
135135
}));
136136

137137
(reader_file, writer_file)

user/shell/src/main.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use syscall::vfs::FileDescriptor;
2+
13
fn main() {
24
println!("Creating /test");
35
syscall::vfs::mkdir("/test").expect("mkdir failed");
@@ -42,7 +44,13 @@ fn main() {
4244
syscall::vfs::mkdir("/test").expect("mkdir failed");
4345

4446
println!("Adding /test/test.txt");
45-
syscall::vfs::open("/test/test.txt", syscall::vfs::O_CREATE, 0).expect("open failed");
47+
syscall::vfs::open(
48+
FileDescriptor::AT_FDCWD,
49+
"/test/test.txt",
50+
syscall::vfs::O_CREATE,
51+
0,
52+
)
53+
.expect("open failed");
4654

4755
println!("Trying to removing /test");
4856
match syscall::vfs::rmdir("/test") {

user/syscall/src/vfs.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ pub const O_EXCL: usize = 1 << 4;
1111
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1212
pub struct FileDescriptor(usize);
1313

14+
impl FileDescriptor {
15+
pub const STDIN: Self = Self(0);
16+
pub const STDOUT: Self = Self(1);
17+
pub const STDERR: Self = Self(2);
18+
pub const AT_FDCWD: Self = Self(usize::MAX);
19+
}
20+
1421
pub enum Whence {
1522
Current(isize),
1623
Start(isize),
@@ -70,6 +77,9 @@ pub enum OpenError {
7077
/// An invalid address was passed as an argument
7178
BadAddress,
7279

80+
/// An invalid file descriptor was passed as an argument
81+
BadFileDescriptor,
82+
7383
/// The path is invalid
7484
InvalidPath,
7585

@@ -562,16 +572,22 @@ impl From<Errno> for UnlinkError {
562572
///
563573
/// # Errors
564574
/// See `OpenError` for a list of possible errors.
565-
pub fn open(path: &str, flags: usize, _mode: usize) -> Result<FileDescriptor, OpenError> {
575+
pub fn open(
576+
dir: FileDescriptor,
577+
path: &str,
578+
flags: usize,
579+
_mode: usize,
580+
) -> Result<FileDescriptor, OpenError> {
566581
let str = SyscallString::from(path);
567582
let ret;
568583

569584
unsafe {
570585
core::arch::asm!(
571586
"syscall",
572587
in("rax") Syscall::VfsOpen as u64,
573-
in("rsi") &str as *const _ as u64,
574-
in("rdx") flags as u64,
588+
in("rsi") dir.0,
589+
in("rdx") &str as *const _ as u64,
590+
in("r10") flags,
575591
lateout("rax") ret,
576592
);
577593
}

0 commit comments

Comments
 (0)