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
80 changes: 80 additions & 0 deletions os/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::sync::SpinNoIrqLock;
use crate::syscall::errno::ERRNO;
use crate::syscall::Pod;
use core::any::Any;
use lazy_static::*;
pub use fs::vfs::{InodeTime, VfsFileType};
pub use page_cache::{
discard_inode,
Expand Down Expand Up @@ -111,6 +112,29 @@ pub enum AccessMode {
ReadWrite,
}

const LOCK_SH: i32 = 1;
const LOCK_EX: i32 = 2;
const LOCK_NB: i32 = 4;
const LOCK_UN: i32 = 8;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum FlockKind {
Shared,
Exclusive,
}

#[derive(Clone, Copy, Debug)]
struct FlockRecord {
fs_id: u64,
ino: u64,
owner: usize,
kind: FlockKind,
}

lazy_static! {
static ref FLOCK_TABLE: SpinNoIrqLock<Vec<FlockRecord>> = SpinNoIrqLock::new(Vec::new());
}

impl AccessMode {
/// 从 `open` 低两位访问模式中解析访问权限。
pub fn from_open_bits(bits: i32) -> Result<Self, ERRNO> {
Expand Down Expand Up @@ -394,6 +418,55 @@ impl FileDescription {
self.file.backing_inode()
}

/// Apply a BSD `flock(2)` lock to this open file description.
pub fn flock(&self, operation: i32) -> Result<(), ERRNO> {
let op = operation & !LOCK_NB;
let kind = match op {
LOCK_SH => Some(FlockKind::Shared),
LOCK_EX => Some(FlockKind::Exclusive),
LOCK_UN => None,
_ => return Err(ERRNO::EINVAL),
};
if operation & !(LOCK_SH | LOCK_EX | LOCK_NB | LOCK_UN) != 0 {
return Err(ERRNO::EINVAL);
}

let inode = self.backing_inode().ok_or(ERRNO::EINVAL)?;
let fs_id = inode.fs_id();
let ino = inode.ino();
let owner = self as *const Self as usize;
let mut table = FLOCK_TABLE.lock();

if kind.is_none() {
table.retain(|record| {
!(record.fs_id == fs_id && record.ino == ino && record.owner == owner)
});
return Ok(());
}

let kind = kind.unwrap();
let has_conflict = table.iter().any(|record| {
if record.fs_id != fs_id || record.ino != ino || record.owner == owner {
return false;
}
kind == FlockKind::Exclusive || record.kind == FlockKind::Exclusive
});
if has_conflict {
return Err(ERRNO::EAGAIN);
}

table.retain(|record| {
!(record.fs_id == fs_id && record.ino == ino && record.owner == owner)
});
table.push(FlockRecord {
fs_id,
ino,
owner,
kind,
});
Ok(())
}

/// 读取目录项并推进共享目录位置。
pub fn getdents64(&self, buf: &mut [u8]) -> usize {
let mut inner = self.inner.lock();
Expand Down Expand Up @@ -489,6 +562,13 @@ impl FileDescription {
}
}

impl Drop for FileDescription {
fn drop(&mut self) {
let owner = self as *const Self as usize;
FLOCK_TABLE.lock().retain(|record| record.owner != owner);
}
}

/// trait File for all file types
pub trait File: Send + Sync + Any {
/// Returns this file as `Any` for runtime downcasting.
Expand Down
98 changes: 98 additions & 0 deletions os/src/fs/procfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1261,6 +1261,9 @@ impl VfsNode for ProcPidDirNode {
(String::from("ns"), VfsFileType::Directory),
(String::from("stat"), VfsFileType::Regular),
(String::from("status"), VfsFileType::Regular),
(String::from("setgroups"), VfsFileType::Regular),
(String::from("uid_map"), VfsFileType::Regular),
(String::from("gid_map"), VfsFileType::Regular),
]
}

Expand All @@ -1273,6 +1276,11 @@ impl VfsNode for ProcPidDirNode {
"ns" => Some(Arc::new(ProcPidNsDirNode::new(self.pid)) as Arc<dyn VfsNode>),
"stat" => Some(Arc::new(ProcPidStatNode::new(self.pid)) as Arc<dyn VfsNode>),
"status" => Some(Arc::new(ProcPidStatusNode::new(self.pid)) as Arc<dyn VfsNode>),
"setgroups" => {
Some(Arc::new(ProcPidUsernsNode::new(self.pid, ProcPidUsernsKind::Setgroups)) as Arc<dyn VfsNode>)
}
"uid_map" => Some(Arc::new(ProcPidUsernsNode::new(self.pid, ProcPidUsernsKind::UidMap)) as Arc<dyn VfsNode>),
"gid_map" => Some(Arc::new(ProcPidUsernsNode::new(self.pid, ProcPidUsernsKind::GidMap)) as Arc<dyn VfsNode>),
_ => None,
}
}
Expand Down Expand Up @@ -1305,6 +1313,96 @@ impl VfsNode for ProcPidDirNode {
}
}

#[derive(Debug, Clone, Copy)]
enum ProcPidUsernsKind {
Setgroups,
UidMap,
GidMap,
}

/// User namespace setup files used by LTP helpers.
#[derive(Debug)]
struct ProcPidUsernsNode {
pid: usize,
kind: ProcPidUsernsKind,
}

impl ProcPidUsernsNode {
fn new(pid: usize, kind: ProcPidUsernsKind) -> Self {
Self { pid, kind }
}

fn content(&self) -> Result<&'static str, FS_ERRNO> {
pid2process(self.pid).ok_or(FS_ERRNO::ENOENT)?;
Ok(match self.kind {
ProcPidUsernsKind::Setgroups => "allow\n",
ProcPidUsernsKind::UidMap | ProcPidUsernsKind::GidMap => "0 0 4294967295\n",
})
}
}

