Linear search in the LUN translation routines scst_translate_lun()

and scst_mgmt_translate_lun() was changed to a hash-based one, thanks
to Michael G. Byrnes.


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@116 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2007-05-17 15:30:02 +00:00
parent 2edf177f73
commit ad50c22583
5 changed files with 140 additions and 91 deletions

View File

@@ -8,7 +8,7 @@ Summary of changes between versions 0.9.5 and 0.9.6
implemented full support for SCSI task attributes (SIMPLE, ORDERED,
etc.).
- Updated to work on 2.6.20.x
- Updated to work on 2.6.20.x, no update for 2.6.21.x is needed
- Updated to work on 2.6.19.x, thanks to Ming Zhang.
@@ -18,6 +18,10 @@ Summary of changes between versions 0.9.5 and 0.9.6
- /proc implementation moved to seq_*() library, thanks to Ming Zhang.
Target drivers need to be updated accordingly.
- Linear search in the LUN translation routines scst_translate_lun()
and scst_mgmt_translate_lun() was changed to a hash-based one, thanks
to Michael G. Byrnes.
- Building from the Linux kernel tree updated, inside kernel building fixed.
- Support for CPU cache flushing before doing DMA to target devices added.

View File

@@ -559,4 +559,6 @@ Thanks to:
code and Vu Pham <huongvp@yahoo.com> who updated it for the VDISK dev
handler.
* Michael G. Byrnes <michael.byrnes@hp.com> for fixes.
Vladislav Bolkhovitin <vst@vlnb.net>, http://scst.sourceforge.net

View File

