Files
gotgt/pkg/scsi/scsi_pr.go
2016-11-24 23:16:53 +08:00

325 lines
7.9 KiB
Go

package scsi
import (
"github.com/gostor/gotgt/pkg/api"
"github.com/satori/go.uuid"
)
type SCSIReservationOperator interface {
GetCurrentReservation(tgtName string, devUUID uint64) *api.SCSIReservation
SetCurrentReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool
IsCurrentReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool
GetPRGeneration(tgtName string, devUUID uint64) (uint32, bool)
IncPRGeneration(tgtName string, devUUID uint64) bool
AddReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool
GetReservation(tgtName string, devUUID uint64, ITNexusID uuid.UUID) *api.SCSIReservation
GetReservationList(tgtName string, devUUID uint64) []*api.SCSIReservation
DeleteAndRemoveReservation(tgtName string, devUUID uint64, res *api.SCSIReservation)
RemoveReservation(tgtName string, devUUID uint64, res *api.SCSIReservation)
RemoveAllReservation(tgtName string, devUUID uint64)
IsKeyExists(tgtName string, devUUID uint64, key uint64) bool
Save(tgtName string, devUUID uint64) bool
}
var onePROperator SCSIReservationOperator
func GetSCSIReservationOperator() SCSIReservationOperator {
if onePROperator == nil {
onePROperator = &SCSISimpleReservationOperator{
targetReservations: make(map[string]SCSILUReservationMap),
}
}
return onePROperator
}
type SCSILUReservation struct {
TargetName string
DeviceUUID uint64
PRGeneration uint32
Reservations []*api.SCSIReservation
CurrentReservation *api.SCSIReservation
}
type SCSILUReservationMap map[uint64]*SCSILUReservation /* device uuid as the key */
type SCSISimpleReservationOperator struct {
SCSIReservationOperator
targetReservations map[string]SCSILUReservationMap /* target name as the key*/
}
func (op *SCSISimpleReservationOperator) InitLUReservation(tgtName string, devUUID uint64) {
var (
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
op.targetReservations[tgtName] = make(SCSILUReservationMap)
targetRes = op.targetReservations[tgtName]
}
if _, ok = targetRes[devUUID]; !ok {
targetRes[devUUID] = &SCSILUReservation{TargetName: tgtName,
DeviceUUID: devUUID,
PRGeneration: 0,
Reservations: []*api.SCSIReservation{},
CurrentReservation: nil,
}
}
}
func (op *SCSISimpleReservationOperator) GetReservation(tgtName string, devUUID uint64, ITNexusID uuid.UUID) *api.SCSIReservation {
var (
LURes *SCSILUReservation
SCSIRes *api.SCSIReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return nil
}
if LURes, ok = targetRes[devUUID]; !ok {
return nil
}
for _, SCSIRes = range LURes.Reservations {
if uuid.Equal(SCSIRes.ITNexusID, ITNexusID) {
return SCSIRes
}
}
return nil
}
func (op *SCSISimpleReservationOperator) GetPRGeneration(tgtName string, devUUID uint64) (uint32, bool) {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return 0, false
}
if LURes, ok = targetRes[devUUID]; !ok {
return 0, false
}
return LURes.PRGeneration, true
}
func (op *SCSISimpleReservationOperator) IncPRGeneration(tgtName string, devUUID uint64) bool {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return false
}
if LURes, ok = targetRes[devUUID]; !ok {
return false
}
LURes.PRGeneration++
return true
}
func (op *SCSISimpleReservationOperator) GetCurrentReservation(tgtName string, devUUID uint64) *api.SCSIReservation {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return nil
}
if LURes, ok = targetRes[devUUID]; !ok {
return nil
}
return LURes.CurrentReservation
}
func (op *SCSISimpleReservationOperator) SetCurrentReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return false
}
if LURes, ok = targetRes[devUUID]; !ok {
return false
}
LURes.CurrentReservation = res
return true
}
func (op *SCSISimpleReservationOperator) GetReservationList(tgtName string, devUUID uint64) []*api.SCSIReservation {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return nil
}
if LURes, ok = targetRes[devUUID]; !ok {
return nil
}
return LURes.Reservations
}
func (op *SCSISimpleReservationOperator) DeleteAndRemoveReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) {
var (
i int = -1
ok bool
tmpRes *api.SCSIReservation
LURes *SCSILUReservation
targetRes SCSILUReservationMap
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return
}
if LURes, ok = targetRes[devUUID]; !ok {
return
}
resArray := LURes.Reservations
curRes := LURes.CurrentReservation
for i, tmpRes = range resArray {
if tmpRes == res {
break
}
}
if i >= 0 {
resArray[i] = resArray[len(resArray)-1]
resArray[len(resArray)-1] = nil
resArray = resArray[:len(resArray)-1]
}
if curRes == nil {
return
}
if !op.IsCurrentReservation(tgtName, devUUID, res) {
return
}
if (curRes.Type != PR_TYPE_WRITE_EXCLUSIVE_ALLREG &&
curRes.Type != PR_TYPE_EXCLUSIVE_ACCESS_ALLREG) ||
len(resArray) == 0 {
curRes.Scope = 0
curRes.Type = 0
LURes.CurrentReservation = nil
for i, tmpRes = range resArray {
if tmpRes == res {
continue
}
//TODO send sense code
}
LURes.PRGeneration++
} else {
for i, tmpRes = range resArray {
if tmpRes != res {
//kep scope and type
LURes.CurrentReservation = tmpRes
tmpRes.Scope = curRes.Scope
tmpRes.Type = curRes.Type
break
}
}
LURes.PRGeneration++
}
}
func (op *SCSISimpleReservationOperator) RemoveReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) {
var (
i int = -1
tmpRes *api.SCSIReservation
)
resArray := op.GetReservationList(tgtName, devUUID)
for i, tmpRes = range resArray {
if tmpRes == res {
break
}
}
if i >= 0 {
resArray[i] = resArray[len(resArray)-1]
resArray[len(resArray)-1] = nil
resArray = resArray[:len(resArray)-1]
}
}
func (op *SCSISimpleReservationOperator) AddReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return false
}
if LURes, ok = targetRes[devUUID]; !ok {
return false
}
LURes.Reservations = append(LURes.Reservations, res)
return true
}
func (op *SCSISimpleReservationOperator) IsKeyExists(tgtName string, devUUID uint64, key uint64) bool {
resList := op.GetReservationList(tgtName, devUUID)
for _, tmpRes := range resList {
if tmpRes.Key == key {
return true
}
}
return false
}
func (op *SCSISimpleReservationOperator) IsCurrentReservation(tgtName string, devUUID uint64, res *api.SCSIReservation) bool {
curRes := op.GetCurrentReservation(tgtName, devUUID)
if curRes == nil {
return false
}
if curRes.Type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
curRes.Type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG {
return true
}
if curRes == res {
return true
}
return false
}
func (op *SCSISimpleReservationOperator) RemoveAllReservation(tgtName string, devUUID uint64) {
var (
LURes *SCSILUReservation
targetRes SCSILUReservationMap
ok bool
)
if targetRes, ok = op.targetReservations[tgtName]; !ok {
return
}
if LURes, ok = targetRes[devUUID]; !ok {
return
}
LURes.Reservations = []*api.SCSIReservation{}
}
func (op *SCSISimpleReservationOperator) Save(tgtName string, devUUID uint64) bool {
return true
}