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