@@ -797,6 +797,11 @@ struct scst_tgt
void *tgt_priv;
};
/* Hash size and hash fn for hash based lun translation */
#define TGT_DEV_HASH_SHIFT 5
#define TGT_DEV_HASH_SIZE (1<<TGT_DEV_HASH_SHIFT)
#define HASH_VAL(_val) (_val & (TGT_DEV_HASH_SIZE - 1))
struct scst_session
{
/* Initialization phase, one of SCST_SESS_IPH_* constants */
@@ -814,10 +819,10 @@ struct scst_session
/**************************************************************/
/*
* List of tgt_dev's for this session, protected by scst_mutex
* Hash list of tgt_dev's for this session, protected by scst_mutex
* and suspended activity
*/
struct list_head sess_tgt_dev_list;
struct list_head sess_tgt_dev_list_hash[TGT_DEV_HASH_SIZE];
/* Access control for this session and list entry there */
struct scst_acg *acg;
@@ -1242,7 +1247,7 @@ struct scst_thr_data_hdr
*/
struct scst_tgt_dev
{
/* List entry in sess->sess_tgt_dev_list */
/* List entry in sess->sess_tgt_dev_list_hash */
struct list_head sess_tgt_dev_list_entry;
struct scst_device *dev; /* to save extra dereferences */

View File

@@ -390,6 +390,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
int ini_sg, ini_unchecked_isa_dma, ini_use_clustering;
struct scst_tgt_dev *tgt_dev;
struct scst_device *dev = acg_dev->dev;
struct list_head *sess_tgt_dev_list_head;
int rc, i;
TRACE_ENTRY();
@@ -451,7 +452,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
tgt_dev->p_cmd_lists = &scst_main_cmd_lists;
if (dev->scsi_dev != NULL) {
TRACE(TRACE_DEBUG, "host=%d, channel=%d, id=%d, lun=%d, "
TRACE_DBG("host=%d, channel=%d, id=%d, lun=%d, "
"SCST lun=%Ld", dev->scsi_dev->host->host_no,
dev->scsi_dev->channel, dev->scsi_dev->id,
dev->scsi_dev->lun, (uint64_t)tgt_dev->lun);
@@ -527,8 +528,9 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
if (dev->dev_reserved)
__set_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags);
list_add_tail(&tgt_dev->sess_tgt_dev_list_entry,
&sess->sess_tgt_dev_list);
sess_tgt_dev_list_head =
&sess->sess_tgt_dev_list_hash[HASH_VAL(tgt_dev->lun)];
list_add_tail(&tgt_dev->sess_tgt_dev_list_entry, sess_tgt_dev_list_head);
out:
TRACE_EXIT();
@@ -623,7 +625,6 @@ int scst_sess_alloc_tgt_devs(struct scst_session *sess)
TRACE_ENTRY();
INIT_LIST_HEAD(&sess->sess_tgt_dev_list);
list_for_each_entry(acg_dev, &sess->acg->acg_dev_list,
acg_dev_list_entry)
{
@@ -646,17 +647,21 @@ out_free:
/* scst_mutex supposed to be held and activity suspended */
void scst_sess_free_tgt_devs(struct scst_session *sess)
{
int i;
struct scst_tgt_dev *tgt_dev, *t;
TRACE_ENTRY();
/* The session is going down, no users, so no locks */
list_for_each_entry_safe(tgt_dev, t, &sess->sess_tgt_dev_list,
sess_tgt_dev_list_entry)
{
scst_free_tgt_dev(tgt_dev);
for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
struct list_head *sess_tgt_dev_list_head =
&sess->sess_tgt_dev_list_hash[i];
list_for_each_entry_safe(tgt_dev, t, sess_tgt_dev_list_head,
sess_tgt_dev_list_entry) {
scst_free_tgt_dev(tgt_dev);
}
INIT_LIST_HEAD(sess_tgt_dev_list_head);
}
INIT_LIST_HEAD(&sess->sess_tgt_dev_list);
TRACE_EXIT();
return;
@@ -1065,6 +1070,7 @@ struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask,
const char *initiator_name)
{
struct scst_session *sess;
int i;
int len;
char *nm;
@@ -1086,7 +1092,11 @@ struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask,
sess->init_phase = SCST_SESS_IPH_INITING;
atomic_set(&sess->refcnt, 0);
INIT_LIST_HEAD(&sess->sess_tgt_dev_list);
for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
struct list_head *sess_tgt_dev_list_head =
&sess->sess_tgt_dev_list_hash[i];
INIT_LIST_HEAD(sess_tgt_dev_list_head);
}
spin_lock_init(&sess->sess_list_lock);
INIT_LIST_HEAD(&sess->search_cmd_list);
sess->tgt = tgt;

View File

@@ -1240,6 +1240,7 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
int res = SCST_EXEC_COMPLETED;
int dev_cnt = 0;
int buffer_size;
int i;
struct scst_tgt_dev *tgt_dev = NULL;
uint8_t *buffer;
int offs, overflow = 0;
@@ -1267,35 +1268,38 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
memset(buffer, 0, buffer_size);
offs = 8;
/* sess->sess_tgt_dev_list is protected by suspended activity */
list_for_each_entry(tgt_dev, &cmd->sess->sess_tgt_dev_list,
sess_tgt_dev_list_entry)
{
if (!overflow) {
if (offs >= buffer_size) {
scst_put_buf(cmd, buffer);
buffer_size = scst_get_buf_next(cmd, &buffer);
if (buffer_size > 0) {
memset(buffer, 0, buffer_size);
offs = 0;
} else {
overflow = 1;
goto inc_dev_cnt;
/* sess->sess_tgt_dev_list_hash is protected by suspended activity */
for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
struct list_head *sess_tgt_dev_list_head =
&cmd->sess->sess_tgt_dev_list_hash[i];
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
sess_tgt_dev_list_entry) {
if (!overflow) {
if (offs >= buffer_size) {
scst_put_buf(cmd, buffer);
buffer_size = scst_get_buf_next(cmd, &buffer);
if (buffer_size > 0) {
memset(buffer, 0, buffer_size);
offs = 0;
} else {
overflow = 1;
goto inc_dev_cnt;
}
}
if ((buffer_size - offs) < 8) {
PRINT_ERROR_PR("Buffer allocated for REPORT "
"LUNS command doesn't allow to fit 8 "
"byte entry (buffer_size=%d)",
buffer_size);
goto out_put_hw_err;
}
buffer[offs] = (tgt_dev->lun >> 8) & 0xff;
buffer[offs+1] = tgt_dev->lun & 0xff;
offs += 8;
}
if ((buffer_size - offs) < 8) {
PRINT_ERROR_PR("Buffer allocated for REPORT "
"LUNS command doesn't allow to fit 8 "
"byte entry (buffer_size=%d)",
buffer_size);
goto out_put_hw_err;
}
buffer[offs] = (tgt_dev->lun >> 8) & 0xff;
buffer[offs+1] = tgt_dev->lun & 0xff;
offs += 8;
}
inc_dev_cnt:
dev_cnt++;
dev_cnt++;
}
}
if (!overflow)
scst_put_buf(cmd, buffer);
@@ -2580,12 +2584,13 @@ static int scst_translate_lun(struct scst_cmd *cmd)
__scst_get(1);
if (likely(!test_bit(SCST_FLAG_SUSPENDED, &scst_flags))) {
res = -1;
struct list_head *sess_tgt_dev_list_head =
&cmd->sess->sess_tgt_dev_list_hash[HASH_VAL(cmd->lun)];
TRACE_DBG("Finding tgt_dev for cmd %p (lun %Ld)", cmd,
(uint64_t)cmd->lun);
list_for_each_entry(tgt_dev, &cmd->sess->sess_tgt_dev_list,
sess_tgt_dev_list_entry)
{
(uint64_t)cmd->lun);
res = -1;
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
sess_tgt_dev_list_entry) {
if (tgt_dev->lun == cmd->lun) {
TRACE_DBG("tgt_dev %p found", tgt_dev);
@@ -2988,6 +2993,7 @@ void scst_cmd_tasklet(long p)
static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd)
{
struct scst_tgt_dev *tgt_dev = NULL;
struct list_head *sess_tgt_dev_list_head;
int res = -1;
TRACE_ENTRY();
@@ -3005,9 +3011,10 @@ static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd)
goto out;
}
list_for_each_entry(tgt_dev, &mcmd->sess->sess_tgt_dev_list,
sess_tgt_dev_list_entry)
{
sess_tgt_dev_list_head =
&mcmd->sess->sess_tgt_dev_list_hash[HASH_VAL(mcmd->lun)];
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
sess_tgt_dev_list_entry) {
if (tgt_dev->lun == mcmd->lun) {
TRACE_DBG("tgt_dev %p found", tgt_dev);
mcmd->mcmd_tgt_dev = tgt_dev;
@@ -3514,6 +3521,7 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
int nexus_loss)
{
int res;
int i;
struct scst_session *sess = mcmd->sess;
struct scst_tgt_dev *tgt_dev;
@@ -3528,23 +3536,26 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
}
down(&scst_mutex);
list_for_each_entry(tgt_dev, &sess->sess_tgt_dev_list,
sess_tgt_dev_list_entry)
{
struct scst_device *dev = tgt_dev->dev;
int rc;
spin_lock_bh(&dev->dev_lock);
__scst_block_dev(dev);
spin_unlock_bh(&dev->dev_lock);
__scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1);
if (nexus_loss)
scst_reset_tgt_dev(tgt_dev, 1);
rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0);
if ((rc < 0) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS))
mcmd->status = rc;
for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
struct list_head *sess_tgt_dev_list_head =
&sess->sess_tgt_dev_list_hash[i];
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
sess_tgt_dev_list_entry) {
struct scst_device *dev = tgt_dev->dev;
int rc;
spin_lock_bh(&dev->dev_lock);
__scst_block_dev(dev);
spin_unlock_bh(&dev->dev_lock);
__scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1);
if (nexus_loss)
scst_reset_tgt_dev(tgt_dev, 1);
rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0);
if ((rc < 0) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS))
mcmd->status = rc;
}
}
up(&scst_mutex);
@@ -3559,6 +3570,7 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
int nexus_loss)
{
int res;
int i;
struct scst_tgt *tgt = mcmd->sess->tgt;
struct scst_session *sess;
struct scst_device *dev;
@@ -3583,19 +3595,22 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
}
list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) {
list_for_each_entry(tgt_dev, &sess->sess_tgt_dev_list,
sess_tgt_dev_list_entry)
{
int rc;
__scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1);
if (nexus_loss)
scst_reset_tgt_dev(tgt_dev, 1);
rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0);
if ((rc < 0) &&
(mcmd->status == SCST_MGMT_STATUS_SUCCESS))
mcmd->status = rc;
for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
struct list_head *sess_tgt_dev_list_head =
&sess->sess_tgt_dev_list_hash[i];
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
sess_tgt_dev_list_entry) {
int rc;
__scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1);
if (nexus_loss)
scst_reset_tgt_dev(tgt_dev, 1);
rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0);
if ((rc < 0) &&
(mcmd->status == SCST_MGMT_STATUS_SUCCESS))
mcmd->status = rc;
}
}
}
@@ -3720,14 +3735,22 @@ static void scst_mgmt_cmd_send_done(struct scst_mgmt_cmd *mcmd)
case SCST_NEXUS_LOSS_SESS:
case SCST_ABORT_ALL_TASKS_SESS:
{
int i;
down(&scst_mutex);
list_for_each_entry(tgt_dev, &mcmd->sess->sess_tgt_dev_list,
sess_tgt_dev_list_entry) {
scst_unblock_dev(tgt_dev->dev);
for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
struct list_head *sess_tgt_dev_list_head =
&mcmd->sess->sess_tgt_dev_list_hash[i];
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
sess_tgt_dev_list_entry) {
scst_unblock_dev(tgt_dev->dev);
}
}
up(&scst_mutex);
break;
break;
}
case SCST_CLEAR_ACA:
default:
break;
@@ -4205,6 +4228,7 @@ static void scst_unreg_work_fn(void *p)
static void scst_unreg_work_fn(struct work_struct *work)
#endif
{
int i;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
struct scst_session *sess = (struct scst_session*)p;
#else
@@ -4216,15 +4240,19 @@ static void scst_unreg_work_fn(struct work_struct *work)
TRACE_ENTRY();
down(&scst_mutex);
list_for_each_entry(tgt_dev, &sess->sess_tgt_dev_list,
sess_tgt_dev_list_entry) {
struct scst_dev_type *handler = tgt_dev->dev->handler;
if (handler && handler->pre_unreg_sess) {
TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)",
tgt_dev);
handler->pre_unreg_sess(tgt_dev);
TRACE_DBG("%s", "Dev handler's pre_unreg_sess() "
"returned");
for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
struct list_head *sess_tgt_dev_list_head =
&sess->sess_tgt_dev_list_hash[i];
list_for_each_entry(tgt_dev, sess_tgt_dev_list_head,
sess_tgt_dev_list_entry) {
struct scst_dev_type *handler = tgt_dev->dev->handler;
if (handler && handler->pre_unreg_sess) {
TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)",
tgt_dev);
handler->pre_unreg_sess(tgt_dev);
TRACE_DBG("%s", "Dev handler's pre_unreg_sess() "
"returned");
}
}
}
up(&scst_mutex);