scsi: target: Perform ALUA group changes in one step
authorMike Christie <michael.christie@oracle.com>
Thu, 30 Sep 2021 02:04:22 +0000 (21:04 -0500)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 19 Oct 2021 02:38:36 +0000 (22:38 -0400)
When userspace changes the LUN's ALUA group, it will set the LUN's group to
NULL then to the new group. Before the new group is set,
target_alua_state_check() will return 0 and allow the I/O to execute. This
has us skip the NULL stage, and just swap in the new group.

Link: https://lore.kernel.org/r/20210930020422.92578-6-michael.christie@oracle.com
Signed-off-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/target/target_core_alua.c

index 74944b914b4ed52ce64bfbb8ae0dd8a7a6bb7e8b..b56ef8af66e7421e5508488a301e9401cfa9922d 100644 (file)
@@ -1835,8 +1835,6 @@ static void __target_detach_tg_pt_gp(struct se_lun *lun,
        list_del_init(&lun->lun_tg_pt_gp_link);
        tg_pt_gp->tg_pt_gp_members--;
        spin_unlock(&tg_pt_gp->tg_pt_gp_lock);
-
-       rcu_assign_pointer(lun->lun_tg_pt_gp, NULL);
 }
 
 void target_detach_tg_pt_gp(struct se_lun *lun)
@@ -1846,12 +1844,25 @@ void target_detach_tg_pt_gp(struct se_lun *lun)
        spin_lock(&lun->lun_tg_pt_gp_lock);
        tg_pt_gp = rcu_dereference_check(lun->lun_tg_pt_gp,
                                lockdep_is_held(&lun->lun_tg_pt_gp_lock));
-       if (tg_pt_gp)
+       if (tg_pt_gp) {
                __target_detach_tg_pt_gp(lun, tg_pt_gp);
+               rcu_assign_pointer(lun->lun_tg_pt_gp, NULL);
+       }
        spin_unlock(&lun->lun_tg_pt_gp_lock);
        synchronize_rcu();
 }
 
+static void target_swap_tg_pt_gp(struct se_lun *lun,
+                                struct t10_alua_tg_pt_gp *old_tg_pt_gp,
+                                struct t10_alua_tg_pt_gp *new_tg_pt_gp)
+{
+       assert_spin_locked(&lun->lun_tg_pt_gp_lock);
+
+       if (old_tg_pt_gp)
+               __target_detach_tg_pt_gp(lun, old_tg_pt_gp);
+       __target_attach_tg_pt_gp(lun, new_tg_pt_gp);
+}
+
 ssize_t core_alua_show_tg_pt_gp_info(struct se_lun *lun, char *page)
 {
        struct config_item *tg_pt_ci;
@@ -1941,18 +1952,16 @@ ssize_t core_alua_store_tg_pt_gp_info(
                                        &tg_pt_gp->tg_pt_gp_group.cg_item),
                                tg_pt_gp->tg_pt_gp_id);
 
-                       __target_detach_tg_pt_gp(lun, tg_pt_gp);
-                       __target_attach_tg_pt_gp(lun,
+                       target_swap_tg_pt_gp(lun, tg_pt_gp,
                                        dev->t10_alua.default_tg_pt_gp);
                        spin_unlock(&lun->lun_tg_pt_gp_lock);
 
                        goto sync_rcu;
                }
-               __target_detach_tg_pt_gp(lun, tg_pt_gp);
                move = 1;
        }
 
-       __target_attach_tg_pt_gp(lun, tg_pt_gp_new);
+       target_swap_tg_pt_gp(lun, tg_pt_gp, tg_pt_gp_new);
        spin_unlock(&lun->lun_tg_pt_gp_lock);
        pr_debug("Target_Core_ConfigFS: %s %s/tpgt_%hu/%s to ALUA"
                " Target Port Group: alua/%s, ID: %hu\n", (move) ?