From b93b18731ff4359854ff2d4e5fff3e50755dc053 Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Thu, 30 Jun 2022 20:17:06 +0300 Subject: [PATCH] scst_tg: Fix usage of the on_alua_state_change_*() callback functions The use of the on_alua_state_change_*() callback functions was changed in commit d333ce82 ("Restore the on_alua_state_change_*() callback functions") in a such way that they are now only invoked if the state of a local target port group is being modified. But when compared to the old implementation, which was removed in commit 29548a4a ("scst: Remove the on_alua_state_change_*() callback functions"), they won't be invoked for devices that do not have target devices, or have only those that aren't included in the target group. Hence additionally invoke these callbacks for such devices if the state of a local target port group is being modified. Fixes: https://github.com/SCST-project/scst/issues/55 --- scst/src/scst_tg.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/scst/src/scst_tg.c b/scst/src/scst_tg.c index d7f5d9b4c..72feb671d 100644 --- a/scst/src/scst_tg.c +++ b/scst/src/scst_tg.c @@ -991,6 +991,7 @@ static void __scst_tg_set_state(struct scst_target_group *tg, struct scst_tgt_dev *tgt_dev; struct scst_tgt *tgt; bool invoke_callbacks; + bool tg_is_remote; sBUG_ON(state >= ARRAY_SIZE(scst_alua_filter)); lockdep_assert_held(&scst_dg_mutex); @@ -998,9 +999,21 @@ static void __scst_tg_set_state(struct scst_target_group *tg, if (tg->state == state) return; + /* + * If the target group has a target with NULL target device, + * that means that this target is remote one, so we shouldn't + * call on_alua_state_change_*() callbacks then. + * + * See also 29548a4a ("scst: Remove the on_alua_state_change_*() + * callback functions") and d333ce82 ("Restore the + * on_alua_state_change_*() callback functions"). + */ + tg_is_remote = __scst_tg_have_tgt(tg, NULL); + list_for_each_entry(dg_dev, &tg->dg->dev_list, entry) { invoke_callbacks = true; dev = dg_dev->dev; + list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { tgt = tgt_dev->sess->tgt; @@ -1011,6 +1024,28 @@ static void __scst_tg_set_state(struct scst_target_group *tg, invoke_callbacks = false; } } + + /* + * There are several cases when `invoke_callbacks` can + * still be true here: + * - The SCST device still doesn't have any target + * devices, or have only those that aren't included + * in the given target group (e.g. the default copy + * manager for a blockio devices). + * - Target group has remote targets. + * + * We should call on_alua_state_chage_*() callbacks only + * in the first case. + * + * See also https://github.com/SCST-project/scst/issues/55. + */ + if (invoke_callbacks && !tg_is_remote) { + if (dev->handler->on_alua_state_change_start) + dev->handler->on_alua_state_change_start(dev, tg->state, state); + + if (dev->handler->on_alua_state_change_finish) + dev->handler->on_alua_state_change_finish(dev, tg->state, state); + } } tg->state = state;