From ba818d1266e796f63f46ec57cfd3477e47fbabc0 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 22 Aug 2025 20:21:43 +0100 Subject: [PATCH] Use a single device aligned buffer. --- Aaru.Devices/Linux/Command.cs | 12 +++++++----- Aaru.Devices/Linux/Device.cs | 31 +++++++++++++++++++++++++++++- Aaru.Devices/Windows/Command.cs | 17 +++++++++-------- Aaru.Devices/Windows/Device.cs | 34 +++++++++++++++++++++++++++++---- 4 files changed, 76 insertions(+), 18 deletions(-) diff --git a/Aaru.Devices/Linux/Command.cs b/Aaru.Devices/Linux/Command.cs index 63cf6978b..736e63d4a 100644 --- a/Aaru.Devices/Linux/Command.cs +++ b/Aaru.Devices/Linux/Command.cs @@ -64,6 +64,8 @@ partial class Device _ => ScsiIoctlDirection.Unknown }; + EnsureCapacityAligned((nuint)buffer.Length); + var ioHdr = new SgIoHdrT(); ioHdr.interface_id = 'S'; @@ -71,13 +73,14 @@ partial class Device ioHdr.mx_sb_len = (byte)SenseBuffer.Length; ioHdr.dxfer_direction = dir; ioHdr.dxfer_len = (uint)buffer.Length; - ioHdr.dxferp = Marshal.AllocHGlobal(buffer.Length); + ioHdr.dxferp = (IntPtr)_nativeBuffer; ioHdr.cmdp = (IntPtr)CdbPtr; ioHdr.sbp = (IntPtr)SensePtr; ioHdr.timeout = timeout * 1000; ioHdr.flags = (uint)SgFlags.DirectIo; - Marshal.Copy(buffer, 0, ioHdr.dxferp, buffer.Length); + // OUT or bidirectional → pre‑fill from managed buffer + if(direction != ScsiDirection.In) buffer.AsSpan().CopyTo(new Span((void*)_nativeBuffer, buffer.Length)); var cmdStopWatch = new Stopwatch(); cmdStopWatch.Start(); @@ -86,14 +89,13 @@ partial class Device if(error < 0) error = Marshal.GetLastWin32Error(); - Marshal.Copy(ioHdr.dxferp, buffer, 0, buffer.Length); + // IN or bidirectional → copy back into managed buffer + if(direction != ScsiDirection.Out) new Span((void*)_nativeBuffer, buffer.Length).CopyTo(buffer); sense |= (ioHdr.info & SgInfo.OkMask) != SgInfo.Ok; duration = ioHdr.duration > 0 ? ioHdr.duration : cmdStopWatch.Elapsed.TotalMilliseconds; - Marshal.FreeHGlobal(ioHdr.dxferp); - return error; } diff --git a/Aaru.Devices/Linux/Device.cs b/Aaru.Devices/Linux/Device.cs index 9f17c353a..c8c14dfe9 100644 --- a/Aaru.Devices/Linux/Device.cs +++ b/Aaru.Devices/Linux/Device.cs @@ -33,6 +33,7 @@ using System; using System.Globalization; using System.IO; +using System.Runtime.InteropServices; using System.Runtime.Versioning; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interop; @@ -47,14 +48,42 @@ namespace Aaru.Devices.Linux; /// [SupportedOSPlatform("linux")] -partial class Device : Devices.Device +partial class Device : Devices.Device, IDisposable { + private const nuint ALIGNMENT = 64; + private nuint _capacity; /// Gets the file handle representing this device /// The file handle int _fileDescriptor; +// Persistent, aligned native buffer + private nuint _nativeBuffer; + Device() {} +#region IDisposable Members + + public new unsafe void Dispose() + { + if(_nativeBuffer == 0) return; + NativeMemory.AlignedFree((void*)_nativeBuffer); + _nativeBuffer = 0; + _capacity = 0; + } + +#endregion + + + private unsafe void EnsureCapacityAligned(nuint size) + { + if(size <= _capacity) return; + + if(_nativeBuffer != 0) NativeMemory.AlignedFree((void*)_nativeBuffer); + + _nativeBuffer = (nuint)NativeMemory.AlignedAlloc(size, ALIGNMENT); + _capacity = size; + } + internal new static Device Create(string devicePath, out ErrorNumber errno) { errno = ErrorNumber.NoError; diff --git a/Aaru.Devices/Windows/Command.cs b/Aaru.Devices/Windows/Command.cs index 35d4a7e7e..f02214670 100644 --- a/Aaru.Devices/Windows/Command.cs +++ b/Aaru.Devices/Windows/Command.cs @@ -44,8 +44,8 @@ namespace Aaru.Devices.Windows; partial class Device { /// - public override int SendScsiCommand(Span cdb, ref byte[] buffer, uint timeout, ScsiDirection direction, - out double duration, out bool sense) + public override unsafe int SendScsiCommand(Span cdb, ref byte[] buffer, uint timeout, ScsiDirection direction, + out double duration, out bool sense) { // We need a timeout if(timeout == 0) timeout = Timeout > 0 ? Timeout : 15; @@ -62,6 +62,8 @@ partial class Device _ => ScsiIoctlDirection.Unspecified }; + EnsureCapacityAligned((nuint)buffer.Length); + var sptdSb = new ScsiPassThroughDirectAndSenseBuffer { SenseBuf = new byte[32], @@ -73,7 +75,7 @@ partial class Device DataIn = dir, DataTransferLength = (uint)buffer.Length, TimeOutValue = timeout, - DataBuffer = Marshal.AllocHGlobal(buffer.Length) + DataBuffer = (IntPtr)_nativeBuffer } }; @@ -81,11 +83,12 @@ partial class Device sptdSb.sptd.SenseInfoOffset = (uint)Marshal.SizeOf(sptdSb.sptd); cdb.CopyTo(sptdSb.sptd.Cdb); +// OUT or BiDir → pre‑copy + if(direction != ScsiDirection.In) buffer.AsSpan().CopyTo(new Span((void*)_nativeBuffer, buffer.Length)); + uint k = 0; int error = 0; - Marshal.Copy(buffer, 0, sptdSb.sptd.DataBuffer, buffer.Length); - var cmdStopwatch = new Stopwatch(); cmdStopwatch.Start(); @@ -102,7 +105,7 @@ partial class Device if(hasError) error = Marshal.GetLastWin32Error(); - Marshal.Copy(sptdSb.sptd.DataBuffer, buffer, 0, buffer.Length); + if(direction != ScsiDirection.Out) new Span((void*)_nativeBuffer, buffer.Length).CopyTo(buffer); sense |= sptdSb.sptd.ScsiStatus != 0; @@ -110,8 +113,6 @@ partial class Device duration = cmdStopwatch.Elapsed.TotalMilliseconds; - Marshal.FreeHGlobal(sptdSb.sptd.DataBuffer); - return error; } diff --git a/Aaru.Devices/Windows/Device.cs b/Aaru.Devices/Windows/Device.cs index 14f4d5d4f..6494fac89 100644 --- a/Aaru.Devices/Windows/Device.cs +++ b/Aaru.Devices/Windows/Device.cs @@ -43,14 +43,40 @@ namespace Aaru.Devices.Windows; /// [SupportedOSPlatform("windows")] -partial class Device : Devices.Device +partial class Device : Devices.Device, IDisposable { + private const nuint ALIGNMENT = 64; + private nuint _capacity; /// Gets the file handle representing this device /// The file handle SafeFileHandle _fileHandle; + private nuint _nativeBuffer; Device() {} +#region IDisposable Members + + public new unsafe void Dispose() + { + if(_nativeBuffer == 0) return; + NativeMemory.AlignedFree((void*)_nativeBuffer); + _nativeBuffer = 0; + _capacity = 0; + } + +#endregion + + private unsafe void EnsureCapacityAligned(nuint size) + { + if(size <= _capacity) return; + + if(_nativeBuffer != 0) NativeMemory.AlignedFree((void*)_nativeBuffer); + + _nativeBuffer = (nuint)NativeMemory.AlignedAlloc(size, ALIGNMENT); + + _capacity = size; + } + internal new static Device Create(string devicePath, out ErrorNumber errno) { errno = ErrorNumber.NoError; @@ -102,10 +128,10 @@ partial class Device : Devices.Device }; IntPtr descriptorPtr = Marshal.AllocHGlobal(1000); - var descriptorB = new byte[1000]; + byte[] descriptorB = new byte[1000]; uint returned = 0; - var error = 0; + int error = 0; bool hasError = !Extern.DeviceIoControlStorageQuery(dev._fileHandle, WindowsIoctl.IoctlStorageQueryProperty, @@ -203,7 +229,7 @@ partial class Device : Devices.Device if(IsSdhci(dev._fileHandle)) { - var sdBuffer = new byte[16]; + byte[] sdBuffer = new byte[16]; dev.LastError = dev.SendMmcCommand(MmcCommands.SendCsd, false,