1use crate::sync::SpinLock;
10use crate::uapi::fcntl::{Flock, LockType};
11use crate::vfs::FsError;
12use alloc::collections::BTreeMap;
13use alloc::vec::Vec;
14
15#[derive(Debug, Clone)]
17struct FileLockEntry {
18 lock_type: LockType,
20 start: usize,
22 len: usize,
24 pid: i32,
26}
27
28impl FileLockEntry {
29 fn overlaps(&self, start: usize, len: usize) -> bool {
31 let self_end = self.start.saturating_add(self.len);
32 let other_end = start.saturating_add(len);
33 !(self_end <= start || other_end <= self.start)
34 }
35
36 fn conflicts_with(&self, other: &FileLockEntry) -> bool {
38 if !self.overlaps(other.start, other.len) {
39 return false;
40 }
41
42 if self.pid == other.pid {
44 return false;
45 }
46
47 if self.lock_type == LockType::Read && other.lock_type == LockType::Read {
49 return false;
50 }
51
52 true
54 }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
59struct FileId {
60 dev: u64,
61 ino: u64,
62}
63
64pub struct FileLockManager {
66 locks: SpinLock<BTreeMap<FileId, Vec<FileLockEntry>>>,
68}
69
70impl FileLockManager {
71 pub const fn new() -> Self {
73 Self {
74 locks: SpinLock::new(BTreeMap::new()),
75 }
76 }
77
78 pub fn test_lock(
82 &self,
83 dev: u64,
84 ino: u64,
85 start: usize,
86 len: usize,
87 flock: &mut Flock,
88 pid: i32,
89 ) -> Result<(), FsError> {
90 let file_id = FileId { dev, ino };
91 let locks = self.locks.lock();
92
93 let lock_type = match LockType::from_raw(flock.l_type) {
94 Some(LockType::Read) | Some(LockType::Write) => {
95 LockType::from_raw(flock.l_type).unwrap()
96 }
97 _ => return Err(FsError::InvalidArgument),
98 };
99
100 let requested_lock = FileLockEntry {
102 lock_type,
103 start,
104 len,
105 pid,
106 };
107
108 if let Some(file_locks) = locks.get(&file_id) {
110 for existing_lock in file_locks {
111 if existing_lock.conflicts_with(&requested_lock) {
112 flock.l_type = existing_lock.lock_type as i16;
114 flock.l_start = existing_lock.start as i64;
115 flock.l_len = existing_lock.len as i64;
116 flock.l_pid = existing_lock.pid;
117 flock.l_whence = 0; return Ok(());
119 }
120 }
121 }
122
123 flock.l_type = LockType::Unlock as i16;
125 Ok(())
126 }
127
128 pub fn set_lock(
162 &self,
163 dev: u64,
164 ino: u64,
165 start: usize,
166 len: usize,
167 lock_type: LockType,
168 pid: i32,
169 _blocking: bool,
170 ) -> Result<(), FsError> {
171 let file_id = FileId { dev, ino };
172 let mut locks = self.locks.lock();
173
174 match lock_type {
175 LockType::Unlock => {
176 if let Some(file_locks) = locks.get_mut(&file_id) {
178 file_locks.retain(|lock| !(lock.pid == pid && lock.overlaps(start, len)));
179 if file_locks.is_empty() {
180 locks.remove(&file_id);
181 }
182 }
183 Ok(())
184 }
185 LockType::Read | LockType::Write => {
186 let file_locks = locks.entry(file_id).or_insert_with(Vec::new);
188
189 let new_lock = FileLockEntry {
190 lock_type,
191 start,
192 len,
193 pid,
194 };
195
196 for existing_lock in file_locks.iter() {
198 if existing_lock.conflicts_with(&new_lock) {
199 return Err(FsError::WouldBlock);
202 }
203 }
204
205 file_locks.retain(|lock| !(lock.pid == pid && lock.overlaps(start, len)));
207
208 file_locks.push(new_lock);
210 Ok(())
211 }
212 }
213 }
214
215 pub fn release_all_locks(&self, pid: i32) {
217 let mut locks = self.locks.lock();
218 for file_locks in locks.values_mut() {
219 file_locks.retain(|lock| lock.pid != pid);
220 }
221 locks.retain(|_, file_locks| !file_locks.is_empty());
222 }
223}
224
225static FILE_LOCK_MANAGER: FileLockManager = FileLockManager::new();
227
228pub fn file_lock_manager() -> &'static FileLockManager {
230 &FILE_LOCK_MANAGER
231}