From a65caa9b9b6af3a7a80877e6e68e84330c909810 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Thu, 6 Aug 2009 11:47:18 +0000 Subject: [PATCH] Automatic sessions reassignment implemented git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1017 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- scst/README | 39 ++++--- scst/README_in-tree | 39 ++++--- scst/src/scst_lib.c | 270 +++++++++++++++++++++++++++++++++---------- scst/src/scst_main.c | 2 +- scst/src/scst_priv.h | 6 + scst/src/scst_proc.c | 139 ++++++++++++++++++---- scst/src/scst_targ.c | 36 +++--- 7 files changed, 399 insertions(+), 132 deletions(-) diff --git a/scst/README b/scst/README index 71fc8b876..022b537b9 100644 --- a/scst/README +++ b/scst/README @@ -448,40 +448,43 @@ names of initiators, which allowed to access devices in this group. To configure access and devices visibility management SCST provides the following files and directories under /proc/scsi_tgt: - - "add_group GROUP" to /proc/scsi_tgt/scsi_tgt adds group "GROUP" + - "add_group GROUP_NAME" to /proc/scsi_tgt/scsi_tgt adds group "GROUP_NAME" - - "del_group GROUP" to /proc/scsi_tgt/scsi_tgt deletes group "GROUP" + - "del_group GROUP_NAME" to /proc/scsi_tgt/scsi_tgt deletes group "GROUP_NAME" - - "add H:C:I:L lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds - device with host:channel:id:lun with LUN "lun" in group "GROUP". Optionally, + - "rename_group OLD_NAME NEW_NAME" to /proc/scsi_tgt/scsi_tgt renames + group "OLD_NAME" to "NEW_NAME". + + - "add H:C:I:L lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP_NAME/devices adds + device with host:channel:id:lun with LUN "lun" in group "GROUP_NAME". Optionally, the device could be marked as read only. The recommended way to find out H:C:I:L numbers is use of lsscsi utility. - - "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP/devices deletes device with - host:channel:id:lun from group "GROUP". The recommended way to find out + - "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP_NAME/devices deletes device with + host:channel:id:lun from group "GROUP_NAME". The recommended way to find out H:C:I:L numbers is use of lsscsi utility. - - "add V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds - device with virtual name "V_NAME" with LUN "lun" in group "GROUP". + - "add V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP_NAME/devices adds + device with virtual name "V_NAME" with LUN "lun" in group "GROUP_NAME". Optionally, the device could be marked as read only. - - "del V_NAME" to /proc/scsi_tgt/groups/GROUP/devices deletes device with - virtual name "V_NAME" from group "GROUP" + - "del V_NAME" to /proc/scsi_tgt/groups/GROUP_NAME/devices deletes device with + virtual name "V_NAME" from group "GROUP_NAME" - - "clear" to /proc/scsi_tgt/groups/GROUP/devices clears the list of devices - for group "GROUP" + - "clear" to /proc/scsi_tgt/groups/GROUP_NAME/devices clears the list of devices + for group "GROUP_NAME" - - "add NAME" to /proc/scsi_tgt/groups/GROUP/names adds name "NAME" to group - "GROUP". For NAME you can use simple DOS-type patterns, containing + - "add NAME" to /proc/scsi_tgt/groups/GROUP_NAME/names adds name "NAME" to group + "GROUP_NAME". For NAME you can use simple DOS-type patterns, containing '*' and '?' symbols. '*' means match all any symbols, '?' means match only any single symbol. For instance, "blah.xxx" will match "bl?h.*". - - "del NAME" to /proc/scsi_tgt/groups/GROUP/names deletes name "NAME" from group - "GROUP" + - "del NAME" to /proc/scsi_tgt/groups/GROUP_NAME/names deletes name "NAME" from group + "GROUP_NAME" - - "clear" to /proc/scsi_tgt/groups/GROUP/names clears the list of names - for group "GROUP" + - "clear" to /proc/scsi_tgt/groups/GROUP_NAME/names clears the list of names + for group "GROUP_NAME" Examples: diff --git a/scst/README_in-tree b/scst/README_in-tree index 3c491a9c0..388c59617 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -366,40 +366,43 @@ names of initiators, which allowed to access devices in this group. To configure access and devices visibility management SCST provides the following files and directories under /proc/scsi_tgt: - - "add_group GROUP" to /proc/scsi_tgt/scsi_tgt adds group "GROUP" + - "add_group GROUP_NAME" to /proc/scsi_tgt/scsi_tgt adds group "GROUP_NAME" - - "del_group GROUP" to /proc/scsi_tgt/scsi_tgt deletes group "GROUP" + - "del_group GROUP_NAME" to /proc/scsi_tgt/scsi_tgt deletes group "GROUP_NAME" - - "add H:C:I:L lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds - device with host:channel:id:lun with LUN "lun" in group "GROUP". Optionally, + - "rename_group OLD_NAME NEW_NAME" to /proc/scsi_tgt/scsi_tgt renames + group "OLD_NAME" to "NEW_NAME". + + - "add H:C:I:L lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP_NAME/devices adds + device with host:channel:id:lun with LUN "lun" in group "GROUP_NAME". Optionally, the device could be marked as read only. The recommended way to find out H:C:I:L numbers is use of lsscsi utility. - - "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP/devices deletes device with - host:channel:id:lun from group "GROUP". The recommended way to find out + - "del H:C:I:L" to /proc/scsi_tgt/groups/GROUP_NAME/devices deletes device with + host:channel:id:lun from group "GROUP_NAME". The recommended way to find out H:C:I:L numbers is use of lsscsi utility. - - "add V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP/devices adds - device with virtual name "V_NAME" with LUN "lun" in group "GROUP". + - "add V_NAME lun [READ_ONLY]" to /proc/scsi_tgt/groups/GROUP_NAME/devices adds + device with virtual name "V_NAME" with LUN "lun" in group "GROUP_NAME". Optionally, the device could be marked as read only. - - "del V_NAME" to /proc/scsi_tgt/groups/GROUP/devices deletes device with - virtual name "V_NAME" from group "GROUP" + - "del V_NAME" to /proc/scsi_tgt/groups/GROUP_NAME/devices deletes device with + virtual name "V_NAME" from group "GROUP_NAME" - - "clear" to /proc/scsi_tgt/groups/GROUP/devices clears the list of devices - for group "GROUP" + - "clear" to /proc/scsi_tgt/groups/GROUP_NAME/devices clears the list of devices + for group "GROUP_NAME" - - "add NAME" to /proc/scsi_tgt/groups/GROUP/names adds name "NAME" to group - "GROUP". For NAME you can use simple DOS-type patterns, containing + - "add NAME" to /proc/scsi_tgt/groups/GROUP_NAME/names adds name "NAME" to group + "GROUP_NAME". For NAME you can use simple DOS-type patterns, containing '*' and '?' symbols. '*' means match all any symbols, '?' means match only any single symbol. For instance, "blah.xxx" will match "bl?h.*". - - "del NAME" to /proc/scsi_tgt/groups/GROUP/names deletes name "NAME" from group - "GROUP" + - "del NAME" to /proc/scsi_tgt/groups/GROUP_NAME/names deletes name "NAME" from group + "GROUP_NAME" - - "clear" to /proc/scsi_tgt/groups/GROUP/names clears the list of names - for group "GROUP" + - "clear" to /proc/scsi_tgt/groups/GROUP_NAME/names clears the list of names + for group "GROUP_NAME" Examples: diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index 91c9e42cb..09da5ce75 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -48,6 +48,9 @@ static void scst_free_all_UA(struct scst_tgt_dev *tgt_dev); static void scst_release_space(struct scst_cmd *cmd); static void scst_sess_free_tgt_devs(struct scst_session *sess); static void scst_unblock_cmds(struct scst_device *dev); +static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev); +static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess, + struct scst_acg_dev *acg_dev); #ifdef CONFIG_SCST_DEBUG_TM static void tm_dbg_init_tgt_dev(struct scst_tgt_dev *tgt_dev, @@ -562,6 +565,66 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess, return; } +/* The activity supposed to be suspended and scst_mutex held */ +static void scst_report_luns_changed_sess(struct scst_session *sess) +{ + int i; + struct list_head *shead; + struct scst_tgt_dev *tgt_dev; + struct scst_tgt_template *tgtt = sess->tgt->tgtt; + + TRACE_ENTRY(); + + TRACE_DBG("REPORTED LUNS DATA CHANGED (sess %p)", sess); + + for (i = 0; i < TGT_DEV_HASH_SIZE; i++) { + shead = &sess->sess_tgt_dev_list_hash[i]; + + list_for_each_entry(tgt_dev, shead, + sess_tgt_dev_list_entry) { + if (scst_is_report_luns_changed_type( + tgt_dev->dev->type)) + goto found; + } + } + TRACE_MGMT_DBG("Not found a device capable REPORTED " + "LUNS DATA CHANGED UA (sess %p)", sess); + goto out; + +found: + if (tgtt->report_aen != NULL) { + struct scst_aen *aen; + int rc; + + aen = scst_alloc_aen(tgt_dev); + if (aen == NULL) + goto queue_ua; + + aen->event_fn = SCST_AEN_SCSI; + aen->aen_sense_len = SCST_STANDARD_SENSE_LEN; + scst_set_sense(aen->aen_sense, aen->aen_sense_len, + tgt_dev->dev->d_sense, + SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed)); + + TRACE_DBG("Calling target's %s report_aen(%p)", + tgtt->name, aen); + rc = tgtt->report_aen(aen); + TRACE_DBG("Target's %s report_aen(%p) returned %d", + tgtt->name, aen, rc); + if (rc == SCST_AEN_RES_SUCCESS) + goto out; + + scst_free_aen(aen); + } + +queue_ua: + scst_queue_report_luns_changed_UA(sess, 0); + +out: + TRACE_EXIT(); + return; +} + /* The activity supposed to be suspended and scst_mutex held */ void scst_report_luns_changed(struct scst_acg *acg) { @@ -572,52 +635,7 @@ void scst_report_luns_changed(struct scst_acg *acg) TRACE_MGMT_DBG("REPORTED LUNS DATA CHANGED (acg %s)", acg->acg_name); list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) { - int i; - struct list_head *shead; - struct scst_tgt_dev *tgt_dev; - struct scst_tgt_template *tgtt = sess->tgt->tgtt; - - for (i = 0; i < TGT_DEV_HASH_SIZE; i++) { - shead = &sess->sess_tgt_dev_list_hash[i]; - - list_for_each_entry(tgt_dev, shead, - sess_tgt_dev_list_entry) { - if (scst_is_report_luns_changed_type( - tgt_dev->dev->type)) - goto found; - } - } - TRACE_MGMT_DBG("Not found a device capable REPORTED " - "LUNS DATA CHANGED UA (sess %p)", sess); - continue; -found: - if (tgtt->report_aen != NULL) { - struct scst_aen *aen; - int rc; - - aen = scst_alloc_aen(tgt_dev); - if (aen == NULL) - goto queue_ua; - - aen->event_fn = SCST_AEN_SCSI; - aen->aen_sense_len = SCST_STANDARD_SENSE_LEN; - scst_set_sense(aen->aen_sense, aen->aen_sense_len, - tgt_dev->dev->d_sense, - SCST_LOAD_SENSE(scst_sense_reported_luns_data_changed)); - - TRACE_DBG("Calling target's %s report_aen(%p)", - tgtt->name, aen); - rc = tgtt->report_aen(aen); - TRACE_DBG("Target's %s report_aen(%p) returned %d", - tgtt->name, aen, rc); - if (rc == SCST_AEN_RES_SUCCESS) - continue; - - scst_free_aen(aen); - } - -queue_ua: - scst_queue_report_luns_changed_UA(sess, 0); + scst_report_luns_changed_sess(sess); } TRACE_EXIT(); @@ -684,6 +702,129 @@ out_free: } EXPORT_SYMBOL(scst_aen_done); +/* The activity supposed to be suspended and scst_mutex held */ +static void scst_check_reassign_sess(struct scst_session *sess) +{ + struct scst_acg *acg, *old_acg; + struct scst_acg_dev *acg_dev; + int i; + struct list_head *shead; + struct scst_tgt_dev *tgt_dev; + bool luns_changed = false; + bool add_failed, something_freed; + + TRACE_ENTRY(); + + TRACE_MGMT_DBG("Checking reassignment for sess %p (initiator %s)", + sess, sess->initiator_name); + + acg = scst_find_acg(sess); + if (acg == sess->acg) { + TRACE_MGMT_DBG("No reassignment for sess %p", sess); + goto out; + } + + TRACE_MGMT_DBG("sess %p will be reassigned from acg %s to acg %s", + sess, sess->acg->acg_name, acg->acg_name); + + old_acg = sess->acg; + sess->acg = NULL; /* to catch implicit dependencies earlier */ + +retry_add: + add_failed = false; + list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) { + for (i = 0; i < TGT_DEV_HASH_SIZE; i++) { + shead = &sess->sess_tgt_dev_list_hash[i]; + + list_for_each_entry(tgt_dev, shead, + sess_tgt_dev_list_entry) { + if ((tgt_dev->dev == acg_dev->dev) && + (tgt_dev->lun == acg_dev->lun) && + (tgt_dev->acg_dev->rd_only == acg_dev->rd_only)) { + TRACE_MGMT_DBG("sess %p: tgt_dev %p for " + "LUN %lld stays the same", + sess, tgt_dev, + (unsigned long long)tgt_dev->lun); + tgt_dev->acg_dev = acg_dev; + goto next; + } + } + } + + luns_changed = true; + + TRACE_MGMT_DBG("sess %p: Allocing new tgt_dev for LUN %lld", + sess, (unsigned long long)acg_dev->lun); + + tgt_dev = scst_alloc_add_tgt_dev(sess, acg_dev); + if (tgt_dev == NULL) { + add_failed = true; + break; + } +next: + continue; + } + + something_freed = false; + for (i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct scst_tgt_dev *t; + shead = &sess->sess_tgt_dev_list_hash[i]; + + list_for_each_entry_safe(tgt_dev, t, shead, + sess_tgt_dev_list_entry) { + if (tgt_dev->acg_dev->acg != acg) { + TRACE_MGMT_DBG("sess %p: Deleting not used " + "tgt_dev %p for LUN %lld", + sess, tgt_dev, + (unsigned long long)tgt_dev->lun); + luns_changed = true; + something_freed = true; + scst_free_tgt_dev(tgt_dev); + } + } + } + + if (add_failed && something_freed) { + TRACE_MGMT_DBG("sess %p: Retrying adding new tgt_devs", sess); + goto retry_add; + } + + sess->acg = acg; + + TRACE_DBG("Moving sess %p from acg %s to acg %s", sess, + old_acg->acg_name, acg->acg_name); + list_move_tail(&sess->acg_sess_list_entry, &acg->acg_sess_list); + + if (luns_changed) + scst_report_luns_changed_sess(sess); + +out: + TRACE_EXIT(); + return; +} + +/* The activity supposed to be suspended and scst_mutex held */ +void scst_check_reassign_sessions(void) +{ + struct scst_tgt_template *tgtt; + + TRACE_ENTRY(); + + list_for_each_entry(tgtt, &scst_template_list, scst_template_list_entry) { + struct scst_tgt *tgt; + list_for_each_entry(tgt, &tgtt->tgt_list, tgt_list_entry) { + struct scst_session *sess; + list_for_each_entry(sess, &tgt->sess_list, + sess_list_entry) { + scst_check_reassign_sess(sess); + } + } + } + + TRACE_EXIT(); + return; +} + int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd) { int res; @@ -1125,6 +1266,8 @@ struct scst_acg *scst_alloc_add_acg(const char *acg_name) TRACE_DBG("Adding acg %s to scst_acg_list", acg_name); list_add_tail(&acg->scst_acg_list_entry, &scst_acg_list); + scst_check_reassign_sessions(); + out: TRACE_EXIT_HRES(acg); return acg; @@ -1380,8 +1523,6 @@ out_free: goto out; } -static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev); - /* No locks supposed to be held, scst_mutex - held */ void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA) { @@ -1628,7 +1769,7 @@ out: return res; } -/* scst_mutex supposed to be held */ +/* The activity supposed to be suspended and scst_mutex held */ int scst_acg_add_name(struct scst_acg *acg, const char *name) { int res = 0; @@ -1638,8 +1779,7 @@ int scst_acg_add_name(struct scst_acg *acg, const char *name) TRACE_ENTRY(); - list_for_each_entry(n, &acg->acn_list, acn_list_entry) - { + list_for_each_entry(n, &acg->acn_list, acn_list_entry) { if (strcmp(n->name, name) == 0) { PRINT_ERROR("Name %s already exists in group %s", name, acg->acg_name); @@ -1669,8 +1809,10 @@ int scst_acg_add_name(struct scst_acg *acg, const char *name) list_add_tail(&n->acn_list_entry, &acg->acn_list); out: - if (res == 0) + if (res == 0) { PRINT_INFO("Added name %s to group %s", name, acg->acg_name); + scst_check_reassign_sessions(); + } TRACE_EXIT_RES(res); return res; @@ -1681,6 +1823,19 @@ out_free: } /* scst_mutex supposed to be held */ +void __scst_acg_remove_acn(struct scst_acn *n) +{ + TRACE_ENTRY(); + + list_del(&n->acn_list_entry); + kfree(n->name); + kfree(n); + + TRACE_EXIT(); + return; +} + +/* The activity supposed to be suspended and scst_mutex held */ int scst_acg_remove_name(struct scst_acg *acg, const char *name) { int res = -EINVAL; @@ -1688,12 +1843,9 @@ int scst_acg_remove_name(struct scst_acg *acg, const char *name) TRACE_ENTRY(); - list_for_each_entry(n, &acg->acn_list, acn_list_entry) - { + list_for_each_entry(n, &acg->acn_list, acn_list_entry) { if (strcmp(n->name, name) == 0) { - list_del(&n->acn_list_entry); - kfree(n->name); - kfree(n); + __scst_acg_remove_acn(n); res = 0; break; } @@ -1702,10 +1854,10 @@ int scst_acg_remove_name(struct scst_acg *acg, const char *name) if (res == 0) { PRINT_INFO("Removed name %s from group %s", name, acg->acg_name); - } else { + scst_check_reassign_sessions(); + } else PRINT_ERROR("Unable to find name %s in group %s", name, acg->acg_name); - } TRACE_EXIT_RES(res); return res; diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 33fdc1d30..c47d59cd0 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -77,7 +77,7 @@ struct mutex scst_mutex; /* All 3 protected by scst_mutex */ -static struct list_head scst_template_list; +struct list_head scst_template_list; struct list_head scst_dev_list; struct list_head scst_dev_type_list; diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 150877951..080a76071 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -140,6 +140,7 @@ extern struct scst_sgv_pools scst_sgv; extern unsigned long scst_flags; extern struct mutex scst_mutex; extern atomic_t scst_cmd_count; +extern struct list_head scst_template_list; extern struct list_head scst_dev_list; extern struct list_head scst_dev_type_list; extern wait_queue_head_t scst_dev_cmd_waitQ; @@ -292,6 +293,10 @@ void scst_free_device(struct scst_device *dev); struct scst_acg *scst_alloc_add_acg(const char *acg_name); int scst_destroy_acg(struct scst_acg *acg); +struct scst_acg *scst_find_acg(const struct scst_session *sess); + +void scst_check_reassign_sessions(void); + int scst_sess_alloc_tgt_devs(struct scst_session *sess); void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA); @@ -301,6 +306,7 @@ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev); int scst_acg_add_name(struct scst_acg *acg, const char *name); int scst_acg_remove_name(struct scst_acg *acg, const char *name); +void __scst_acg_remove_acn(struct scst_acn *n); int scst_prepare_request_sense(struct scst_cmd *orig_cmd); int scst_finish_internal_cmd(struct scst_cmd *cmd); diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c index d825e1e7c..90aceb942 100644 --- a/scst/src/scst_proc.c +++ b/scst/src/scst_proc.c @@ -83,6 +83,7 @@ static struct scst_proc_data scst_dev_handler_proc_data; #define SCST_PROC_ACTION_ASSIGN 9 #define SCST_PROC_ACTION_ADD_GROUP 10 #define SCST_PROC_ACTION_DEL_GROUP 11 +#define SCST_PROC_ACTION_RENAME_GROUP 12 static struct proc_dir_entry *scst_proc_scsi_tgt; static struct proc_dir_entry *scst_proc_groups_root; @@ -125,17 +126,18 @@ static struct scst_proc_log scst_proc_local_trace_tbl[] = static char *scst_proc_help_string = " echo \"assign H:C:I:L HANDLER_NAME\" >/proc/scsi_tgt/scsi_tgt\n" "\n" -" echo \"add_group GROUP\" >/proc/scsi_tgt/scsi_tgt\n" -" echo \"del_group GROUP\" >/proc/scsi_tgt/scsi_tgt\n" +" echo \"add_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n" +" echo \"del_group GROUP_NAME\" >/proc/scsi_tgt/scsi_tgt\n" +" echo \"rename_group OLD_NAME NEW_NAME\" >/proc/scsi_tgt/scsi_tgt\n" "\n" " echo \"add|del H:C:I:L lun [READ_ONLY]\"" -" >/proc/scsi_tgt/groups/GROUP/devices\n" +" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n" " echo \"add|del V_NAME lun [READ_ONLY]\"" -" >/proc/scsi_tgt/groups/GROUP/devices\n" -" echo \"clear\" >/proc/scsi_tgt/groups/GROUP/devices\n" +" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n" +" echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/devices\n" "\n" -" echo \"add|del NAME\" >/proc/scsi_tgt/groups/GROUP/names\n" -" echo \"clear\" >/proc/scsi_tgt/groups/GROUP/names\n" +" echo \"add|del NAME\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n" +" echo \"clear\" >/proc/scsi_tgt/groups/GROUP_NAME/names\n" "\n" " echo \"DEC|0xHEX|0OCT\" >/proc/scsi_tgt/threads\n" #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) @@ -707,6 +709,45 @@ static int scst_proc_del_free_acg(struct scst_acg *acg, int remove_proc) return res; } +/* The activity supposed to be suspended and scst_mutex held */ +static int scst_proc_rename_acg(struct scst_acg *acg, const char *new_name) +{ + int res = 0, len = strlen(new_name) + 1; + char *name; + struct proc_dir_entry *old_acg_proc_root = acg->acg_proc_root; + + TRACE_ENTRY(); + + name = kmalloc(len, GFP_KERNEL); + if (name == NULL) { + TRACE(TRACE_OUT_OF_MEM, "%s", "Allocation of new name failed"); + goto out_nomem; + } + strncpy(name, new_name, len); + + res = scst_proc_group_add_tree(acg, new_name); + if (res != 0) + goto out_free; + + scst_proc_del_acg_tree(old_acg_proc_root, acg->acg_name); + + kfree(acg->acg_name); + acg->acg_name = name; + + scst_check_reassign_sessions(); + +out: + TRACE_EXIT_RES(res); + return res; + +out_free: + kfree(name); + +out_nomem: + res = -ENOMEM; + goto out; +} + static int __init scst_proc_init_groups(void) { int res = 0; @@ -1262,7 +1303,7 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, size_t length, loff_t *off) { int res, rc = 0, action; - char *buffer, *p; + char *buffer, *p, *pp; struct scst_acg *a, *acg = NULL; TRACE_ENTRY(); @@ -1292,8 +1333,9 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, } /* - * Usage: echo "add_group GROUP" >/proc/scsi_tgt/scsi_tgt - * or echo "del_group GROUP" >/proc/scsi_tgt/scsi_tgt + * Usage: echo "add_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt + * or echo "del_group GROUP_NAME" >/proc/scsi_tgt/scsi_tgt + * or echo "rename_group OLD_NAME NEW_NAME" >/proc/scsi_tgt/scsi_tgt" * or echo "assign H:C:I:L HANDLER_NAME" >/proc/scsi_tgt/scsi_tgt */ p = buffer; @@ -1308,6 +1350,9 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, } else if (!strncasecmp("del_group ", p, 10)) { p += 10; action = SCST_PROC_ACTION_DEL_GROUP; + } else if (!strncasecmp("rename_group ", p, 13)) { + p += 13; + action = SCST_PROC_ACTION_RENAME_GROUP; } else { PRINT_ERROR("Unknown action \"%s\"", p); res = -EINVAL; @@ -1328,12 +1373,33 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, switch (action) { case SCST_PROC_ACTION_ADD_GROUP: case SCST_PROC_ACTION_DEL_GROUP: + case SCST_PROC_ACTION_RENAME_GROUP: if (strcmp(p, SCST_DEFAULT_ACG_NAME) == 0) { - PRINT_ERROR("Attempt to add/delete predefined " + PRINT_ERROR("Attempt to add/delete/rename predefined " "group \"%s\"", p); res = -EINVAL; goto out_up_free; } + + pp = p; + while (!isspace(*pp) && *pp != '\0') + pp++; + if (*pp != '\0') { + switch (action) { + case SCST_PROC_ACTION_ADD_GROUP: + case SCST_PROC_ACTION_DEL_GROUP: + PRINT_ERROR("Wrong acg name %s", p); + res = -EINVAL; + goto out_up_free; + default: + *pp = '\0'; + pp++; + while (isspace(*pp) && *pp != '\0') + pp++; + break; + } + } + list_for_each_entry(a, &scst_acg_list, scst_acg_list_entry) { if (strcmp(a->acg_name, p) == 0) { TRACE_DBG("group (acg) %p %s found", @@ -1342,6 +1408,7 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, break; } } + switch (action) { case SCST_PROC_ACTION_ADD_GROUP: if (acg) { @@ -1359,6 +1426,22 @@ static ssize_t scst_proc_scsi_tgt_gen_write(struct file *file, } rc = scst_proc_del_free_acg(acg, 1); break; + case SCST_PROC_ACTION_RENAME_GROUP: + if (acg == NULL) { + PRINT_ERROR("acg name %s not found", p); + res = -EINVAL; + goto out_up_free; + } + p = pp; + while (!isspace(*pp) && *pp != '\0') + pp++; + if (*pp != '\0') { + PRINT_ERROR("Wrong acg name %s", p); + res = -EINVAL; + goto out_up_free; + } + rc = scst_proc_rename_acg(acg, p); + break; } break; case SCST_PROC_ACTION_ASSIGN: @@ -1519,10 +1602,10 @@ static ssize_t scst_proc_groups_devices_write(struct file *file, /* * Usage: echo "add|del H:C:I:L lun [READ_ONLY]" \ - * >/proc/scsi_tgt/groups/GROUP/devices + * >/proc/scsi_tgt/groups/GROUP_NAME/devices * or echo "add|del V_NAME lun [READ_ONLY]" \ - * >/proc/scsi_tgt/groups/GROUP/devices - * or echo "clear" >/proc/scsi_tgt/groups/GROUP/devices + * >/proc/scsi_tgt/groups/GROUP_NAME/devices + * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/devices */ p = buffer; if (p[strlen(p) - 1] == '\n') @@ -1687,7 +1770,7 @@ static ssize_t scst_proc_groups_names_write(struct file *file, const char __user *buf, size_t length, loff_t *off) { - int res = length, action; + int res = length, rc = 0, action; char *buffer, *p, *e; struct scst_acg *acg = (struct scst_acg *)PDE(file->f_dentry->d_inode)->data; @@ -1720,8 +1803,8 @@ static ssize_t scst_proc_groups_names_write(struct file *file, } /* - * Usage: echo "add|del NAME" >/proc/scsi_tgt/groups/GROUP/names - * or echo "clear" >/proc/scsi_tgt/groups/GROUP/names + * Usage: echo "add|del NAME" >/proc/scsi_tgt/groups/GROUP_NAME/names + * or echo "clear" >/proc/scsi_tgt/groups/GROUP_NAME/names */ p = buffer; if (p[strlen(p) - 1] == '\n') @@ -1752,33 +1835,43 @@ static ssize_t scst_proc_groups_names_write(struct file *file, break; } + rc = scst_suspend_activity(true); + if (rc != 0) + goto out_free; + if (mutex_lock_interruptible(&scst_mutex) != 0) { res = -EINTR; - goto out_free; + goto out_free_resume; } switch (action) { case SCST_PROC_ACTION_ADD: - scst_acg_add_name(acg, p); + rc = scst_acg_add_name(acg, p); break; case SCST_PROC_ACTION_DEL: - scst_acg_remove_name(acg, p); + rc = scst_acg_remove_name(acg, p); break; case SCST_PROC_ACTION_CLEAR: list_for_each_entry_safe(n, nn, &acg->acn_list, acn_list_entry) { - list_del(&n->acn_list_entry); - kfree(n->name); - kfree(n); + __scst_acg_remove_acn(n); } + scst_check_reassign_sessions(); break; } mutex_unlock(&scst_mutex); +out_free_resume: + scst_resume_activity(); + out_free: free_page((unsigned long)buffer); + out: + if (rc < 0) + res = rc; + TRACE_EXIT_RES(res); return res; } diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index b74652096..8039b510e 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -5326,7 +5326,7 @@ EXPORT_SYMBOL(scst_rx_mgmt_fn); * Written by Jack Handy - jakkhandy@hotmail.com * Taken by Gennadiy Nerubayev from * http://www.codeproject.com/KB/string/wildcmp.aspx. No license attached - * to it, and is posted on a free site; assumed to be free for use. + * to it, and it's posted on a free site; assumed to be free for use. */ static bool wildcmp(const char *wild, const char *string) { @@ -5363,7 +5363,7 @@ static bool wildcmp(const char *wild, const char *string) } /* scst_mutex supposed to be held */ -static struct scst_acg *scst_find_acg(const char *initiator_name) +static struct scst_acg *scst_find_acg_by_name_wild(const char *initiator_name) { struct scst_acg *acg, *res = NULL; struct scst_acn *n; @@ -5407,10 +5407,27 @@ out: return res; } +/* Must be called under scst_mitex */ +struct scst_acg *scst_find_acg(const struct scst_session *sess) +{ + struct scst_acg *acg = NULL; + + TRACE_ENTRY(); + + if (sess->initiator_name) + acg = scst_find_acg_by_name_wild(sess->initiator_name); + if ((acg == NULL) && (sess->tgt->default_group_name != NULL)) + acg = scst_find_acg_by_name(sess->tgt->default_group_name); + if (acg == NULL) + acg = scst_default_acg; + + TRACE_EXIT_HRES((unsigned long)acg); + return acg; +} + static int scst_init_session(struct scst_session *sess) { int res = 0; - struct scst_acg *acg = NULL; struct scst_cmd *cmd; struct scst_mgmt_cmd *mcmd, *tm; int mwake = 0; @@ -5419,19 +5436,12 @@ static int scst_init_session(struct scst_session *sess) mutex_lock(&scst_mutex); - if (sess->initiator_name) - acg = scst_find_acg(sess->initiator_name); - if ((acg == NULL) && (sess->tgt->default_group_name != NULL)) - acg = scst_find_acg_by_name(sess->tgt->default_group_name); - if (acg == NULL) - acg = scst_default_acg; + sess->acg = scst_find_acg(sess); PRINT_INFO("Using security group \"%s\" for initiator \"%s\"", - acg->acg_name, sess->initiator_name); + sess->acg->acg_name, sess->initiator_name); - sess->acg = acg; - TRACE_MGMT_DBG("Assigning session %p to acg %s", sess, acg->acg_name); - list_add_tail(&sess->acg_sess_list_entry, &acg->acg_sess_list); + list_add_tail(&sess->acg_sess_list_entry, &sess->acg->acg_sess_list); TRACE_DBG("Adding sess %p to tgt->sess_list", sess); list_add_tail(&sess->sess_list_entry, &sess->tgt->sess_list);