fix: prevent nil deref on session reinstatement during cleanup race

When a new login arrives while the previous connection's async cleanup
is still running, LookupISCSISession finds the stale session but
LookupConnection returns nil (old connection already closed). This
caused a nil pointer dereference when accessing existConn.session
during session reinstatement.

Fix by checking existConn != nil before reinstatement. If the old
connection is already gone, unbind the stale session and create
a fresh one instead.

Also add sync.Once to removeConnectionFromSession to prevent
concurrent goroutine and main-path cleanup from racing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lei Xue
2026-03-17 14:37:16 +08:00
parent b7e5c4a7d2
commit 8ffe5ec5ce
2 changed files with 24 additions and 14 deletions

View File

@@ -89,6 +89,7 @@ type iscsiConnection struct {
txTask *iscsiTask txTask *iscsiTask
readLock *sync.RWMutex readLock *sync.RWMutex
cleanupOnce sync.Once
} }
type taskState int type taskState int

View File

@@ -340,7 +340,9 @@ func (s *ISCSITargetDriver) UnBindISCSISession(sess *ISCSISession) {
// removeConnectionFromSession removes a connection from its session. // removeConnectionFromSession removes a connection from its session.
// If the session has no remaining connections, the session is unbound. // If the session has no remaining connections, the session is unbound.
// This is safe to call concurrently; cleanup runs at most once per connection.
func (s *ISCSITargetDriver) removeConnectionFromSession(conn *iscsiConnection) { func (s *ISCSITargetDriver) removeConnectionFromSession(conn *iscsiConnection) {
conn.cleanupOnce.Do(func() {
sess := conn.session sess := conn.session
if sess == nil { if sess == nil {
return return
@@ -355,6 +357,7 @@ func (s *ISCSITargetDriver) removeConnectionFromSession(conn *iscsiConnection) {
s.UnBindISCSISession(sess) s.UnBindISCSISession(sess)
} }
conn.session = nil conn.session = nil
})
} }
func (s *ISCSITargetDriver) BindISCSISession(conn *iscsiConnection) error { func (s *ISCSITargetDriver) BindISCSISession(conn *iscsiConnection) error {
@@ -433,7 +436,13 @@ func (s *ISCSITargetDriver) BindISCSISession(conn *iscsiConnection) error {
if conn.loginParam.tsih == ISCSI_UNSPEC_TSIH { if conn.loginParam.tsih == ISCSI_UNSPEC_TSIH {
log.Infof("Session Reinstatement initiator name:%v,target name:%v,ISID:0x%x", log.Infof("Session Reinstatement initiator name:%v,target name:%v,ISID:0x%x",
conn.loginParam.initiator, conn.loginParam.target, conn.loginParam.isid) conn.loginParam.initiator, conn.loginParam.target, conn.loginParam.isid)
if existConn != nil {
newSess, err = s.ReInstatement(existConn.session, conn) newSess, err = s.ReInstatement(existConn.session, conn)
} else {
// Old connection already closed; unbind the stale session and create new
s.UnBindISCSISession(existSess)
newSess, err = s.NewISCSISession(conn)
}
if err != nil { if err != nil {
return err return err
} }