enable UNMAP when LUN is thin provisioned

- support Block Limits VPD page (0xB0)
 - add UNMAP to REPORT SUPPORTED OPERATION CODES
 - READ CAPACITY(16): set LBPME when Thin provisioning is enabled
 - move Thinprovisioning and BlockShift to config
 - add Unmap to BackingStore
This commit is contained in:
chessman
2019-05-21 12:54:55 +03:00
parent e2192b7b01
commit 22d47a9212
10 changed files with 86 additions and 17 deletions
+2 -1
View File
@@ -19,7 +19,7 @@ import (
"errors" "errors"
"sync" "sync"
"github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
) )
type SCSICommandType byte type SCSICommandType byte
@@ -351,6 +351,7 @@ type BackingStore interface {
Write([]byte, int64) error Write([]byte, int64) error
DataSync() error DataSync() error
DataAdvise(int64, int64, uint32) error DataAdvise(int64, int64, uint32) error
Unmap() error
} }
type SCSIDeviceProtocol interface { type SCSIDeviceProtocol interface {
+5 -3
View File
@@ -101,9 +101,11 @@ var (
) )
type BackendStorage struct { type BackendStorage struct {
DeviceID uint64 `json:"deviceID"` DeviceID uint64 `json:"deviceID"`
Path string `json:"path"` Path string `json:"path"`
Online bool `json:"online"` Online bool `json:"online"`
Thinprovisioning bool `json:"thinprovisioning"`
BlockShift uint `json:"blockShift"`
} }
type ISCSIPortalInfo struct { type ISCSIPortalInfo struct {
+5 -1
View File
@@ -135,7 +135,11 @@ func bsPerformCommand(bs api.BackingStore, cmd *api.SCSICommand) (err error, key
doVerify = true doVerify = true
goto verify goto verify
case api.UNMAP: case api.UNMAP:
// TODO err = bs.Unmap()
if err != nil {
key = MEDIUM_ERROR
asc = NO_ADDITIONAL_SENSE
}
default: default:
break break
} }
+4
View File
@@ -149,3 +149,7 @@ func (bs *CephBackingStore) DataSync() error {
func (bs *CephBackingStore) DataAdvise(offset, length int64, advise uint32) error { func (bs *CephBackingStore) DataAdvise(offset, length int64, advise uint32) error {
return nil return nil
} }
func (bs *CephBackingStore) Unmap() error {
return nil
}
+4
View File
@@ -113,3 +113,7 @@ func (bs *FileBackingStore) DataSync() error {
func (bs *FileBackingStore) DataAdvise(offset, length int64, advise uint32) error { func (bs *FileBackingStore) DataAdvise(offset, length int64, advise uint32) error {
return util.Fadvise(bs.file, offset, length, advise) return util.Fadvise(bs.file, offset, length, advise)
} }
func (bs *FileBackingStore) Unmap() error {
return nil
}
+4
View File
@@ -74,3 +74,7 @@ func (bs *NullBackingStore) DataSync() error {
func (bs *NullBackingStore) DataAdvise(offset, length int64, advise uint32) error { func (bs *NullBackingStore) DataAdvise(offset, length int64, advise uint32) error {
return nil return nil
} }
func (bs *NullBackingStore) Unmap() error {
return nil
}
+7 -6
View File
@@ -20,13 +20,13 @@ import (
"strings" "strings"
"github.com/gostor/gotgt/pkg/api" "github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/config"
) )
// NewSCSILu: create a new SCSI LU // NewSCSILu: create a new SCSI LU
// path format <protocol>:/absolute/file/path // path format <protocol>:/absolute/file/path
func NewSCSILu(device_uuid uint64, path string, online bool) (*api.SCSILu, error) { func NewSCSILu(bs *config.BackendStorage) (*api.SCSILu, error) {
pathinfo := strings.SplitN(bs.Path, ":", 2)
pathinfo := strings.SplitN(path, ":", 2)
if len(pathinfo) < 2 { if len(pathinfo) < 2 {
return nil, errors.New("invalid device path string") return nil, errors.New("invalid device path string")
} }
@@ -43,8 +43,8 @@ func NewSCSILu(device_uuid uint64, path string, online bool) (*api.SCSILu, error
PerformCommand: luPerformCommand, PerformCommand: luPerformCommand,
DeviceProtocol: sbc, DeviceProtocol: sbc,
Storage: backing, Storage: backing,
BlockShift: api.DefaultBlockShift, BlockShift: bs.BlockShift,
UUID: device_uuid, UUID: bs.DeviceID,
} }
err = backing.Open(lu, backendPath) err = backing.Open(lu, backendPath)
@@ -53,7 +53,8 @@ func NewSCSILu(device_uuid uint64, path string, online bool) (*api.SCSILu, error
} }
lu.Size = backing.Size(lu) lu.Size = backing.Size(lu)
lu.DeviceProtocol.InitLu(lu) lu.DeviceProtocol.InitLu(lu)
lu.Attrs.Online = online lu.Attrs.Thinprovisioning = bs.Thinprovisioning
lu.Attrs.Online = bs.Online
lu.Attrs.Lbppbe = 3 lu.Attrs.Lbppbe = 3
return lu, nil return lu, nil
} }
+12 -2
View File
@@ -295,7 +295,13 @@ sense:
} }
func SBCUnmap(host int, cmd *api.SCSICommand) api.SAMStat { func SBCUnmap(host int, cmd *api.SCSICommand) api.SAMStat {
return api.SAMStatGood err, key, asc := bsPerformCommand(cmd.Device.Storage, cmd)
if err == nil {
return api.SAMStatGood
}
BuildSenseData(cmd, key, asc)
return api.SAMStatCheckCondition
} }
/* /*
@@ -594,7 +600,11 @@ func SBCReadCapacity16(host int, cmd *api.SCSICommand) api.SAMStat {
if allocationLength > 12 { if allocationLength > 12 {
copy(cmd.InSDBBuffer.Buffer[8:], util.MarshalUint32(uint32(1<<bshift))) copy(cmd.InSDBBuffer.Buffer[8:], util.MarshalUint32(uint32(1<<bshift)))
if allocationLength > 16 { if allocationLength > 16 {
val := (cmd.Device.Attrs.Lbppbe << 16) | cmd.Device.Attrs.LowestAlignedLBA var lbpme int
if cmd.Device.Attrs.Thinprovisioning {
lbpme = 1
}
val := (cmd.Device.Attrs.Lbppbe << 16) | (lbpme << 15) | cmd.Device.Attrs.LowestAlignedLBA
copy(cmd.InSDBBuffer.Buffer[12:], util.MarshalUint32(uint32(val))) copy(cmd.InSDBBuffer.Buffer[12:], util.MarshalUint32(uint32(val)))
} }
} }
+1 -1
View File
@@ -73,7 +73,7 @@ func InitSCSILUMap(config *config.Config) error {
defer globalSCSILUMap.mutex.Unlock() defer globalSCSILUMap.mutex.Unlock()
for _, bs := range config.Storages { for _, bs := range config.Storages {
lu, err := NewSCSILu(bs.DeviceID, bs.Path, bs.Online) lu, err := NewSCSILu(&bs)
if err != nil { if err != nil {
return fmt.Errorf("Init SCSI LU map error: %v", err) return fmt.Errorf("Init SCSI LU map error: %v", err)
} }
+42 -3
View File
@@ -25,7 +25,7 @@ import (
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"github.com/gostor/gotgt/pkg/api" "github.com/gostor/gotgt/pkg/api"
"github.com/gostor/gotgt/pkg/util" "github.com/gostor/gotgt/pkg/util"
"github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
) )
func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat { func SPCIllegalOp(host int, cmd *api.SCSICommand) api.SAMStat {
@@ -58,6 +58,7 @@ func InquiryPage0x00(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
descBuf.WriteByte(0x00) descBuf.WriteByte(0x00)
descBuf.WriteByte(0x80) descBuf.WriteByte(0x80)
descBuf.WriteByte(0x83) descBuf.WriteByte(0x83)
descBuf.WriteByte(0xB0)
/* /*
TODO: TODO:
descBuf.WriteByte(0x86) descBuf.WriteByte(0x86)
@@ -188,6 +189,42 @@ func InquiryPage0x83(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
return buf, pageLength return buf, pageLength
} }
func InquiryPage0xB0(host int, cmd *api.SCSICommand) (*bytes.Buffer, uint16) {
var (
buf = &bytes.Buffer{}
pageLength uint16 = 0x3C
maxUnmapLbaCount uint32 = 0
maxUnmapBlockDescriptorCount uint32 = 0
)
if cmd.Device.Attrs.Thinprovisioning {
maxUnmapLbaCount = 0xFFFFFFFF
maxUnmapBlockDescriptorCount = 0xFFFFFFFF
}
//byte 0
if cmd.Device.Attrs.Online {
buf.WriteByte(PQ_DEVICE_CONNECTED | byte(cmd.Device.Attrs.DeviceType))
} else {
buf.WriteByte(PQ_DEVICE_NOT_CONNECT | byte(cmd.Device.Attrs.DeviceType))
}
//PAGE CODE
buf.WriteByte(0xB0)
//PAGE LENGTH
binary.Write(buf, binary.BigEndian, pageLength)
buf.Write(make([]byte, 16))
//MAXIMUM UNMAP LBA COUNT
binary.Write(buf, binary.BigEndian, maxUnmapLbaCount)
//MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT
binary.Write(buf, binary.BigEndian, maxUnmapBlockDescriptorCount)
buf.Write(make([]byte, 36))
return buf, pageLength
}
/* /*
* SPCInquiry Implements SCSI INQUIRY command * SPCInquiry Implements SCSI INQUIRY command
* The INQUIRY command requests the device server to return information regarding the logical unit and SCSI target device. * The INQUIRY command requests the device server to return information regarding the logical unit and SCSI target device.
@@ -231,6 +268,8 @@ func SPCInquiry(host int, cmd *api.SCSICommand) api.SAMStat {
buf, _ = InquiryPage0x80(host, cmd) buf, _ = InquiryPage0x80(host, cmd)
case 0x83: case 0x83:
buf, _ = InquiryPage0x83(host, cmd) buf, _ = InquiryPage0x83(host, cmd)
case 0xB0:
buf, _ = InquiryPage0xB0(host, cmd)
default: default:
goto sense goto sense
} }
@@ -610,7 +649,7 @@ func reportOpcodesAll(cmd *api.SCSICommand, rctd int) error {
var ( var (
data = []byte{0x00, 0x00, 0x00, 0x00} data = []byte{0x00, 0x00, 0x00, 0x00}
) )
for _, i := range []api.SCSICommandType{api.TEST_UNIT_READY, api.WRITE_6, api.INQUIRY, api.READ_CAPACITY, api.WRITE_10, api.WRITE_16, api.REPORT_LUNS, api.WRITE_12} { for _, i := range []api.SCSICommandType{api.TEST_UNIT_READY, api.WRITE_6, api.INQUIRY, api.READ_CAPACITY, api.WRITE_10, api.WRITE_16, api.REPORT_LUNS, api.WRITE_12, api.UNMAP} {
data = append(data, byte(i)) data = append(data, byte(i))
// reserved // reserved
data = append(data, 0x00) data = append(data, 0x00)
@@ -627,7 +666,7 @@ func reportOpcodesAll(cmd *api.SCSICommand, rctd int) error {
} }
// cdb length // cdb length
length := getSCSICmdSize(i) length := getSCSICmdSize(i)
data = append(data, (length>>8)&0xff) data = append(data, 0)
data = append(data, length&0xff) data = append(data, length&0xff)
// timeout descriptor // timeout descriptor
if rctd != 0 { if rctd != 0 {