Files
seaweedfs/weed/storage/blockvol/lba.go
T
Ping QiuandClaude Opus 4.6 6a400f6760 feat: add BlockVol engine and iSCSI target (Phase 1 + Phase 2)
Phase 1: Extent-mapped block storage engine with WAL, crash recovery,
dirty map, flusher, and group commit. 174 tests, zero SeaweedFS imports.

Phase 2: Pure Go iSCSI target (RFC 7143) with PDU codec, login
negotiation, SendTargets discovery, 12 SCSI opcodes, Data-In/Out/R2T
sequencing, session management, and standalone iscsi-target binary.
164 tests. IQN->BlockDevice binding via DeviceLookup interface.

Total: 338 tests, 14.6K lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 09:32:01 -08:00

39 lines
1.2 KiB
Go

package blockvol
import (
"errors"
"fmt"
)
var (
ErrLBAOutOfBounds = errors.New("blockvol: LBA out of bounds")
ErrWritePastEnd = errors.New("blockvol: write extends past volume end")
ErrAlignment = errors.New("blockvol: data length not aligned to block size")
)
// ValidateLBA checks that lba is within the volume's logical address space.
func ValidateLBA(lba uint64, volumeSize uint64, blockSize uint32) error {
maxLBA := volumeSize / uint64(blockSize)
if lba >= maxLBA {
return fmt.Errorf("%w: lba=%d, max=%d", ErrLBAOutOfBounds, lba, maxLBA-1)
}
return nil
}
// ValidateWrite checks that a write at lba with dataLen bytes fits within
// the volume and that dataLen is aligned to blockSize.
func ValidateWrite(lba uint64, dataLen uint32, volumeSize uint64, blockSize uint32) error {
if err := ValidateLBA(lba, volumeSize, blockSize); err != nil {
return err
}
if dataLen%blockSize != 0 {
return fmt.Errorf("%w: dataLen=%d, blockSize=%d", ErrAlignment, dataLen, blockSize)
}
blocksNeeded := uint64(dataLen / blockSize)
maxLBA := volumeSize / uint64(blockSize)
if lba+blocksNeeded > maxLBA {
return fmt.Errorf("%w: lba=%d, blocks=%d, max=%d", ErrWritePastEnd, lba, blocksNeeded, maxLBA)
}
return nil
}