impl VfsNode for ProcPidUsernsNode {
fn as_any(&self) -> &dyn Any {
self
}

fn file_type(&self) -> VfsFileType {
VfsFileType::Regular
}

fn size(&self) -> usize {
self.content().map(|data| data.len()).unwrap_or(0)
}

fn ls(&self) -> Vec<(String, VfsFileType)> {
Vec::new()
}

fn find(&self, _name: &str) -> Option<Arc<dyn VfsNode>> {
None
}

fn create(&self, _name: &str) -> Option<Arc<dyn VfsNode>> {
None
}

fn mkdir(&self, _name: &str) -> Option<Arc<dyn VfsNode>> {
None
}

fn clear(&self) {}

fn truncate(&self, _new_size: usize) -> Result<(), FS_ERRNO> {
Ok(())
}

fn read_at(&self, offset: usize, buf: &mut [u8]) -> usize {
self.content()
.map(|data| read_string_at(data.to_string(), offset, buf))
.unwrap_or(0)
}

fn write_at(&self, _offset: usize, buf: &[u8]) -> usize {
if pid2process(self.pid).is_none() {
return 0;
}
buf.len()
}

fn write_at_result(&self, offset: usize, buf: &[u8]) -> Result<usize, FS_ERRNO> {
Ok(self.write_at(offset, buf))
}

fn statfs(&self) -> Result<fs::VfsStatFs, fs::errno::FS_ERRNO> {
Ok(crate::fs::empty_statfs(
fs::STATFS_MAGIC_PROC,
crate::config::PAGE_SIZE as u64,
0x9fa0,
255,
))
}
}

/// `/proc/<pid>/ns` directory node.
#[derive(Debug)]
pub struct ProcPidNsDirNode {
Expand Down
37 changes: 25 additions & 12 deletions os/src/net/compat_socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ pub(crate) fn compat_ifreq_ioctl(req: usize, arg: usize) -> Result<isize, ERRNO>
}

struct PacketBinding {
ifindex: usize,
ifindex: Option<usize>,
protocol: u16,
}

