• Joe Eykholt's avatar
    [SCSI] libfc: Fix remote port restart problem · 4b2164d4
    Joe Eykholt authored
    This patch somewhat combines two fixes to remote port handing in libfc.
    The first problem was that rport work could be queued on a deleted
    and freed rport.  This is handled by not resetting rdata->event
    ton NONE if the rdata is about to be deleted.
    However, that fix led to the second problem, described by
    Bhanu Gollapudi, as follows:
    > Here is the sequence of events. T1 is first LOGO receive thread, T2 is
    > fc_rport_work() scheduled by T1 and T3 is second LOGO receive thread and
    > T4 is fc_rport_work scheduled by T3.
    > 1. (T1)Received 1st LOGO in state Ready
    > 2. (T1)Delete port & enter to RESTART state.
    > 3. (T1)schdule event_work, since event is RPORT_EV_NONE.
    > 4. (T1)set event = RPORT_EV_LOGO
    > 5. (T1)Enter RESTART state as disc_id is set.
    > 6. (T2)remember to PLOGI, and set event = RPORT_EV_NONE
    > 6. (T3)Received 2nd LOGO
    > 7. (T3)Delete Port & enter to RESTART state.
    > 8. (T3)schedule event_work, since event is RPORT_EV_NONE.
    > 9. (T3)Enter RESTART state as disc_id is set.
    > 9. (T3)set event = RPORT_EV_LOGO
    > 10.(T2)work restart, enter PLOGI state and issues PLOGI
    > 11.(T4)Since state is not RESTART anymore, restart is not set, and the
    > event is not reset to RPORT_EV_NONE. (current event is RPORT_EV_LOGO).
    > 12. Now, PLOGI succeeds and fc_rport_enter_ready() will not schedule
    > event_work, and hence the rport will never be created, eventually losing
    > the target after dev_loss_tmo.
    So, the problem here is that we were tracking the desire for
    the rport be restarted by state RESTART, which was otherwise
    equivalent to DELETE.  A contributing factor is that we dropped
    the lock between steps 6 and 10 in thread T2, which allows the
    state to change, and we didn't completely re-evaluate then.
    This is hopefully corrected by the following minor redesign:
    Simplify the rport restart logic by making the decision to
    restart after deleting the transport rport.  That decision
    is based on a new STARTED flag that indicates fc_rport_login()
    has been called and fc_rport_logoff() has not been called
    since then.  This replaces the need for the RESTART state.
    Only restart if the rdata is still in DELETED state
    and only if it still has the STARTED flag set.
    Also now, since we clear the event code much later in the
    work thread, allow for the possibility that the rport may
    have become READY again via incoming PLOGI, and if so,
    queue another event to handle that.
    In the problem scenario, the second LOGO received will
    cause the LOGO event to occur again.
    Reported-by: default avatarBhanu Gollapudi <bprakash@broadcom.com>
    Signed-off-by: default avatarJoe Eykholt <jeykholt@cisco.com>
    Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
    Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
libfc.h 30.8 KB