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::fcntl::{do_fcntl, FcntlCmd}; | ||||
| 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::fsync::{do_fdatasync, do_fsync}; | ||||
| pub use self::getdents::{do_getdents, do_getdents64}; | ||||
| @ -38,6 +39,7 @@ mod dup; | ||||
| mod fallocate; | ||||
| mod fcntl; | ||||
| mod file_flags; | ||||
| mod flock; | ||||
| mod fspath; | ||||
| mod fsync; | ||||
| mod getdents; | ||||
|  | ||||
| @ -338,6 +338,46 @@ impl INodeFile { | ||||
| 
 | ||||
|         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 { | ||||
|  | ||||
							
								
								
									
										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::*; | ||||
| 
 | ||||
| pub mod flock; | ||||
| pub mod range_lock; | ||||
|  | ||||
| @ -23,13 +23,14 @@ pub use self::file_ops::{ | ||||
|     IfConf, IoctlCmd, Stat, StatusFlags, StructuredIoctlArgType, StructuredIoctlNum, | ||||
| }; | ||||
| 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_view::FsView; | ||||
| pub use self::host_fd::HostFd; | ||||
| 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::rootfs::ROOT_FS; | ||||
| pub use self::stdio::{HostStdioFds, StdinFile, StdoutFile}; | ||||
| @ -43,12 +44,12 @@ mod events; | ||||
| mod file; | ||||
| mod file_ops; | ||||
| mod file_table; | ||||
| mod locks; | ||||
| mod fs_ops; | ||||
| mod fs_view; | ||||
| mod host_fd; | ||||
| mod hostfs; | ||||
| mod inode_file; | ||||
| mod locks; | ||||
| mod pipe; | ||||
| mod procfs; | ||||
| mod rootfs; | ||||
|  | ||||
| @ -693,3 +693,10 @@ pub fn do_umount(target: *const i8, flags: u32) -> Result<isize> { | ||||
|     fs_ops::do_umount(&target, flags)?; | ||||
|     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::{ | ||||
|     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_fchown, do_fchownat, do_fcntl, do_fdatasync, do_fstat, do_fstatat, do_fstatfs, do_fsync, | ||||
|     do_ftruncate, do_getcwd, do_getdents, do_getdents64, do_ioctl, do_lchown, do_link, do_linkat, | ||||
|     do_lseek, do_lstat, do_mkdir, do_mkdirat, do_mount, do_mount_rootfs, do_open, do_openat, | ||||
|     do_pipe, do_pipe2, do_pread, do_pwrite, do_read, do_readlink, do_readlinkat, do_readv, | ||||
|     do_rename, do_renameat, do_rmdir, do_sendfile, do_stat, do_statfs, do_symlink, do_symlinkat, | ||||
|     do_sync, do_timerfd_create, do_timerfd_gettime, do_timerfd_settime, do_truncate, do_umask, | ||||
|     do_umount, do_unlink, do_unlinkat, do_write, do_writev, iovec_t, AsTimer, File, FileDesc, | ||||
|     FileRef, HostStdioFds, Stat, Statfs, | ||||
|     do_fchown, do_fchownat, do_fcntl, do_fdatasync, do_flock, do_fstat, do_fstatat, do_fstatfs, | ||||
|     do_fsync, do_ftruncate, do_getcwd, do_getdents, do_getdents64, do_ioctl, do_lchown, do_link, | ||||
|     do_linkat, do_lseek, do_lstat, do_mkdir, do_mkdirat, do_mount, do_mount_rootfs, do_open, | ||||
|     do_openat, do_pipe, do_pipe2, do_pread, do_pwrite, do_read, do_readlink, do_readlinkat, | ||||
|     do_readv, do_rename, do_renameat, do_rmdir, do_sendfile, do_stat, do_statfs, do_symlink, | ||||
|     do_symlinkat, do_sync, do_timerfd_create, do_timerfd_gettime, do_timerfd_settime, do_truncate, | ||||
|     do_umask, do_umount, do_unlink, do_unlinkat, do_write, do_writev, iovec_t, AsTimer, File, | ||||
|     FileDesc, FileRef, HostStdioFds, Stat, Statfs, | ||||
| }; | ||||
| use crate::interrupt::{do_handle_interrupt, sgx_interrupt_info_t}; | ||||
| 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(), | ||||
|             (Msgctl = 71) => handle_unsupported(), | ||||
|             (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), | ||||
|             (Fdatasync = 75) => do_fdatasync(fd: FileDesc), | ||||
|             (Truncate = 76) => do_truncate(path: *const i8, len: usize), | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user