Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 10 additions & 1 deletion .github/workflows/dunitest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ jobs:
dunitest:
name: Dunitest
runs-on: ubuntu-latest
timeout-minutes: 30
# Allow the 30-minute guest test budget plus build, cleanup, and diagnostics.
timeout-minutes: 50
container:
image: dragonos/dragonos-dev:v1.23
options: --privileged -v /dev:/dev
Expand All @@ -41,3 +42,11 @@ jobs:
DISK_SAVE_MODE: "1"
run: |
make test-dunit

- name: Preserve dunitest serial log
if: always()
uses: actions/upload-artifact@v4
with:
name: dunitest-serial-x86_64-${{ github.run_id }}-${{ github.run_attempt }}
path: serial_opt.txt
if-no-files-found: error
11 changes: 10 additions & 1 deletion .github/workflows/test-x86.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ jobs:
integration-test:
name: Integration Test
runs-on: ubuntu-latest
timeout-minutes: 60
# Allow the 50-minute guest test budget plus build, cleanup, and diagnostics.
timeout-minutes: 75
container:
image: dragonos/dragonos-dev:v1.23
options: --privileged -v /dev:/dev
Expand All @@ -42,6 +43,14 @@ jobs:
run: |
make test-syscall

- name: Preserve syscall serial log
if: always()
uses: actions/upload-artifact@v4
with:
name: gvisor-serial-x86_64-${{ github.run_id }}-${{ github.run_attempt }}
path: serial_opt.txt
if-no-files-found: error

- name: Upload test results
if: always() && github.repository == 'DragonOS-Community/DragonOS'
shell: bash -ileo pipefail {0}
Expand Down
15 changes: 13 additions & 2 deletions kernel/crates/another_ext4/src/ext4/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,9 +400,14 @@ impl Ext4 {
self.transaction_stage_super_block(transaction, &sb)
}

