Add a dummy implementation for file advisory locks
This commits is a dummy implementation of file advisory locks. Specifically, for regular files, fcntl `F_SETLK` (i.e., acquiring or releasing locks) always succeeds and fcntl `F_GETLK` (i.e., testing locks) always returns no locks.
This commit is contained in:
parent
a6e55881b9
commit
551fb8f9d8
@ -79,6 +79,14 @@ pub trait File: Debug + Sync + Send + Any {
|
|||||||
return_op_unsupported_error!("set_status_flags")
|
return_op_unsupported_error!("set_status_flags")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_advisory_lock(&self, lock: &mut Flock) -> Result<()> {
|
||||||
|
return_op_unsupported_error!("test_advisory_lock")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_advisory_lock(&self, lock: &Flock) -> Result<()> {
|
||||||
|
return_op_unsupported_error!("set_advisory_lock")
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
use super::flock::flock;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use util::mem_util::from_user;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FcntlCmd {
|
pub enum FcntlCmd<'a> {
|
||||||
/// Duplicate the file descriptor fd using the lowest-numbered available
|
/// Duplicate the file descriptor fd using the lowest-numbered available
|
||||||
/// file descriptor greater than or equal to arg.
|
/// file descriptor greater than or equal to arg.
|
||||||
DupFd(FileDesc),
|
DupFd(FileDesc),
|
||||||
@ -16,11 +18,15 @@ pub enum FcntlCmd {
|
|||||||
GetFl(),
|
GetFl(),
|
||||||
/// Set the file status flags
|
/// Set the file status flags
|
||||||
SetFl(u32),
|
SetFl(u32),
|
||||||
|
/// Test a file lock
|
||||||
|
GetLk(&'a mut flock),
|
||||||
|
/// Acquire or release a file lock
|
||||||
|
SetLk(&'a flock),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FcntlCmd {
|
impl<'a> FcntlCmd<'a> {
|
||||||
#[deny(unreachable_patterns)]
|
#[deny(unreachable_patterns)]
|
||||||
pub fn from_raw(cmd: u32, arg: u64) -> Result<FcntlCmd> {
|
pub fn from_raw(cmd: u32, arg: u64) -> Result<FcntlCmd<'a>> {
|
||||||
Ok(match cmd as c_int {
|
Ok(match cmd as c_int {
|
||||||
libc::F_DUPFD => FcntlCmd::DupFd(arg as FileDesc),
|
libc::F_DUPFD => FcntlCmd::DupFd(arg as FileDesc),
|
||||||
libc::F_DUPFD_CLOEXEC => FcntlCmd::DupFdCloexec(arg as FileDesc),
|
libc::F_DUPFD_CLOEXEC => FcntlCmd::DupFdCloexec(arg as FileDesc),
|
||||||
@ -28,12 +34,24 @@ impl FcntlCmd {
|
|||||||
libc::F_SETFD => FcntlCmd::SetFd(arg as u32),
|
libc::F_SETFD => FcntlCmd::SetFd(arg as u32),
|
||||||
libc::F_GETFL => FcntlCmd::GetFl(),
|
libc::F_GETFL => FcntlCmd::GetFl(),
|
||||||
libc::F_SETFL => FcntlCmd::SetFl(arg as u32),
|
libc::F_SETFL => FcntlCmd::SetFl(arg as u32),
|
||||||
|
libc::F_GETLK => {
|
||||||
|
let flock_mut_ptr = arg as *mut flock;
|
||||||
|
from_user::check_mut_ptr(flock_mut_ptr)?;
|
||||||
|
let flock_mut_c = unsafe { &mut *flock_mut_ptr };
|
||||||
|
FcntlCmd::GetLk(flock_mut_c)
|
||||||
|
}
|
||||||
|
libc::F_SETLK => {
|
||||||
|
let flock_ptr = arg as *const flock;
|
||||||
|
from_user::check_ptr(flock_ptr)?;
|
||||||
|
let flock_c = unsafe { &*flock_ptr };
|
||||||
|
FcntlCmd::SetLk(flock_c)
|
||||||
|
}
|
||||||
_ => return_errno!(EINVAL, "unsupported command"),
|
_ => return_errno!(EINVAL, "unsupported command"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize> {
|
pub fn do_fcntl(fd: FileDesc, cmd: &mut FcntlCmd) -> Result<isize> {
|
||||||
info!("fcntl: fd: {:?}, cmd: {:?}", &fd, cmd);
|
info!("fcntl: fd: {:?}, cmd: {:?}", &fd, cmd);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let mut current = current_ref.lock().unwrap();
|
let mut current = current_ref.lock().unwrap();
|
||||||
@ -59,7 +77,7 @@ pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize> {
|
|||||||
}
|
}
|
||||||
FcntlCmd::SetFd(fd_flags) => {
|
FcntlCmd::SetFd(fd_flags) => {
|
||||||
let entry = file_table.get_entry_mut(fd)?;
|
let entry = file_table.get_entry_mut(fd)?;
|
||||||
entry.set_close_on_spawn((fd_flags & libc::FD_CLOEXEC as u32) != 0);
|
entry.set_close_on_spawn((*fd_flags & libc::FD_CLOEXEC as u32) != 0);
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
FcntlCmd::GetFl() => {
|
FcntlCmd::GetFl() => {
|
||||||
@ -74,6 +92,22 @@ pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize> {
|
|||||||
file.set_status_flags(status_flags)?;
|
file.set_status_flags(status_flags)?;
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
FcntlCmd::GetLk(flock_mut_c) => {
|
||||||
|
let file = file_table.get(fd)?;
|
||||||
|
let mut lock = Flock::from_c(*flock_mut_c)?;
|
||||||
|
if let FlockType::F_UNLCK = lock.l_type {
|
||||||
|
return_errno!(EINVAL, "invalid flock type for getlk");
|
||||||
|
}
|
||||||
|
file.test_advisory_lock(&mut lock)?;
|
||||||
|
(*flock_mut_c).copy_from_safe(&lock);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
FcntlCmd::SetLk(flock_c) => {
|
||||||
|
let file = file_table.get(fd)?;
|
||||||
|
let lock = Flock::from_c(*flock_c)?;
|
||||||
|
file.set_advisory_lock(&lock)?;
|
||||||
|
0
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
88
src/libos/src/fs/file_ops/flock.rs
Normal file
88
src/libos/src/fs/file_ops/flock.rs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/// File POSIX advisory lock
|
||||||
|
use super::*;
|
||||||
|
use process::pid_t;
|
||||||
|
|
||||||
|
/// C struct for a lock
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct flock {
|
||||||
|
pub l_type: u16,
|
||||||
|
pub l_whence: u16,
|
||||||
|
pub l_start: off_t,
|
||||||
|
pub l_len: off_t,
|
||||||
|
pub l_pid: pid_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl flock {
|
||||||
|
pub fn copy_from_safe(&mut self, lock: &Flock) {
|
||||||
|
self.l_type = lock.l_type as u16;
|
||||||
|
self.l_whence = lock.l_whence as u16;
|
||||||
|
self.l_start = lock.l_start;
|
||||||
|
self.l_len = lock.l_len;
|
||||||
|
self.l_pid = lock.l_pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type safe representation of flock
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Flock {
|
||||||
|
pub l_type: FlockType,
|
||||||
|
pub l_whence: FlockWhence,
|
||||||
|
pub l_start: off_t,
|
||||||
|
pub l_len: off_t,
|
||||||
|
pub l_pid: pid_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Flock {
|
||||||
|
pub fn from_c(flock_c: &flock) -> Result<Self> {
|
||||||
|
let l_type = FlockType::from_u16(flock_c.l_type)?;
|
||||||
|
let l_whence = FlockWhence::from_u16(flock_c.l_whence)?;
|
||||||
|
Ok(Self {
|
||||||
|
l_type: l_type,
|
||||||
|
l_whence: l_whence,
|
||||||
|
l_start: flock_c.l_start,
|
||||||
|
l_len: flock_c.l_len,
|
||||||
|
l_pid: flock_c.l_pid,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum FlockType {
|
||||||
|
F_RDLCK = 0,
|
||||||
|
F_WRLCK = 1,
|
||||||
|
F_UNLCK = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlockType {
|
||||||
|
pub fn from_u16(_type: u16) -> Result<Self> {
|
||||||
|
Ok(match _type {
|
||||||
|
0 => FlockType::F_RDLCK,
|
||||||
|
1 => FlockType::F_WRLCK,
|
||||||
|
2 => FlockType::F_UNLCK,
|
||||||
|
_ => return_errno!(EINVAL, "invalid flock type"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum FlockWhence {
|
||||||
|
SEEK_SET = 0,
|
||||||
|
SEEK_CUR = 1,
|
||||||
|
SEEK_END = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlockWhence {
|
||||||
|
pub fn from_u16(whence: u16) -> Result<Self> {
|
||||||
|
Ok(match whence {
|
||||||
|
0 => FlockWhence::SEEK_SET,
|
||||||
|
1 => FlockWhence::SEEK_CUR,
|
||||||
|
2 => FlockWhence::SEEK_END,
|
||||||
|
_ => return_errno!(EINVAL, "Invalid whence"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ pub use self::dirent::do_getdents64;
|
|||||||
pub use self::dup::{do_dup, do_dup2, do_dup3};
|
pub use self::dup::{do_dup, do_dup2, do_dup3};
|
||||||
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::{Flock, FlockType};
|
||||||
pub use self::fsync::{do_fdatasync, do_fsync};
|
pub use self::fsync::{do_fdatasync, do_fsync};
|
||||||
pub use self::ioctl::{do_ioctl, IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
|
pub use self::ioctl::{do_ioctl, IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
|
||||||
pub use self::link::do_link;
|
pub use self::link::do_link;
|
||||||
@ -34,6 +35,7 @@ mod dirent;
|
|||||||
mod dup;
|
mod dup;
|
||||||
mod fcntl;
|
mod fcntl;
|
||||||
mod file_flags;
|
mod file_flags;
|
||||||
|
mod flock;
|
||||||
mod fsync;
|
mod fsync;
|
||||||
mod ioctl;
|
mod ioctl;
|
||||||
mod link;
|
mod link;
|
||||||
|
@ -166,6 +166,32 @@ impl File for INodeFile {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_advisory_lock(&self, lock: &mut Flock) -> Result<()> {
|
||||||
|
// Let the advisory lock could be placed
|
||||||
|
// TODO: Implement the real advisory lock
|
||||||
|
lock.l_type = FlockType::F_UNLCK;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_advisory_lock(&self, lock: &Flock) -> Result<()> {
|
||||||
|
match lock.l_type {
|
||||||
|
FlockType::F_RDLCK => {
|
||||||
|
if !self.access_mode.readable() {
|
||||||
|
return_errno!(EBADF, "File not readable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FlockType::F_WRLCK => {
|
||||||
|
if !self.access_mode.writable() {
|
||||||
|
return_errno!(EBADF, "File not writable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
// Let the advisory lock could be acquired or released
|
||||||
|
// TODO: Implement the real advisory lock
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
fn as_any(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ use std::mem::MaybeUninit;
|
|||||||
|
|
||||||
pub use self::file::{File, FileRef};
|
pub use self::file::{File, FileRef};
|
||||||
pub use self::file_ops::{AccessMode, CreationFlags, Stat, StatusFlags};
|
pub use self::file_ops::{AccessMode, CreationFlags, Stat, StatusFlags};
|
||||||
|
pub use self::file_ops::{Flock, FlockType};
|
||||||
pub use self::file_ops::{IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
|
pub use self::file_ops::{IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
|
||||||
pub use self::file_table::{FileDesc, FileTable};
|
pub use self::file_table::{FileDesc, FileTable};
|
||||||
pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};
|
pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};
|
||||||
|
@ -347,8 +347,8 @@ pub fn do_sendfile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize> {
|
pub fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize> {
|
||||||
let cmd = FcntlCmd::from_raw(cmd, arg)?;
|
let mut cmd = FcntlCmd::from_raw(cmd, arg)?;
|
||||||
file_ops::do_fcntl(fd, &cmd)
|
file_ops::do_fcntl(fd, &mut cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_ioctl(fd: FileDesc, cmd: u32, argp: *mut u8) -> Result<isize> {
|
pub fn do_ioctl(fd: FileDesc, cmd: u32, argp: *mut u8) -> Result<isize> {
|
||||||
|
@ -43,6 +43,32 @@ static int __fcntl_setfl(int fd, int open_flags) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __fcntl_getlk_and_setlk(int fd, int open_flags) {
|
||||||
|
int ret;
|
||||||
|
struct flock fl = { F_WRLCK, SEEK_SET, 0, 0, 0 };
|
||||||
|
|
||||||
|
// getlk
|
||||||
|
ret = fcntl(fd, F_GETLK, &fl);
|
||||||
|
if (ret < 0) {
|
||||||
|
THROW_ERROR("failed to call getlk");
|
||||||
|
}
|
||||||
|
if (fl.l_type != F_UNLCK) {
|
||||||
|
THROW_ERROR("failed to get correct fl type");
|
||||||
|
}
|
||||||
|
|
||||||
|
// setlk
|
||||||
|
if ((open_flags & O_WRONLY) || (open_flags & O_RDWR))
|
||||||
|
fl.l_type = F_WRLCK;
|
||||||
|
else
|
||||||
|
fl.l_type = F_RDLCK;
|
||||||
|
ret = fcntl(fd, F_SETLK, &fl);
|
||||||
|
if (ret < 0) {
|
||||||
|
THROW_ERROR("failed to call setlk");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
typedef int(*test_fcntl_func_t)(int fd, int open_flags);
|
typedef int(*test_fcntl_func_t)(int fd, int open_flags);
|
||||||
|
|
||||||
static int test_fcntl_framework(test_fcntl_func_t fn) {
|
static int test_fcntl_framework(test_fcntl_func_t fn) {
|
||||||
@ -74,6 +100,10 @@ static int test_fcntl_setfl() {
|
|||||||
return test_fcntl_framework(__fcntl_setfl);
|
return test_fcntl_framework(__fcntl_setfl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_getlk_and_setlk() {
|
||||||
|
return test_fcntl_framework(__fcntl_getlk_and_setlk);
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Test suite
|
// Test suite
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -81,6 +111,7 @@ static int test_fcntl_setfl() {
|
|||||||
static test_case_t test_cases[] = {
|
static test_case_t test_cases[] = {
|
||||||
TEST_CASE(test_fcntl_getfl),
|
TEST_CASE(test_fcntl_getfl),
|
||||||
TEST_CASE(test_fcntl_setfl),
|
TEST_CASE(test_fcntl_setfl),
|
||||||
|
TEST_CASE(test_getlk_and_setlk),
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
Loading…
Reference in New Issue
Block a user