os/vfs/
file_lock.rs

1//! 文件锁管理
2//!
3//! 实现 POSIX 文件锁(advisory locks)语义:
4//! - 读锁(共享锁)之间兼容
5//! - 写锁(独占锁)与任何锁互斥
6//! - 同一进程的锁可以合并/覆盖
7//! - 进程退出时自动释放所有锁
8
9use crate::sync::SpinLock;
10use crate::uapi::fcntl::{Flock, LockType};
11use crate::vfs::FsError;
12use alloc::collections::BTreeMap;
13use alloc::vec::Vec;
14
15/// 文件锁条目
16#[derive(Debug, Clone)]
17struct FileLockEntry {
18    /// 锁类型
19    lock_type: LockType,
20    /// 起始位置(绝对偏移)
21    start: usize,
22    /// 长度
23    len: usize,
24    /// 持有锁的进程 PID
25    pid: i32,
26}
27
28impl FileLockEntry {
29    /// 检查锁范围是否重叠
30    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    /// 检查与另一个锁是否冲突
37    fn conflicts_with(&self, other: &FileLockEntry) -> bool {
38        if !self.overlaps(other.start, other.len) {
39            return false;
40        }
41
42        // 同一进程的锁不冲突
43        if self.pid == other.pid {
44            return false;
45        }
46
47        // 读锁之间不冲突
48        if self.lock_type == LockType::Read && other.lock_type == LockType::Read {
49            return false;
50        }
51
52        // 其他情况都冲突
53        true
54    }
55}
56
57/// 文件标识符(设备号 + inode 号)
58#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
59struct FileId {
60    dev: u64,
61    ino: u64,
62}
63
64/// 全局文件锁管理器
65pub struct FileLockManager {
66    /// 文件锁表:FileId -> 锁列表
67    locks: SpinLock<BTreeMap<FileId, Vec<FileLockEntry>>>,
68}
69
70impl FileLockManager {
71    /// 创建新的文件锁管理器
72    pub const fn new() -> Self {
73        Self {
74            locks: SpinLock::new(BTreeMap::new()),
75        }
76    }
77
78    /// 测试锁(F_GETLK)
79    ///
80    /// 检查是否有锁会阻塞请求的锁。如果有冲突,返回冲突锁的信息。
81    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        // 构造请求的锁(使用传入的范围参数)
101        let requested_lock = FileLockEntry {
102            lock_type,
103            start,
104            len,
105            pid,
106        };
107
108        // 检查是否有冲突的锁
109        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 结构
113                    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; // SEEK_SET
118                    return Ok(());
119                }
120            }
121        }
122
123        // 没有冲突,设置为 F_UNLCK
124        flock.l_type = LockType::Unlock as i16;
125        Ok(())
126    }
127
128    /// 设置锁(F_SETLK / F_SETLKW)
129    ///
130    /// # 参数
131    /// - `blocking`: true 表示阻塞(F_SETLKW),false 表示非阻塞(F_SETLK)
132    ///
133    /// # TODO: 实现 F_SETLKW 阻塞等待
134    /// 当前实现在锁冲突时立即返回 WouldBlock,即使 blocking=true。
135    ///
136    /// 完整的 F_SETLKW 实现需要:
137    /// 1. 在 FileLockManager 中为每个文件维护一个 WaitQueue
138    /// 2. 锁冲突时,如果 blocking=true:
139    ///    - 将当前任务加入该文件的等待队列
140    ///    - 调用 yield_task() 让出 CPU
141    ///    - 被唤醒后重新检查并尝试获取锁(可能需要循环)
142    /// 3. 释放锁时(包括进程退出),唤醒等待队列中的所有任务
143    /// 4. 需要处理信号中断(返回 EINTR)
144    ///
145    /// 参考实现:
146    /// ```ignore
147    /// loop {
148    ///     if can_acquire_lock() {
149    ///         acquire_and_break();
150    ///     }
151    ///     if !blocking {
152    ///         return Err(WouldBlock);
153    ///     }
154    ///     // 检查信号
155    ///     if has_pending_signal() {
156    ///         return Err(Interrupted);
157    ///     }
158    ///     wait_queue.sleep(current_task());
159    /// }
160    /// ```
161    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                // 释放锁:移除指定范围的锁
177                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                // 检查是否有冲突
187                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                // 检查冲突
197                for existing_lock in file_locks.iter() {
198                    if existing_lock.conflicts_with(&new_lock) {
199                        // 有冲突
200                        // TODO: 如果 blocking=true,应该阻塞等待
201                        return Err(FsError::WouldBlock);
202                    }
203                }
204
205                // 移除同一进程在重叠范围内的旧锁
206                file_locks.retain(|lock| !(lock.pid == pid && lock.overlaps(start, len)));
207
208                // 添加新锁
209                file_locks.push(new_lock);
210                Ok(())
211            }
212        }
213    }
214
215    /// 释放进程持有的所有锁(进程退出时调用)
216    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
225/// 全局文件锁管理器实例
226static FILE_LOCK_MANAGER: FileLockManager = FileLockManager::new();
227
228/// 获取全局文件锁管理器
229pub fn file_lock_manager() -> &'static FileLockManager {
230    &FILE_LOCK_MANAGER
231}