/// Create a new inode, returning the inode and its number
/// Create a new inode with its final owner, returning the inode and its number.
#[inline(never)]
pub(super) fn create_inode(&self, mode: InodeMode) -> Result<InodeRef> {
pub(super) fn create_inode_with_owner(
&self,
mode: InodeMode,
uid: u32,
gid: u32,
) -> Result<InodeRef> {
self.ensure_mutable()?;
// Allocate an inode
let is_dir = mode.file_type() == FileType::Directory;
Expand All @@ -413,6 +418,8 @@ impl Ext4 {
let mut inode = Box::new(Inode::default());
inode.set_generation(generation);
inode.set_mode(mode);
inode.set_uid(uid);
inode.set_gid(gid);
inode.extent_init();
let mut inode_ref = InodeRef::new(id, inode);
self.write_inode_with_csum(&mut inode_ref)?;
Expand Down Expand Up @@ -443,6 +450,8 @@ impl Ext4 {
mode: InodeMode,
major: u32,
minor: u32,
uid: u32,
gid: u32,
) -> Result<InodeRef> {
self.ensure_mutable()?;
// Device nodes are never directories
Expand All @@ -453,6 +462,8 @@ impl Ext4 {
let mut inode = Box::new(Inode::default());
inode.set_generation(generation);
inode.set_mode(mode);
inode.set_uid(uid);
inode.set_gid(gid);
inode.set_device(major, minor);
let mut inode_ref = InodeRef::new(id, inode);
self.write_inode_with_csum(&mut inode_ref)?;
Expand Down
151 changes: 140 additions & 11 deletions kernel/crates/another_ext4/src/ext4/low_level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ pub struct SetAttr {
pub crtime: Option<u32>,
}

#[derive(Clone, Copy)]
pub struct InodeOwner {
pub uid: u32,
pub gid: u32,
}

impl SetAttr {
/// Create a new SetAttr struct with all fields set to None.
pub fn new() -> Self {
Expand Down Expand Up @@ -270,15 +276,19 @@ impl Ext4 {
return_error!(ErrCode::EINVAL, "Invalid inode {}", id);
}

Ok(Self::file_attr(&inode))
}

fn file_attr(inode: &InodeRef) -> FileAttr {
// Get device number for device nodes
let rdev = if inode.inode.is_device() {
inode.inode.device()
} else {
(0, 0)
};

Ok(FileAttr {
ino: id,
FileAttr {
ino: inode.id,
size: inode.inode.size(),
blocks: inode.inode.block_count(),
atime: inode.inode.atime(),
Expand All @@ -291,7 +301,7 @@ impl Ext4 {
uid: inode.inode.uid(),
gid: inode.inode.gid(),
rdev,
})
}
}

/// Set file attributes.
Expand Down Expand Up @@ -486,6 +496,7 @@ impl Ext4 {
&self,
id: InodeId,
size: Option<u64>,
atime: Option<u32>,
mtime: Option<u32>,
) -> Result<()> {
self.ensure_mutable()?;
Expand All @@ -498,6 +509,9 @@ impl Ext4 {
if let Some(size) = size {
inode.inode.set_size(size);
}
if let Some(atime) = atime {
inode.inode.set_atime(atime);
}
if let Some(mtime) = mtime {
inode.inode.set_mtime(mtime);
}
Expand All @@ -510,7 +524,7 @@ impl Ext4 {
///
/// Call this after successful page-cache write to finalise the new file size.
pub fn commit_inode_size(&self, id: InodeId, size: u64, mtime: Option<u32>) -> Result<()> {
self.commit_inode_metadata(id, Some(size), mtime)
self.commit_inode_metadata(id, Some(size), None, mtime)
}

/// Link a newly created inode into `parent`.
Expand Down Expand Up @@ -557,6 +571,30 @@ impl Ext4 {
/// * `ENOTDIR` - `parent` is not a directory
/// * `ENOSPC` - No space left on device
pub fn create(&self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
self.create_with_owner(parent, name, mode, InodeOwner { uid: 0, gid: 0 })
}

pub fn create_with_owner(
&self,
parent: InodeId,
name: &str,
mode: InodeMode,
owner: InodeOwner,
) -> Result<InodeId> {
Ok(self
.create_with_owner_and_attr(parent, name, mode, owner)?
.ino)
}

/// Create and link a file, returning the attributes from the authoritative
/// in-memory inode used by the namespace transaction.
pub fn create_with_owner_and_attr(
&self,
parent: InodeId,
name: &str,
mode: InodeMode,
owner: InodeOwner,
) -> Result<FileAttr> {
self.ensure_mutable()?;
let _metadata_guard = self.lock_direct_metadata_mutation()?;
let _namespace_guard = self.namespace_lock.lock();
Expand All @@ -567,10 +605,9 @@ impl Ext4 {
return_error!(ErrCode::ENOTDIR, "Inode {} is not a directory", parent.id);
}
// Create child inode and link it to parent directory
let mut child = self.create_inode(mode)?;
let mut child = self.create_inode_with_owner(mode, owner.uid, owner.gid)?;
self.link_new_inode_or_free(&mut parent, &mut child, name)?;
// Create file handler
Ok(child.id)
Ok(Self::file_attr(&child))
}

/// Create a device node (character or block device).
Expand Down Expand Up @@ -603,6 +640,41 @@ impl Ext4 {
major: u32,
minor: u32,
) -> Result<InodeId> {
self.mknod_with_owner(
parent,
name,
mode,
major,
minor,
InodeOwner { uid: 0, gid: 0 },
)
}

pub fn mknod_with_owner(
&self,
parent: InodeId,
name: &str,
mode: InodeMode,
major: u32,
minor: u32,
owner: InodeOwner,
) -> Result<InodeId> {
Ok(self
.mknod_with_owner_and_attr(parent, name, mode, major, minor, owner)?
.ino)
}

/// Create and link a device node, returning the attributes from the
/// authoritative in-memory inode used by the namespace transaction.
pub fn mknod_with_owner_and_attr(
&self,
parent: InodeId,
name: &str,
mode: InodeMode,
major: u32,
minor: u32,
owner: InodeOwner,
) -> Result<FileAttr> {
self.ensure_mutable()?;
let _metadata_guard = self.lock_direct_metadata_mutation()?;
let _namespace_guard = self.namespace_lock.lock();
Expand All @@ -619,13 +691,13 @@ impl Ext4 {
}

// Create device inode (uses create_device_inode which sets device number)
let mut child = self.create_device_inode(mode, major, minor)?;
let mut child = self.create_device_inode(mode, major, minor, owner.uid, owner.gid)?;

// Link to parent directory
self.link_new_inode_or_free(&mut parent_ref, &mut child, name)?;

trace!("mknod {} ({}:{}) -> inode {}", name, major, minor, child.id);
Ok(child.id)
Ok(Self::file_attr(&child))
}

/// Read data from a file. This function will read exactly `buf.len()`
Expand Down Expand Up @@ -1404,6 +1476,30 @@ impl Ext4 {
/// * `ENOTDIR` - `parent` is not a directory
/// * `ENOSPC` - no space left on device
pub fn mkdir(&self, parent: InodeId, name: &str, mode: InodeMode) -> Result<InodeId> {
self.mkdir_with_owner(parent, name, mode, InodeOwner { uid: 0, gid: 0 })
}

pub fn mkdir_with_owner(
&self,
parent: InodeId,
name: &str,
mode: InodeMode,
owner: InodeOwner,
) -> Result<InodeId> {
Ok(self
.mkdir_with_owner_and_attr(parent, name, mode, owner)?
.ino)
}

/// Create and link a directory, returning the attributes from the
/// authoritative in-memory inode used by the namespace transaction.
pub fn mkdir_with_owner_and_attr(
&self,
parent: InodeId,
name: &str,
mode: InodeMode,
owner: InodeOwner,
) -> Result<FileAttr> {
self.ensure_mutable()?;
let _metadata_guard = self.lock_direct_metadata_mutation()?;
let _namespace_guard = self.namespace_lock.lock();
Expand All @@ -1415,7 +1511,7 @@ impl Ext4 {
}
// Create file/directory
let mode = mode & InodeMode::PERM_MASK | InodeMode::DIRECTORY;
let mut child = self.create_inode(mode)?;
let mut child = self.create_inode_with_owner(mode, owner.uid, owner.gid)?;
// Add "." entry
let child_self = child.clone();
if let Err(error) = self.dir_add_entry(&mut child, &child_self, ".") {
Expand All @@ -1427,7 +1523,7 @@ impl Ext4 {
child.inode.set_link_count(1);
// Link the new inode
self.link_new_inode_or_free(&mut parent, &mut child, name)?;
Ok(child.id)
Ok(Self::file_attr(&child))
}

/// Look up a directory entry by name.
Expand Down Expand Up @@ -1705,6 +1801,39 @@ mod tests {
use crate::FileType;
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

#[test]
fn file_attr_is_derived_from_the_authoritative_in_memory_inode() {
let mut inode = Box::new(Inode::default());
inode.set_mode(InodeMode::CHARDEV | InodeMode::from_bits_retain(0o640));
inode.set_uid(0x12345);
inode.set_gid(0x23456);
inode.set_size(0x1_0000_0020);
inode.set_block_count(17);
inode.set_atime(11);
inode.set_mtime(12);
inode.set_ctime(13);
inode.set_crtime(14);
inode.set_link_count(2);
inode.set_device(259, 0x1_0002);
let inode = InodeRef::new(42, inode);

let attr = Ext4::file_attr(&inode);

assert_eq!(attr.ino, 42);
assert_eq!(attr.ftype, FileType::CharacterDev);
assert_eq!(attr.perm.bits(), 0o640);
assert_eq!(attr.uid, 0x12345);
assert_eq!(attr.gid, 0x23456);
assert_eq!(attr.size, 0x1_0000_0020);
assert_eq!(attr.blocks, 17);
assert_eq!(
(attr.atime, attr.mtime, attr.ctime, attr.crtime),
(11, 12, 13, 14)
);
assert_eq!(attr.links, 2);
assert_eq!(attr.rdev, (259, 0x1_0002));
}

struct StubBlockDevice {
sb_block: Block,
}
Expand Down
2 changes: 1 addition & 1 deletion kernel/crates/another_ext4/src/ext4/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mod orphan;
mod rw;
mod xattr_reclaim;

pub use low_level::SetAttr;
pub use low_level::{InodeOwner, SetAttr};

/// Simple fixed-size inode cache.
/// When full, the entire cache is cleared (simple but effective for common workloads).
Expand Down
2 changes: 1 addition & 1 deletion kernel/crates/another_ext4/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mod prelude;

pub use constants::{BLOCK_SIZE, EXT4_ROOT_INO, INODE_BLOCK_SIZE};
pub use error::{ErrCode, Ext4Error};
pub use ext4::{Ext4, SetAttr};
pub use ext4::{Ext4, InodeOwner, SetAttr};
pub use ext4_defs::{
Block, BlockDevice, DirEntry, FileAttr, FileType, Inode, InodeMode, InodeReclaimError,
InodeReclaimHandle, InodeRef,
Expand Down
Loading
Loading