From 1dd1c8c77565a8d650fec03145dc1fc48880b62e Mon Sep 17 00:00:00 2001 From: Chen Chengjun Date: Fri, 6 Jun 2025 07:16:01 +0000 Subject: [PATCH] Enable read and write operations of the attribute to handle offset --- kernel/comps/systree/src/lib.rs | 3 +++ kernel/comps/systree/src/node.rs | 27 +++++++++++++++++++++++++++ kernel/src/error.rs | 1 + kernel/src/fs/sysfs/inode.rs | 27 ++++++++++++++++++--------- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/kernel/comps/systree/src/lib.rs b/kernel/comps/systree/src/lib.rs index 5aae9448..2fbb8ad5 100644 --- a/kernel/comps/systree/src/lib.rs +++ b/kernel/comps/systree/src/lib.rs @@ -76,6 +76,8 @@ pub enum Error { PermissionDenied, /// Other internal error InternalError(&'static str), + /// Arithmetic overflow occurred + Overflow, } impl core::fmt::Display for Error { @@ -88,6 +90,7 @@ impl core::fmt::Display for Error { Error::AttributeError => write!(f, "Attribute error"), Error::PermissionDenied => write!(f, "Permission denied for operation"), Error::InternalError(msg) => write!(f, "Internal error: {}", msg), + Error::Overflow => write!(f, "Numerical overflow occurred"), } } } diff --git a/kernel/comps/systree/src/node.rs b/kernel/comps/systree/src/node.rs index 91b55adf..a3dc515c 100644 --- a/kernel/comps/systree/src/node.rs +++ b/kernel/comps/systree/src/node.rs @@ -118,6 +118,33 @@ pub trait SysNode: SysObj { /// Writes the value of an attribute. fn write_attr(&self, name: &str, reader: &mut VmReader) -> Result; + /// Reads the value of an attribute from the specified `offset`. + fn read_attr_at(&self, name: &str, offset: usize, writer: &mut VmWriter) -> Result { + let (attr_buffer, attr_len) = { + let attr_buffer_len = writer.avail().checked_add(offset).ok_or(Error::Overflow)?; + let mut buffer = vec![0; attr_buffer_len]; + let len = self.read_attr( + name, + &mut VmWriter::from(buffer.as_mut_slice()).to_fallible(), + )?; + (buffer, len) + }; + + if attr_len <= offset { + return Ok(0); + } + + writer + .write_fallible(VmReader::from(attr_buffer.as_slice()).skip(offset)) + .map_err(|_| Error::AttributeError) + } + + /// Writes the value of an attribute at the specified `offset`. + fn write_attr_at(&self, name: &str, _offset: usize, reader: &mut VmReader) -> Result { + // In general, the `offset` for attribute write operations is ignored directly. + self.write_attr(name, reader) + } + /// Shows the string value of an attribute. /// /// Most attributes are textual, rather binary (see `SysAttrFlags::IS_BINARY`). diff --git a/kernel/src/error.rs b/kernel/src/error.rs index 2bb1883b..7e8714e8 100644 --- a/kernel/src/error.rs +++ b/kernel/src/error.rs @@ -339,6 +339,7 @@ impl From for Error { AttributeError => Error::new(Errno::EIO), PermissionDenied => Error::new(Errno::EACCES), InternalError(msg) => Error::with_message(Errno::EIO, msg), + Overflow => Error::new(Errno::EOVERFLOW), } } } diff --git a/kernel/src/fs/sysfs/inode.rs b/kernel/src/fs/sysfs/inode.rs index 08e09f90..21b3d23e 100644 --- a/kernel/src/fs/sysfs/inode.rs +++ b/kernel/src/fs/sysfs/inode.rs @@ -376,29 +376,38 @@ impl Inode for SysFsInode { self.read_direct_at(offset, buf) } - fn read_direct_at(&self, _offset: usize, buf: &mut VmWriter) -> Result { - // TODO: it is unclear whether we should simply ignore the offset - // or report errors if it is non-zero. - + fn read_direct_at(&self, offset: usize, buf: &mut VmWriter) -> Result { let InnerNode::Attr(attr, leaf) = &self.inner_node else { return Err(Error::new(Errno::EINVAL)); }; - // TODO: check read permission - Ok(leaf.read_attr(attr.name(), buf)?) + let len = if offset == 0 { + leaf.read_attr(attr.name(), buf)? + } else { + // The `read_attr_at` method is more general than `read_attr`, + // but it could be less efficient. So we only use the more general form when necessary. + leaf.read_attr_at(attr.name(), offset, buf)? + }; + + Ok(len) } fn write_at(&self, offset: usize, buf: &mut VmReader) -> Result { self.write_direct_at(offset, buf) } - fn write_direct_at(&self, _offset: usize, buf: &mut VmReader) -> Result { + fn write_direct_at(&self, offset: usize, buf: &mut VmReader) -> Result { let InnerNode::Attr(attr, leaf) = &self.inner_node else { return Err(Error::new(Errno::EINVAL)); }; - // TODO: check write permission - Ok(leaf.write_attr(attr.name(), buf)?) + let len = if offset == 0 { + leaf.write_attr(attr.name(), buf)? + } else { + leaf.write_attr_at(attr.name(), offset, buf)? + }; + + Ok(len) } fn create(&self, _name: &str, _type_: InodeType, _mode: InodeMode) -> Result> {