Implement stats and resize and fix remote backing store apis
- Convert constant to var so that it can be configured from backend - Add options to disable persistent reservation and ORWrite16 commands Signed-off-by: Utkarsh Mani Tripathi <utkarsh.tripathi@mayadata.io>
This commit is contained in:
@@ -239,6 +239,7 @@ func parseHeader(data []byte) (*ISCSICommand, error) {
|
||||
m.Write = data[1]&0x20 == 0x20
|
||||
m.CDB = data[32:48]
|
||||
m.ExpStatSN = uint32(ParseUint(data[28:32]))
|
||||
m.SCSIOpCode = m.CDB[0]
|
||||
SCSIOpcode := api.SCSICommandType(m.SCSIOpCode)
|
||||
switch SCSIOpcode {
|
||||
case api.READ_6, api.READ_10, api.READ_12, api.READ_16:
|
||||
|
||||
+10
-6
@@ -51,6 +51,7 @@ var (
|
||||
)
|
||||
|
||||
type iscsiConnection struct {
|
||||
ConnNum int
|
||||
state int
|
||||
authState int
|
||||
session *ISCSISession
|
||||
@@ -96,12 +97,13 @@ const (
|
||||
)
|
||||
|
||||
type iscsiTask struct {
|
||||
tag uint32
|
||||
conn *iscsiConnection
|
||||
cmd *ISCSICommand
|
||||
scmd *api.SCSICommand
|
||||
state taskState
|
||||
result byte
|
||||
tag uint32
|
||||
conn *iscsiConnection
|
||||
cmd *ISCSICommand
|
||||
scmd *api.SCSICommand
|
||||
state taskState
|
||||
expectedDataLength int64
|
||||
result byte
|
||||
|
||||
offset int
|
||||
r2tCount int
|
||||
@@ -154,6 +156,7 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
|
||||
task = conn.rxTask
|
||||
}
|
||||
conn.resp = &ISCSICommand{
|
||||
StartTime: conn.req.StartTime,
|
||||
StatSN: conn.req.ExpStatSN,
|
||||
TaskTag: conn.req.TaskTag,
|
||||
ExpCmdSN: conn.session.ExpCmdSN,
|
||||
@@ -172,6 +175,7 @@ func (conn *iscsiConnection) buildRespPackage(oc OpCode, task *iscsiTask) error
|
||||
}
|
||||
case OpSCSIIn, OpSCSIResp:
|
||||
conn.resp.OpCode = oc
|
||||
conn.resp.SCSIOpCode = conn.req.SCSIOpCode
|
||||
conn.resp.Immediate = true
|
||||
conn.resp.Final = true
|
||||
conn.resp.SCSIResponse = 0x00
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gostor/gotgt/pkg/api"
|
||||
"github.com/gostor/gotgt/pkg/config"
|
||||
@@ -35,6 +36,17 @@ const (
|
||||
ISCSI_UNSPEC_TSIH = uint16(0)
|
||||
)
|
||||
|
||||
const (
|
||||
STATE_INIT = iota
|
||||
STATE_RUNNING
|
||||
STATE_SHUTTING_DOWN
|
||||
STATE_TERMINATE
|
||||
)
|
||||
|
||||
var (
|
||||
EnableStats bool
|
||||
)
|
||||
|
||||
type ISCSITargetDriver struct {
|
||||
SCSI *scsi.SCSITargetService
|
||||
Name string
|
||||
@@ -42,9 +54,13 @@ type ISCSITargetDriver struct {
|
||||
TSIHPool map[uint16]bool
|
||||
TSIHPoolMutex sync.Mutex
|
||||
isClientConnected bool
|
||||
|
||||
mu sync.Mutex
|
||||
l net.Listener
|
||||
enableStats bool
|
||||
SCSIIOCount map[int]int64
|
||||
mu *sync.RWMutex
|
||||
l net.Listener
|
||||
state uint8
|
||||
OpCode int
|
||||
TargetStats scsi.Stats
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -52,12 +68,19 @@ func init() {
|
||||
}
|
||||
|
||||
func NewISCSITargetDriver(base *scsi.SCSITargetService) (scsi.SCSITargetDriver, error) {
|
||||
return &ISCSITargetDriver{
|
||||
driver := &ISCSITargetDriver{
|
||||
Name: iSCSIDriverName,
|
||||
iSCSITargets: map[string]*ISCSITarget{},
|
||||
SCSI: base,
|
||||
TSIHPool: map[uint16]bool{0: true, 65535: true},
|
||||
}, nil
|
||||
mu: &sync.RWMutex{},
|
||||
}
|
||||
|
||||
if EnableStats {
|
||||
driver.SCSIIOCount = map[int]int64{}
|
||||
driver.enableStats = true
|
||||
}
|
||||
return driver, nil
|
||||
}
|
||||
|
||||
func (s *ISCSITargetDriver) AllocTSIH() uint16 {
|
||||
@@ -167,19 +190,23 @@ func (s *ISCSITargetDriver) Run() error {
|
||||
s.l = l
|
||||
s.mu.Unlock()
|
||||
log.Infof("iSCSI service listening on: %v", s.l.Addr())
|
||||
|
||||
s.setState(STATE_RUNNING)
|
||||
for {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
if err, ok := err.(net.Error); ok {
|
||||
if !err.Temporary() {
|
||||
log.Info("Closing ...")
|
||||
log.Warning("Closing connection with initiator...")
|
||||
break
|
||||
}
|
||||
}
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Info(conn.LocalAddr().String())
|
||||
s.setClientStatus(true)
|
||||
|
||||
iscsiConn := &iscsiConnection{conn: conn,
|
||||
loginParam: &iscsiLoginParam{}}
|
||||
@@ -206,11 +233,28 @@ func (s *ISCSITargetDriver) Close() error {
|
||||
s.setClientStatus(false)
|
||||
s.mu.Unlock()
|
||||
if l != nil {
|
||||
return l.Close()
|
||||
s.setState(STATE_SHUTTING_DOWN)
|
||||
if err := l.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
s.setState(STATE_TERMINATE)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ISCSITargetDriver) setState(st uint8) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.state = st
|
||||
}
|
||||
|
||||
func (s *ISCSITargetDriver) Resize(size uint64) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.SCSI.Resize(size)
|
||||
}
|
||||
|
||||
func (s *ISCSITargetDriver) handler(events byte, conn *iscsiConnection) {
|
||||
|
||||
if events&DATAIN != 0 {
|
||||
@@ -481,6 +525,12 @@ func (s *ISCSITargetDriver) txHandler(conn *iscsiConnection) {
|
||||
resp.DataSN = 0
|
||||
maxCount := conn.maxSeqCount
|
||||
|
||||
if s.enableStats {
|
||||
if resp.OpCode == OpSCSIResp || resp.OpCode == OpSCSIIn {
|
||||
s.UpdateStats(conn)
|
||||
}
|
||||
}
|
||||
|
||||
/* send data splitted by segmentLen */
|
||||
SendRemainingData:
|
||||
if resp.OpCode == OpSCSIIn {
|
||||
@@ -581,6 +631,11 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
|
||||
switch req.OpCode {
|
||||
case OpSCSICmd:
|
||||
log.Debugf("SCSI Command processing...")
|
||||
if _, ok := s.SCSIIOCount[(int)(req.CDB[0])]; ok != false {
|
||||
s.SCSIIOCount[(int)(req.CDB[0])] += 1
|
||||
} else {
|
||||
s.SCSIIOCount[(int)(req.CDB[0])] = 1
|
||||
}
|
||||
scmd := &api.SCSICommand{
|
||||
ITNexusID: conn.session.ITNexus.ID,
|
||||
SCB: req.CDB,
|
||||
@@ -612,6 +667,7 @@ func (s *ISCSITargetDriver) scsiCommandHandler(conn *iscsiConnection) (err error
|
||||
}
|
||||
if req.Write {
|
||||
task.r2tCount = int(req.ExpectedDataLen) - req.DataLen
|
||||
task.expectedDataLength = int64(req.ExpectedDataLen)
|
||||
if !req.Final {
|
||||
task.unsolCount = 1
|
||||
}
|
||||
@@ -849,3 +905,23 @@ func (s *ISCSITargetDriver) iscsiExecTask(task *iscsiTask) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ISCSITargetDriver) Stats() scsi.Stats {
|
||||
return s.TargetStats
|
||||
}
|
||||
|
||||
func (s *ISCSITargetDriver) UpdateStats(conn *iscsiConnection) {
|
||||
s.TargetStats.IsClientConnected = s.isClientConnected
|
||||
switch api.SCSICommandType(conn.resp.SCSIOpCode) {
|
||||
case api.READ_6, api.READ_10, api.READ_12, api.READ_16:
|
||||
s.TargetStats.ReadIOPS += 1
|
||||
s.TargetStats.TotalReadTime += int64(time.Since(conn.resp.StartTime))
|
||||
s.TargetStats.TotalReadBlockCount += int64(conn.resp.ExpectedDataLen)
|
||||
break
|
||||
case api.WRITE_6, api.WRITE_10, api.WRITE_12, api.WRITE_16:
|
||||
s.TargetStats.WriteIOPS += 1
|
||||
s.TargetStats.TotalWriteTime += int64(time.Since(conn.resp.StartTime))
|
||||
s.TargetStats.TotalWriteBlockCount += int64(conn.resp.ExpectedDataLen)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,11 +188,9 @@ var sessionKeys map[string]*iscsiSessionKeys = map[string]*iscsiSessionKeys{
|
||||
// ISCSI_PARAM_HDRDGST_EN
|
||||
"HeaderDigest": {ISCSI_PARAM_HDRDGST_EN, false, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, digestKeyConv, digestKeyInConv},
|
||||
// ISCSI_PARAM_DATADGST_EN
|
||||
// TODO: Not sure why initialR2T was changed to true, need help in
|
||||
// understanding it's use?
|
||||
"DataDigest": {ISCSI_PARAM_DATADGST_EN, true, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, digestKeyConv, digestKeyInConv},
|
||||
"DataDigest": {ISCSI_PARAM_DATADGST_EN, false, DIGEST_NONE, DIGEST_NONE, DIGEST_ALL, digestKeyConv, digestKeyInConv},
|
||||
// ISCSI_PARAM_INITIAL_R2T_EN
|
||||
"InitialR2T": {ISCSI_PARAM_INITIAL_R2T_EN, false, 1, 0, 1, boolKeyConv, boolKeyInConv},
|
||||
"InitialR2T": {ISCSI_PARAM_INITIAL_R2T_EN, true, 1, 0, 1, boolKeyConv, boolKeyInConv},
|
||||
// ISCSI_PARAM_MAX_R2T
|
||||
"MaxOutstandingR2T": {ISCSI_PARAM_MAX_R2T, true, 1, 1, 65535, numberKeyConv, numberKeyInConv},
|
||||
// ISCSI_PARAM_IMM_DATA_EN
|
||||
|
||||
Reference in New Issue
Block a user