From 00d0c3a3063aff9fd98cf868e39b1a484ca6eed4 Mon Sep 17 00:00:00 2001 From: Lei Xue Date: Sat, 14 Mar 2026 12:29:12 +0800 Subject: [PATCH] fix UNMAP data corruption by implementing block zeroing The UNMAP command was a no-op in all backing stores, causing unmapped blocks to retain stale data instead of returning zeros per SCSI spec. - Implement Unmap in FileBackingStore to zero out unmapped blocks - Implement Unmap in IOUringBackingStore to zero out unmapped blocks - Enable Unmap in RemBackingStore (was commented out) - Change UnmapBlockDescriptor.TL from uint32 to uint64 to prevent integer overflow when converting block count to byte length with large block shifts Fixes #119 Co-Authored-By: Claude Opus 4.6 (1M context) --- pkg/api/types.go | 2 +- pkg/scsi/backingstore/common.go | 8 +++++++- pkg/scsi/backingstore/iouring/iouring_linux.go | 10 ++++++++-- pkg/scsi/backingstore/remote/remote.go | 6 +++++- pkg/scsi/sbc.go | 2 +- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/pkg/api/types.go b/pkg/api/types.go index 2ab3f1d..1c5aa38 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -409,7 +409,7 @@ type LUNMap map[uint64]*SCSILu type UnmapBlockDescriptor struct { Offset uint64 - TL uint32 + TL uint64 } type ReaderWriterAt interface { diff --git a/pkg/scsi/backingstore/common.go b/pkg/scsi/backingstore/common.go index 16a83b1..f8abfe3 100644 --- a/pkg/scsi/backingstore/common.go +++ b/pkg/scsi/backingstore/common.go @@ -159,6 +159,12 @@ func (bs *FileBackingStore) DataAdvise(offset, length int64, advise uint32) erro return util.Fadvise(bs.file, offset, length, advise) } -func (bs *FileBackingStore) Unmap([]api.UnmapBlockDescriptor) error { +func (bs *FileBackingStore) Unmap(descriptors []api.UnmapBlockDescriptor) error { + for _, desc := range descriptors { + zeros := make([]byte, desc.TL) + if _, err := bs.file.WriteAt(zeros, int64(desc.Offset)); err != nil { + return err + } + } return nil } diff --git a/pkg/scsi/backingstore/iouring/iouring_linux.go b/pkg/scsi/backingstore/iouring/iouring_linux.go index 3a2767c..726271b 100644 --- a/pkg/scsi/backingstore/iouring/iouring_linux.go +++ b/pkg/scsi/backingstore/iouring/iouring_linux.go @@ -628,8 +628,14 @@ func (bs *IOUringBackingStore) DataAdvise(offset, length int64, advise uint32) e return nil } -// Unmap is a no-op for file-based storage -func (bs *IOUringBackingStore) Unmap([]api.UnmapBlockDescriptor) error { +// Unmap zeros out the specified blocks +func (bs *IOUringBackingStore) Unmap(descriptors []api.UnmapBlockDescriptor) error { + for _, desc := range descriptors { + zeros := make([]byte, desc.TL) + if _, err := bs.file.WriteAt(zeros, int64(desc.Offset)); err != nil { + return err + } + } return nil } diff --git a/pkg/scsi/backingstore/remote/remote.go b/pkg/scsi/backingstore/remote/remote.go index 5d6a12e..9f6b342 100644 --- a/pkg/scsi/backingstore/remote/remote.go +++ b/pkg/scsi/backingstore/remote/remote.go @@ -113,6 +113,10 @@ func (bs *RemBackingStore) DataSync(offset, length int64) (err error) { } func (bs *RemBackingStore) Unmap(bd []api.UnmapBlockDescriptor) (err error) { - //_, err = bs.RemBs.Unmap(int64(bd[0].Offset), int64(bd[0].TL)) + for _, desc := range bd { + if _, err = bs.RemBs.Unmap(int64(desc.Offset), int64(desc.TL)); err != nil { + return + } + } return } diff --git a/pkg/scsi/sbc.go b/pkg/scsi/sbc.go index 290e5dc..10aeef9 100644 --- a/pkg/scsi/sbc.go +++ b/pkg/scsi/sbc.go @@ -320,7 +320,7 @@ func SBCUnmap(host int, cmd *api.SCSICommand) api.SAMStat { num := binary.BigEndian.Uint32(cmd.OutSDBBuffer.Buffer[off+8 : off+12]) blockDescs = append(blockDescs, api.UnmapBlockDescriptor{ Offset: lba << cmd.Device.BlockShift, - TL: num << cmd.Device.BlockShift, + TL: uint64(num) << cmd.Device.BlockShift, }) }