Expand Down Expand Up @@ -567,8 +567,15 @@ impl PacketSocketFile {
if raw.sll_family != AF_PACKET_FAMILY {
return Err(ERRNO::EAFNOSUPPORT);
}
let ifindex = raw.sll_ifindex as usize;
compat::get_iface_by_ifindex(ifindex).ok_or(ERRNO::ENODEV)?;
let ifindex = if raw.sll_ifindex == 0 {
None
} else if raw.sll_ifindex > 0 {
let ifindex = raw.sll_ifindex as usize;
compat::get_iface_by_ifindex(ifindex).ok_or(ERRNO::ENODEV)?;
Some(ifindex)
} else {
return Err(ERRNO::ENODEV);
};
*self.binding.lock() = Some(PacketBinding {
ifindex,
protocol: u16::from_be(raw.sll_protocol),
Expand All @@ -579,17 +586,21 @@ impl PacketSocketFile {
pub(crate) fn getsockname_raw(&self) -> Result<SockAddrLl, ERRNO> {
let binding = self.binding.lock();
let binding = binding.as_ref().ok_or(ERRNO::EINVAL)?;
let iface = compat::get_iface_by_ifindex(binding.ifindex).ok_or(ERRNO::ENODEV)?;
let iface = binding
.ifindex
.and_then(compat::get_iface_by_ifindex);
let mut out = SockAddrLl {
sll_family: AF_PACKET_FAMILY,
sll_protocol: binding.protocol.to_be(),
sll_ifindex: binding.ifindex as i32,
sll_ifindex: binding.ifindex.unwrap_or(0) as i32,
sll_hatype: ARPHRD_ETHER,
sll_pkttype: PACKET_HOST,
sll_halen: 6,
sll_halen: if iface.is_some() { 6 } else { 0 },
sll_addr: [0; 8],
};
out.sll_addr[..6].copy_from_slice(&iface.mac);
if let Some(iface) = iface {
out.sll_addr[..6].copy_from_slice(&iface.mac);
}
Ok(out)
}

Expand All @@ -603,11 +614,10 @@ impl PacketSocketFile {
data.extend_from_slice(chunk);
}

let local_ifindex = {
let bound_ifindex = {
let binding = self.binding.lock();
binding.as_ref().ok_or(ERRNO::EINVAL)?.ifindex
};
let local = compat::get_iface_by_ifindex(local_ifindex).ok_or(ERRNO::ENODEV)?;

let send_ifindex = if let Some(addr) = addr {
if addr.len() < size_of::<SockAddrLl>() {
Expand All @@ -619,10 +629,13 @@ impl PacketSocketFile {
}
raw.sll_ifindex as usize
} else {
local.ifindex
bound_ifindex.unwrap_or(2)
};
if send_ifindex != local.ifindex {
return Err(ERRNO::ENODEV);
let local = compat::get_iface_by_ifindex(send_ifindex).ok_or(ERRNO::ENODEV)?;
if let Some(bound_ifindex) = bound_ifindex {
if send_ifindex != bound_ifindex {
return Err(ERRNO::ENODEV);
}
}

if let Some((src_mac, src_ip, dst_ip)) = read_arp_ipv4_request(data.as_slice()) {
Expand Down
5 changes: 4 additions & 1 deletion os/src/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ pub(crate) use socket_timeout::{
socket_wait_should_skip, socket_wait_state, timeout_ns_to_deadline_ns, SocketTimerTag,
SocketWakeState,
};
pub(crate) use unix_socket::create_unix_stream_socket_file;
pub(crate) use unix_socket::{
create_unix_datagram_socket_file, create_unix_stream_socket_file, unix_stream_listener,
UnixDatagramSocketFile,
};
pub use unix_socket::{
UnixSocketAncillaryData, UnixSocketPairEnd, UnixUcred, SCM_CREDENTIALS, SCM_RIGHTS,
SocketLevel,
Expand Down
Loading
Loading