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:
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:
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,
}
/* 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();
}
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;
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;
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)
{
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;
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);
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;
}
/* 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;
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;
}
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;
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;
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;
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);
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);
#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;
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)
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;
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();
}
/*
- * 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;
} 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;
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",
break;
}
}
+
switch (action) {
case SCST_PROC_ACTION_ADD_GROUP:
if (acg) {
}
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:
/*
* 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')
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;
}
/*
- * 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')
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;
}
* 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)
{
}
/* 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;
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;
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);