SMB performance optimization: pread/pwrite, tokio::sync::Mutex, direct response, fast-path

- VfsFile trait: add read_at()/write_at() with seek+read default impl
- LocalFs: override with real pread/pwrite (FileExt::read_at/write_at) — 1 syscall vs 2
- smb_server_backend: use read_at/write_at + tokio::sync::Mutex (non-blocking async)
- read handler: build response directly, avoid Bytes→Vec<u8> copy + intermediate struct
- oplock break: fast-path skip when ≤1 open entry (single-user scenario)
This commit is contained in:
Warren
2026-06-23 09:58:19 +08:00
parent e7863a3034
commit d4f60929fa
6 changed files with 58 additions and 31 deletions

View File

@@ -3,7 +3,7 @@ use super::util;
use super::{VfsAce, VfsAceFlag, VfsAceMask, VfsAceType, VfsAcl, VfsBackend, VfsDirEntry, VfsError, VfsFile, VfsPreviousVersion, VfsQuota, VfsQuotaUsage, VfsSnapshotInfo, VfsStat};
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Seek, SeekFrom, Write};
use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::os::unix::fs::{FileExt, MetadataExt, PermissionsExt};
use std::path::{Path, PathBuf};
use std::time::SystemTime;
@@ -42,6 +42,14 @@ impl VfsFile for LocalFile {
self.file.seek(pos).map_err(|e| VfsError::Io(e.to_string()))
}
fn read_at(&mut self, buf: &mut [u8], offset: u64) -> Result<usize, VfsError> {
self.file.read_at(buf, offset).map_err(|e| VfsError::Io(e.to_string()))
}
fn write_at(&mut self, buf: &[u8], offset: u64) -> Result<usize, VfsError> {
self.file.write_at(buf, offset).map_err(|e| VfsError::Io(e.to_string()))
}
fn flush(&mut self) -> Result<(), VfsError> {
self.file.flush().map_err(|e| VfsError::Io(e.to_string()))
}

View File

@@ -103,6 +103,20 @@ pub trait VfsFile: Send {
fn stat(&mut self) -> Result<VfsStat, VfsError>;
fn set_len(&mut self, size: u64) -> Result<(), VfsError>;
/// Read at `offset` without changing the seek position (like pread).
/// Default implementation does seek + read.
fn read_at(&mut self, buf: &mut [u8], offset: u64) -> Result<usize, VfsError> {
self.seek(std::io::SeekFrom::Start(offset))?;
self.read(buf)
}
/// Write at `offset` without changing the seek position (like pwrite).
/// Default implementation does seek + write.
fn write_at(&mut self, buf: &[u8], offset: u64) -> Result<usize, VfsError> {
self.seek(std::io::SeekFrom::Start(offset))?;
self.write(buf)
}
/// Write all bytes (convenience, default loops write() until done)
fn write_all(&mut self, mut buf: &[u8]) -> Result<(), VfsError> {
while !buf.is_empty() {

View File

@@ -1,7 +1,7 @@
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::Mutex;
use std::time::SystemTime;
use tokio::sync::Mutex;
use async_trait::async_trait;
use bytes::Bytes;
@@ -211,11 +211,9 @@ impl Handle for VfsHandle {
async fn read(&self, offset: u64, len: u32) -> Result<Bytes, SmbError> {
match self {
Self::File { file, .. } => {
let mut file = file.lock().unwrap();
file.seek(std::io::SeekFrom::Start(offset))
.map_err(vfs_error_to_io)?;
let mut file = file.lock().await;
let mut buf = vec![0u8; len as usize];
let n = file.read(&mut buf).map_err(map_error)?;
let n = file.read_at(&mut buf, offset).map_err(map_error)?;
buf.truncate(n);
Ok(Bytes::from(buf))
}
@@ -226,10 +224,8 @@ impl Handle for VfsHandle {
async fn write(&self, offset: u64, data: &[u8]) -> Result<u32, SmbError> {
match self {
Self::File { file, .. } => {
let mut file = file.lock().unwrap();
file.seek(std::io::SeekFrom::Start(offset))
.map_err(vfs_error_to_io)?;
let n = file.write(data).map_err(map_error)?;
let mut file = file.lock().await;
let n = file.write_at(data, offset).map_err(map_error)?;
Ok(n as u32)
}
Self::Directory { .. } => Err(SmbError::NotSupported),
@@ -239,7 +235,7 @@ impl Handle for VfsHandle {
async fn flush(&self) -> Result<(), SmbError> {
match self {
Self::File { file, .. } => {
let mut file = file.lock().unwrap();
let mut file = file.lock().await;
file.flush().map_err(map_error)
}
Self::Directory { .. } => Ok(()),
@@ -249,7 +245,7 @@ impl Handle for VfsHandle {
async fn stat(&self) -> Result<FileInfo, SmbError> {
match self {
Self::File { file, path, .. } => {
let mut f = file.lock().unwrap();
let mut f = file.lock().await;
let vfs_stat = f.stat().map_err(map_error)?;
Ok(vfs_stat_to_file_info(&vfs_stat, "", path))
}
@@ -278,7 +274,7 @@ impl Handle for VfsHandle {
async fn truncate(&self, len: u64) -> Result<(), SmbError> {
match self {
Self::File { file, .. } => {
let mut file = file.lock().unwrap();
let mut file = file.lock().await;
file.set_len(len).map_err(map_error)
}
Self::Directory { .. } => Err(SmbError::NotSupported),