diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index f4ff0c90d..dfb888fa7 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4267,29 +4267,26 @@ out_free: goto out; } -int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun, - bool gen_scst_report_luns_changed) +static struct scst_acg_dev *__scst_acg_del_lun(struct scst_acg *acg, + uint64_t lun, + struct list_head *tgt_dev_list) { - int res = 0; struct scst_acg_dev *acg_dev = NULL, *a; struct scst_tgt_dev *tgt_dev, *tt; struct scst_session *sess; - TRACE_ENTRY(); - lockdep_assert_held(&scst_mutex); + INIT_LIST_HEAD(tgt_dev_list); + list_for_each_entry(a, &acg->acg_dev_list, acg_dev_list_entry) { if (a->lun == lun) { acg_dev = a; break; } } - if (acg_dev == NULL) { - PRINT_ERROR("Device is not found in group %s", acg->acg_name); - res = -EINVAL; + if (acg_dev == NULL) goto out; - } list_for_each_entry_safe(tgt_dev, tt, &acg_dev->dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { @@ -4300,15 +4297,46 @@ int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun, scst_del_tgt_dev(tgt_dev); mutex_unlock(&sess->tgt_dev_list_mutex); - scst_free_tgt_dev(tgt_dev); + list_add_tail(&tgt_dev->extra_tgt_dev_list_entry, + tgt_dev_list); } } - scst_del_free_acg_dev(acg_dev, true); + scst_del_acg_dev(acg_dev, true, true); + +out: + return acg_dev; +} + +int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun, + bool gen_scst_report_luns_changed) +{ + int res = -EINVAL; + struct scst_acg_dev *acg_dev; + struct scst_tgt_dev *tgt_dev, *tt; + struct list_head tgt_dev_list; + + TRACE_ENTRY(); + + lockdep_assert_held(&scst_mutex); + + acg_dev = __scst_acg_del_lun(acg, lun, &tgt_dev_list); + if (acg_dev == NULL) { + PRINT_ERROR("Device is not found in group %s", acg->acg_name); + goto out; + } if (gen_scst_report_luns_changed) scst_report_luns_changed(acg); + list_for_each_entry_safe(tgt_dev, tt, &tgt_dev_list, + extra_tgt_dev_list_entry) { + scst_free_tgt_dev(tgt_dev); + } + scst_free_acg_dev(acg_dev); + + res = 0; + PRINT_INFO("Removed LUN %lld from group %s (target %s)", lun, acg->acg_name, acg->tgt ? acg->tgt->tgt_name : "?"); @@ -4317,6 +4345,49 @@ out: return res; } +int scst_acg_repl_lun(struct scst_acg *acg, struct kobject *parent, + struct scst_device *dev, uint64_t lun, + bool read_only) +{ + struct scst_acg_dev *acg_dev; + struct scst_tgt_dev *tgt_dev, *tt; + struct list_head tgt_dev_list; + int res = -EINVAL; + + TRACE_ENTRY(); + + lockdep_assert_held(&scst_mutex); + + acg_dev = __scst_acg_del_lun(acg, lun, &tgt_dev_list); + + res = scst_acg_add_lun(acg, parent, dev, lun, read_only, !acg_dev, + NULL); + if (res != 0) + goto out; + + if (acg_dev) { + list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, + dev_tgt_dev_list_entry) { + if (tgt_dev->acg_dev->acg == acg && + tgt_dev->lun == lun) { + TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED" + " on tgt_dev %p", tgt_dev); + scst_gen_aen_or_ua(tgt_dev, + SCST_LOAD_SENSE(scst_sense_inquiry_data_changed)); + } + } + } + list_for_each_entry_safe(tgt_dev, tt, &tgt_dev_list, + extra_tgt_dev_list_entry) { + scst_free_tgt_dev(tgt_dev); + } + scst_free_acg_dev(acg_dev); + +out: + TRACE_EXIT_RES(res); + return res; +} + /* The activity supposed to be suspended and scst_mutex held */ struct scst_acg *scst_alloc_add_acg(struct scst_tgt *tgt, const char *acg_name, bool tgt_acg) diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 3bbdd573b..ff14ba2d2 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -364,6 +364,8 @@ int scst_acg_add_lun(struct scst_acg *acg, struct kobject *parent, bool gen_scst_report_luns_changed, struct scst_acg_dev **out_acg_dev); int scst_acg_del_lun(struct scst_acg *acg, uint64_t lun, bool gen_scst_report_luns_changed); +int scst_acg_repl_lun(struct scst_acg *acg, struct kobject *parent, + struct scst_device *dev, uint64_t lun, bool read_only); int scst_acg_add_acn(struct scst_acg *acg, const char *name); #ifdef CONFIG_SCST_PROC diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 8d591b403..e47da42c4 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -1409,7 +1409,6 @@ static int __scst_process_luns_mgmt_store(char *buffer, &read_only); if (res != 0) goto out_unlock; - acg_dev = NULL; list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list, acg_dev_list_entry) { @@ -1418,7 +1417,6 @@ static int __scst_process_luns_mgmt_store(char *buffer, break; } } - if (acg_dev) { PRINT_ERROR("virt lun %ld already exists in " "group %s", virt_lun, acg->acg_name); @@ -1434,54 +1432,16 @@ static int __scst_process_luns_mgmt_store(char *buffer, break; case SCST_LUN_ACTION_REPLACE: - { - bool dev_replaced = false; - res = scst_parse_add_repl_param(acg, dev, pp, &virt_lun, &read_only); if (res != 0) goto out_unlock; - - acg_dev = NULL; - list_for_each_entry(acg_dev_tmp, &acg->acg_dev_list, - acg_dev_list_entry) { - if (acg_dev_tmp->lun == virt_lun) { - acg_dev = acg_dev_tmp; - break; - } - } - - if (acg_dev) { - res = scst_acg_del_lun(acg, acg_dev->lun, false); - if (res != 0) - goto out_unlock; - - dev_replaced = true; - } - - res = scst_acg_add_lun(acg, + res = scst_acg_repl_lun(acg, tgt_kobj ? tgt->tgt_luns_kobj : acg->luns_kobj, - dev, virt_lun, read_only, !dev_replaced, NULL); + dev, virt_lun, read_only); if (res != 0) goto out_unlock; - - if (dev_replaced) { - struct scst_tgt_dev *tgt_dev; - - list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, - dev_tgt_dev_list_entry) { - if ((tgt_dev->acg_dev->acg == acg) && - (tgt_dev->lun == virt_lun)) { - TRACE_MGMT_DBG("INQUIRY DATA HAS CHANGED" - " on tgt_dev %p", tgt_dev); - scst_gen_aen_or_ua(tgt_dev, - SCST_LOAD_SENSE(scst_sense_inquiry_data_changed)); - } - } - } - break; - } case SCST_LUN_ACTION_DEL: p = scst_get_next_lexem(&pp); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)