Automatic sessions reassignment implemented
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Thu, 6 Aug 2009 11:47:18 +0000 (11:47 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Thu, 6 Aug 2009 11:47:18 +0000 (11:47 +0000)
git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@1017 d57e44dd-8a1f-0410-8b47-8ef2f437770f

scst/README
scst/README_in-tree
scst/src/scst_lib.c
scst/src/scst_main.c
scst/src/scst_priv.h
scst/src/scst_proc.c
scst/src/scst_targ.c

index 71fc8b8..022b537 100644 (file)
@@ -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:
 
index 3c491a9..388c596 100644 (file)
@@ -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:
 
index 91c9e42..09da5ce 100644 (file)
@@ -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,
@@ -563,61 +566,76 @@ static void scst_queue_report_luns_changed_UA(struct scst_session *sess,
 }
 
 /* The activity supposed to be suspended and scst_mutex held */
-void scst_report_luns_changed(struct scst_acg *acg)
+static void scst_report_luns_changed_sess(struct scst_session *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_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;
+       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];
+       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;
-                       }
+               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;
+       }
+       TRACE_MGMT_DBG("Not found a device capable REPORTED "
+               "LUNS DATA CHANGED UA (sess %p)", sess);
+       goto out;
 
-                       aen = scst_alloc_aen(tgt_dev);
-                       if (aen == NULL)
-                               goto queue_ua;
+found:
+       if (tgtt->report_aen != NULL) {
+               struct scst_aen *aen;
+               int rc;
 
-                       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));
+               aen = scst_alloc_aen(tgt_dev);
+               if (aen == NULL)
+                       goto queue_ua;
 
-                       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;
+               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);
-               }
+               scst_free_aen(aen);
+       }
 
 queue_ua:
-               scst_queue_report_luns_changed_UA(sess, 0);
+       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)
+{
+       struct scst_session *sess;
+
+       TRACE_ENTRY();
+
+       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) {
+               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;
index 33fdc1d..c47d59c 100644 (file)
@@ -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;
 
index 1508779..080a760 100644 (file)
@@ -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);
index d825e1e..90aceb9 100644 (file)
@@ -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;
 }
index b746520..8039b51 100644 (file)
@@ -5326,7 +5326,7 @@ EXPORT_SYMBOL(scst_rx_mgmt_fn);
  * Written by Jack Handy - jakkhandy@hotmail.com
  * Taken by Gennadiy Nerubayev <parakie@gmail.com> 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);