mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-17 20:56:24 +00:00
Automatic sessions reassignment implemented
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1017 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
+21
-18
@@ -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:
|
||||
|
||||
|
||||
+21
-18
@@ -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:
|
||||
|
||||
|
||||
+211
-59
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+116
-23
@@ -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;
|
||||
}
|
||||
|
||||
+23
-13
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user