Add support for FLOCK
This commit is contained in:
parent
91f025f1c8
commit
f52bf0b514
19
src/libos/src/fs/file_ops/flock.rs
Normal file
19
src/libos/src/fs/file_ops/flock.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub fn do_flock(fd: FileDesc, ops: FlockOps) -> Result<()> {
|
||||||
|
debug!("flock: fd: {}, ops: {:?}", fd, ops);
|
||||||
|
|
||||||
|
let file_ref = current!().file(fd)?;
|
||||||
|
let inode_file = file_ref.as_inode_file()?;
|
||||||
|
if ops.contains(FlockOps::LOCK_UN) {
|
||||||
|
inode_file.unlock_flock();
|
||||||
|
} else {
|
||||||
|
let is_nonblocking = ops.contains(FlockOps::LOCK_NB);
|
||||||
|
let flock = {
|
||||||
|
let type_ = FlockType::from(ops);
|
||||||
|
Flock::new(&file_ref, type_)
|
||||||
|
};
|
||||||
|
inode_file.set_flock(flock, is_nonblocking)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -9,6 +9,7 @@ pub use self::dup::{do_dup, do_dup2, do_dup3};
|
|||||||
pub use self::fallocate::{do_fallocate, FallocateFlags};
|
pub use self::fallocate::{do_fallocate, FallocateFlags};
|
||||||
pub use self::fcntl::{do_fcntl, FcntlCmd};
|
pub use self::fcntl::{do_fcntl, FcntlCmd};
|
||||||
pub use self::file_flags::{AccessMode, CreationFlags, StatusFlags};
|
pub use self::file_flags::{AccessMode, CreationFlags, StatusFlags};
|
||||||
|
pub use self::flock::do_flock;
|
||||||
pub use self::fspath::{get_abs_path_by_fd, FsPath, AT_FDCWD};
|
pub use self::fspath::{get_abs_path_by_fd, FsPath, AT_FDCWD};
|
||||||
pub use self::fsync::{do_fdatasync, do_fsync};
|
pub use self::fsync::{do_fdatasync, do_fsync};
|
||||||
pub use self::getdents::{do_getdents, do_getdents64};
|
pub use self::getdents::{do_getdents, do_getdents64};
|
||||||
@ -38,6 +39,7 @@ mod dup;
|
|||||||
mod fallocate;
|
mod fallocate;
|
||||||
mod fcntl;
|
mod fcntl;
|
||||||
mod file_flags;
|
mod file_flags;
|
||||||
|
mod flock;
|
||||||
mod fspath;
|
mod fspath;
|
||||||
mod fsync;
|
mod fsync;
|
||||||
mod getdents;
|
mod getdents;
|
||||||
|
@ -338,6 +338,46 @@ impl INodeFile {
|
|||||||
|
|
||||||
range_lock_list.unlock(lock)
|
range_lock_list.unlock(lock)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_flock(&self, lock: Flock, is_nonblocking: bool) -> Result<()> {
|
||||||
|
let ext = match self.inode.ext() {
|
||||||
|
Some(ext) => ext,
|
||||||
|
None => {
|
||||||
|
warn!("Inode extension is not supported, let the lock could be acquired");
|
||||||
|
// TODO: Implement inode extension for FS
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let flock_list = match ext.get::<FlockList>() {
|
||||||
|
Some(list) => list,
|
||||||
|
None => ext.get_or_put_default::<FlockList>(),
|
||||||
|
};
|
||||||
|
|
||||||
|
flock_list.set_lock(lock, is_nonblocking)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unlock_flock(&self) {
|
||||||
|
let ext = match self.inode.ext() {
|
||||||
|
Some(ext) => ext,
|
||||||
|
None => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let flock_list = match ext.get::<FlockList>() {
|
||||||
|
Some(list) => list,
|
||||||
|
None => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
flock_list.unlock(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for INodeFile {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.unlock_flock()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for INodeFile {
|
impl Debug for INodeFile {
|
||||||
|
199
src/libos/src/fs/locks/flock.rs
Normal file
199
src/libos/src/fs/locks/flock.rs
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
/// Non-POSIX file advisory lock (FLOCK)
|
||||||
|
use super::*;
|
||||||
|
use crate::events::{Waiter, WaiterQueue};
|
||||||
|
use rcore_fs::vfs::AnyExt;
|
||||||
|
use std::ptr;
|
||||||
|
use std::sync::Weak;
|
||||||
|
|
||||||
|
/// Kernel representation of FLOCK
|
||||||
|
pub struct Flock {
|
||||||
|
/// Owner of FLOCK, an opened file descriptor holding the lock
|
||||||
|
owner: Weak<dyn File>,
|
||||||
|
/// Type of lock, SH_LOCK or EX_LOCK
|
||||||
|
type_: FlockType,
|
||||||
|
/// Optional waiters that are blocking by the lock
|
||||||
|
waiters: Option<WaiterQueue>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Flock {
|
||||||
|
pub fn new(owner: &Arc<dyn File>, type_: FlockType) -> Self {
|
||||||
|
Self {
|
||||||
|
owner: Arc::downgrade(owner),
|
||||||
|
type_,
|
||||||
|
waiters: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn owner(&self) -> Option<Arc<dyn File>> {
|
||||||
|
Weak::upgrade(&self.owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn same_owner_with(&self, other: &Self) -> bool {
|
||||||
|
self.owner.ptr_eq(&other.owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn conflict_with(&self, other: &Self) -> bool {
|
||||||
|
if self.same_owner_with(other) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if self.type_ == FlockType::EX_LOCK || other.type_ == FlockType::EX_LOCK {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enqueue_waiter(&mut self, waiter: &Waiter) {
|
||||||
|
if self.waiters.is_none() {
|
||||||
|
self.waiters = Some(WaiterQueue::new());
|
||||||
|
}
|
||||||
|
self.waiters.as_ref().unwrap().reset_and_enqueue(waiter)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dequeue_and_wake_all_waiters(&mut self) -> usize {
|
||||||
|
if self.waiters.is_some() {
|
||||||
|
return self.waiters.as_ref().unwrap().dequeue_and_wake_all();
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Flock {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.dequeue_and_wake_all_waiters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Flock {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Flock")
|
||||||
|
.field("owner", &self.owner.as_ptr())
|
||||||
|
.field("type_", &self.type_)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List of Non-POSIX file advisory lock (FLOCK)
|
||||||
|
pub struct FlockList {
|
||||||
|
inner: RwLock<VecDeque<Flock>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlockList {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
inner: RwLock::new(VecDeque::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_lock(&self, mut req_lock: Flock, is_nonblocking: bool) -> Result<()> {
|
||||||
|
debug!(
|
||||||
|
"set_lock with Flock: {:?}, is_nonblocking: {}",
|
||||||
|
req_lock, is_nonblocking
|
||||||
|
);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut list = self.inner.write().unwrap();
|
||||||
|
if let Some(mut conflict_lock) = list.iter_mut().find(|l| req_lock.conflict_with(&l)) {
|
||||||
|
if is_nonblocking {
|
||||||
|
return_errno!(EAGAIN, "The file is locked");
|
||||||
|
}
|
||||||
|
// Start to wait
|
||||||
|
let waiter = Waiter::new();
|
||||||
|
// FLOCK do not support deadlock detection
|
||||||
|
conflict_lock.enqueue_waiter(&waiter);
|
||||||
|
// Ensure that we drop any locks before wait
|
||||||
|
drop(list);
|
||||||
|
waiter.wait(None)?;
|
||||||
|
// Wake up, let's try to set lock again
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match list.iter().position(|l| req_lock.same_owner_with(&l)) {
|
||||||
|
Some(idx) => {
|
||||||
|
std::mem::swap(&mut req_lock, &mut list[idx]);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
list.push_front(req_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unlock(&self, req_owner: &INodeFile) {
|
||||||
|
debug!("unlock with owner: {:?}", req_owner as *const INodeFile);
|
||||||
|
|
||||||
|
let mut list = self.inner.write().unwrap();
|
||||||
|
list.retain(|lock| {
|
||||||
|
if let Some(owner) = lock.owner() {
|
||||||
|
!ptr::eq(
|
||||||
|
Arc::as_ptr(&owner) as *const INodeFile,
|
||||||
|
req_owner as *const INodeFile,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FlockList {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyExt for FlockList {}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum FlockType {
|
||||||
|
/// Shared lock
|
||||||
|
SH_LOCK = 0,
|
||||||
|
/// Exclusive lock
|
||||||
|
EX_LOCK = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FlockOps> for FlockType {
|
||||||
|
fn from(ops: FlockOps) -> Self {
|
||||||
|
if ops.contains(FlockOps::LOCK_EX) {
|
||||||
|
Self::EX_LOCK
|
||||||
|
} else if ops.contains(FlockOps::LOCK_SH) {
|
||||||
|
Self::SH_LOCK
|
||||||
|
} else {
|
||||||
|
panic!("invalid flockops");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct FlockOps: i32 {
|
||||||
|
/// Shared lock
|
||||||
|
const LOCK_SH = 1;
|
||||||
|
/// Exclusive lock
|
||||||
|
const LOCK_EX = 2;
|
||||||
|
// Or'd with one of the above to prevent blocking
|
||||||
|
const LOCK_NB = 4;
|
||||||
|
// Remove lock
|
||||||
|
const LOCK_UN = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlockOps {
|
||||||
|
pub fn from_i32(bits: i32) -> Result<Self> {
|
||||||
|
let ops = Self::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid operation"))?;
|
||||||
|
if ops.contains(Self::LOCK_SH) {
|
||||||
|
if ops.contains(Self::LOCK_EX) || ops.contains(Self::LOCK_UN) {
|
||||||
|
return_errno!(EINVAL, "invalid operation");
|
||||||
|
}
|
||||||
|
} else if ops.contains(Self::LOCK_EX) {
|
||||||
|
if ops.contains(Self::LOCK_UN) {
|
||||||
|
return_errno!(EINVAL, "invalid operation");
|
||||||
|
}
|
||||||
|
} else if !ops.contains(Self::LOCK_UN) {
|
||||||
|
return_errno!(EINVAL, "invalid operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ops)
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
pub mod flock;
|
||||||
pub mod range_lock;
|
pub mod range_lock;
|
||||||
|
@ -23,13 +23,14 @@ pub use self::file_ops::{
|
|||||||
IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum,
|
IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum,
|
||||||
};
|
};
|
||||||
pub use self::file_table::{FileDesc, FileTable, FileTableEvent, FileTableNotifier};
|
pub use self::file_table::{FileDesc, FileTable, FileTableEvent, FileTableNotifier};
|
||||||
pub use self::locks::range_lock::{
|
|
||||||
FileRange, RangeLock, RangeLockBuilder, RangeLockList, RangeLockType, OFFSET_MAX,
|
|
||||||
};
|
|
||||||
pub use self::fs_ops::Statfs;
|
pub use self::fs_ops::Statfs;
|
||||||
pub use self::fs_view::FsView;
|
pub use self::fs_view::FsView;
|
||||||
pub use self::host_fd::HostFd;
|
pub use self::host_fd::HostFd;
|
||||||
pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};
|
pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};
|
||||||
|
pub use self::locks::flock::{Flock, FlockList, FlockOps, FlockType};
|
||||||
|
pub use self::locks::range_lock::{
|
||||||
|
FileRange, RangeLock, RangeLockBuilder, RangeLockList, RangeLockType, OFFSET_MAX,
|
||||||
|
};
|
||||||
pub use self::pipe::PipeType;
|
pub use self::pipe::PipeType;
|
||||||
pub use self::rootfs::ROOT_FS;
|
pub use self::rootfs::ROOT_FS;
|
||||||
pub use self::stdio::{HostStdioFds, StdinFile, StdoutFile};
|
pub use self::stdio::{HostStdioFds, StdinFile, StdoutFile};
|
||||||
@ -43,12 +44,12 @@ mod events;
|
|||||||
mod file;
|
mod file;
|
||||||
mod file_ops;
|
mod file_ops;
|
||||||
mod file_table;
|
mod file_table;
|
||||||
mod locks;
|
|
||||||
mod fs_ops;
|
mod fs_ops;
|
||||||
mod fs_view;
|
mod fs_view;
|
||||||
mod host_fd;
|
mod host_fd;
|
||||||
mod hostfs;
|
mod hostfs;
|
||||||
mod inode_file;
|
mod inode_file;
|
||||||
|
mod locks;
|
||||||
mod pipe;
|
mod pipe;
|
||||||
mod procfs;
|
mod procfs;
|
||||||
mod rootfs;
|
mod rootfs;
|
||||||
|
@ -693,3 +693,10 @@ pub fn do_umount(target: *const i8, flags: u32) -> Result<isize> {
|
|||||||
fs_ops::do_umount(&target, flags)?;
|
fs_ops::do_umount(&target, flags)?;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn do_flock(fd: FileDesc, operation: i32) -> Result<isize> {
|
||||||
|
let flock_ops = FlockOps::from_i32(operation)?;
|
||||||
|
|
||||||
|
file_ops::do_flock(fd, flock_ops)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
@ -24,14 +24,14 @@ use crate::exception::do_handle_exception;
|
|||||||
use crate::fs::{
|
use crate::fs::{
|
||||||
do_access, do_chdir, do_chmod, do_chown, do_close, do_creat, do_dup, do_dup2, do_dup3,
|
do_access, do_chdir, do_chmod, do_chown, do_close, do_creat, do_dup, do_dup2, do_dup3,
|
||||||
do_eventfd, do_eventfd2, do_faccessat, do_fallocate, do_fchdir, do_fchmod, do_fchmodat,
|
do_eventfd, do_eventfd2, do_faccessat, do_fallocate, do_fchdir, do_fchmod, do_fchmodat,
|
||||||
do_fchown, do_fchownat, do_fcntl, do_fdatasync, do_fstat, do_fstatat, do_fstatfs, do_fsync,
|
do_fchown, do_fchownat, do_fcntl, do_fdatasync, do_flock, do_fstat, do_fstatat, do_fstatfs,
|
||||||
do_ftruncate, do_getcwd, do_getdents, do_getdents64, do_ioctl, do_lchown, do_link, do_linkat,
|
do_fsync, do_ftruncate, do_getcwd, do_getdents, do_getdents64, do_ioctl, do_lchown, do_link,
|
||||||
do_lseek, do_lstat, do_mkdir, do_mkdirat, do_mount, do_mount_rootfs, do_open, do_openat,
|
do_linkat, do_lseek, do_lstat, do_mkdir, do_mkdirat, do_mount, do_mount_rootfs, do_open,
|
||||||
do_pipe, do_pipe2, do_pread, do_pwrite, do_read, do_readlink, do_readlinkat, do_readv,
|
do_openat, do_pipe, do_pipe2, do_pread, do_pwrite, do_read, do_readlink, do_readlinkat,
|
||||||
do_rename, do_renameat, do_rmdir, do_sendfile, do_stat, do_statfs, do_symlink, do_symlinkat,
|
do_readv, do_rename, do_renameat, do_rmdir, do_sendfile, do_stat, do_statfs, do_symlink,
|
||||||
do_sync, do_timerfd_create, do_timerfd_gettime, do_timerfd_settime, do_truncate, do_umask,
|
do_symlinkat, do_sync, do_timerfd_create, do_timerfd_gettime, do_timerfd_settime, do_truncate,
|
||||||
do_umount, do_unlink, do_unlinkat, do_write, do_writev, iovec_t, AsTimer, File, FileDesc,
|
do_umask, do_umount, do_unlink, do_unlinkat, do_write, do_writev, iovec_t, AsTimer, File,
|
||||||
FileRef, HostStdioFds, Stat, Statfs,
|
FileDesc, FileRef, HostStdioFds, Stat, Statfs,
|
||||||
};
|
};
|
||||||
use crate::interrupt::{do_handle_interrupt, sgx_interrupt_info_t};
|
use crate::interrupt::{do_handle_interrupt, sgx_interrupt_info_t};
|
||||||
use crate::misc::{resource_t, rlimit_t, sysinfo_t, utsname_t, RandFlags};
|
use crate::misc::{resource_t, rlimit_t, sysinfo_t, utsname_t, RandFlags};
|
||||||
@ -161,7 +161,7 @@ macro_rules! process_syscall_table_with_callback {
|
|||||||
(Msgrcv = 70) => handle_unsupported(),
|
(Msgrcv = 70) => handle_unsupported(),
|
||||||
(Msgctl = 71) => handle_unsupported(),
|
(Msgctl = 71) => handle_unsupported(),
|
||||||
(Fcntl = 72) => do_fcntl(fd: FileDesc, cmd: u32, arg: u64),
|
(Fcntl = 72) => do_fcntl(fd: FileDesc, cmd: u32, arg: u64),
|
||||||
(Flock = 73) => handle_unsupported(),
|
(Flock = 73) => do_flock(fd: FileDesc, operation: i32),
|
||||||
(Fsync = 74) => do_fsync(fd: FileDesc),
|
(Fsync = 74) => do_fsync(fd: FileDesc),
|
||||||
(Fdatasync = 75) => do_fdatasync(fd: FileDesc),
|
(Fdatasync = 75) => do_fdatasync(fd: FileDesc),
|
||||||
(Truncate = 76) => do_truncate(path: *const i8, len: usize),
|
(Truncate = 76) => do_truncate(path: *const i8, len: usize),
|
||||||
|
Loading…
Reference in New Issue
Block a user