From 54ce0d69163c0180dd0a110e461959b7ef115099 Mon Sep 17 00:00:00 2001 From: Warren Date: Sun, 21 Jun 2026 00:19:51 +0800 Subject: [PATCH] Implement SMB Oplocks Phase 4+6 Phase 4: CREATE Handler dynamic oplock granting - Use OplockManager.can_grant() to determine oplock level - Register OplockEntry if oplock granted - Support ShareAccess compatibility checking - Grant Level II if exclusive/batch oplock exists Phase 6: CLOSE Handler oplock cleanup - Unregister from OplockManager when file closed - Only unregister if oplock_level > 0 All 229 tests pass. --- vendor/smb-server/src/handlers/close.rs | 8 +++++- vendor/smb-server/src/handlers/create.rs | 33 +++++++++++++++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/vendor/smb-server/src/handlers/close.rs b/vendor/smb-server/src/handlers/close.rs index 27432ce..0c3e139 100644 --- a/vendor/smb-server/src/handlers/close.rs +++ b/vendor/smb-server/src/handlers/close.rs @@ -15,7 +15,7 @@ use crate::server::ServerState; const FLAG_POSTQUERY_ATTRIB: u16 = 0x0001; pub async fn handle( - _server: &Arc, + server: &Arc, conn: &Arc, hdr: &Smb2Header, body: &[u8], @@ -43,9 +43,15 @@ pub async fn handle( let handle = open.handle.take(); let path = open.last_path.clone(); let delete_on_close = open.delete_on_close; + let oplock_level = open.oplock_level; let want_attrs = req.flags & FLAG_POSTQUERY_ATTRIB != 0; drop(open); + // Phase 6: Unregister from OplockManager if oplock was granted + if oplock_level > 0 { + server.oplock_manager.unregister(&path, &req.file_id).await; + } + // Stat before closing if needed. let info_before_close = if want_attrs { if let Some(h) = handle.as_ref() { diff --git a/vendor/smb-server/src/handlers/create.rs b/vendor/smb-server/src/handlers/create.rs index ea65a95..b223f7c 100644 --- a/vendor/smb-server/src/handlers/create.rs +++ b/vendor/smb-server/src/handlers/create.rs @@ -46,7 +46,7 @@ const FILE_OPENED: u32 = 0x0000_0001; const FILE_CREATED: u32 = 0x0000_0002; pub async fn handle( - _server: &Arc, + server: &Arc, conn: &Arc, hdr: &Smb2Header, body: &[u8], @@ -154,14 +154,39 @@ pub async fn handle( let tree = tree_arc.write().await; let file_id = tree.alloc_file_id(); - // Phase 4: Oplock support - determine oplock level - let granted_oplock = 0; // Phase 1 placeholder (will be dynamic in Phase 4) + // Phase 4: Oplock support - use OplockManager to determine granted level + let requested_oplock = req.requested_oplock_level; + let granted_oplock = if requested_oplock == 0 { + 0 // No oplock requested + } else { + // Check with OplockManager + server.oplock_manager.can_grant( + &path, + requested_oplock, + req.share_access, + if want_write { granted } else { Access::Read }, + ).await.unwrap_or(0) + }; + + // Register with OplockManager if oplock granted + if granted_oplock > 0 { + use crate::oplock::OplockEntry; + server.oplock_manager.register(&path, OplockEntry { + file_id, + tree_id: tree.id, + session_id: hdr.session_id, + oplock_level: granted_oplock, + share_access: req.share_access, + granted_access: if want_write { granted } else { Access::Read }, + connection_id: 0, // Will be tracked in Phase 3 + }).await; + } let open = Open::new( file_id, handle, if want_write { granted } else { Access::Read }, - path, + path.clone(), info.is_directory, delete_on_close, granted_oplock, // oplock_level