scst: add max_tgt_dev_commands sysfs attribute

This per-device attribute allows to control maximum number of SCSI
commands any session to this device can have in flight. It makes
currently hardcoded constant be run time configurable.



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@7073 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2016-12-20 06:14:55 +00:00
parent 42459a6725
commit 2475def30d
8 changed files with 142 additions and 3 deletions

View File

@@ -563,6 +563,9 @@ SCST dev handlers can have the following common entries:
- type - SCSI type of this device
- max_tgt_dev_commands - maximum number of SCSI commands any session to
this device can have in flight.
Attribute "block" allows to temporary block and unblock this device.
"Blocking" means that no new commands for this device will go into the
execution stage, but instead will be suspended just before it. The

View File

@@ -427,6 +427,9 @@ SCST dev handlers can have the following common entries:
- type - SCSI type of this device
- max_tgt_dev_commands - maximum number of SCSI commands any session to
this device can have in flight.
Attribute "block" allows to temporary block and unblock this device.
"Blocking" means that no new commands for this device will go into the
execution stage, but instead will be suspended just before it. The

View File

@@ -1667,6 +1667,13 @@ struct scst_dev_type {
*/
int threads_num;
/*
* Maximum count of uncompleted commands that an initiator could
* queue on any device of this handler by default. Then it will start
* getting TASK QUEUE FULL status.
*/
int max_tgt_dev_commands;
/* Threads pool type. Valid only if threads_num > 0. */
enum scst_dev_type_threads_pool_type threads_pool_type;
@@ -2909,6 +2916,13 @@ struct scst_device {
atomic_t dev_cmd_count;
#endif
/*
* Maximum count of uncompleted commands that an initiator could
* queue on this device. Then it will start getting TASK QUEUE FULL
* status.
*/
int max_tgt_dev_commands;
/*
* How many times device was blocked for new cmds execution.
* Protected by dev_lock.

View File

@@ -13657,7 +13657,56 @@ out:
*/
int scst_get_max_lun_commands(struct scst_session *sess, uint64_t lun)
{
return SCST_MAX_TGT_DEV_COMMANDS;
const int init_res = 0xFFFFFF;
int res = init_res, i;
TRACE_ENTRY();
mutex_lock(&scst_mutex);
if (sess == NULL) {
struct scst_device *dev;
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
if (dev->handler == &scst_null_devtype)
continue;
TRACE_DBG("dev %s, max_tgt_dev_commands %d (res %d)",
dev->virt_name, dev->max_tgt_dev_commands, res);
if (res > dev->max_tgt_dev_commands)
res = dev->max_tgt_dev_commands;
}
goto out_unlock;
}
if (lun != NO_SUCH_LUN) {
struct list_head *head =
&sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(lun)];
struct scst_tgt_dev *tgt_dev;
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
if (tgt_dev->lun == lun) {
res = tgt_dev->dev->max_tgt_dev_commands;
TRACE_DBG("tgt_dev %p, dev %s, max_tgt_dev_commands "
"%d (res %d)", tgt_dev, tgt_dev->dev->virt_name,
tgt_dev->dev->max_tgt_dev_commands, res);
break;
}
}
goto out_unlock;
}
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
struct list_head *head = &sess->sess_tgt_dev_list[i];
struct scst_tgt_dev *tgt_dev;
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
if (res > tgt_dev->dev->max_tgt_dev_commands)
res = tgt_dev->dev->max_tgt_dev_commands;
}
}
out_unlock:
mutex_unlock(&scst_mutex);
TRACE_EXIT_RES(res);
return res;
}
EXPORT_SYMBOL(scst_get_max_lun_commands);

View File

@@ -1367,6 +1367,9 @@ static int scst_dev_handler_check(struct scst_dev_type *dev_handler)
if (dev_handler->dev_done == NULL)
dev_handler->dev_done_atomic = 1;
if (dev_handler->max_tgt_dev_commands == 0)
dev_handler->max_tgt_dev_commands = SCST_MAX_TGT_DEV_COMMANDS;
out:
TRACE_EXIT_RES(res);
return res;
@@ -2154,6 +2157,7 @@ assign:
dev->handler = handler;
dev->threads_num = handler->threads_num;
dev->threads_pool_type = handler->threads_pool_type;
dev->max_tgt_dev_commands = handler->max_tgt_dev_commands;
dev->max_write_same_len = 256 * 1024 * 1024; /* 256 MB */
if (handler->attach) {

View File

@@ -97,7 +97,9 @@ extern unsigned long scst_trace_flag;
/**
** Maximum count of uncompleted commands that an initiator could
** queue on any device. Then it will start getting TASK QUEUE FULL status.
** queue on any device by default, i.e. its dev handler doesn't have
** max_tgt_dev_commands defined. Then it will start getting TASK QUEUE FULL
** status.
**/
#define SCST_MAX_TGT_DEV_COMMANDS 64

View File

@@ -3474,6 +3474,69 @@ static struct kobj_attribute dev_threads_pool_type_attr =
scst_dev_sysfs_threads_pool_type_show,
scst_dev_sysfs_threads_pool_type_store);
static ssize_t scst_dev_sysfs_max_tgt_dev_commands_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
int pos = 0;
struct scst_device *dev;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
pos = sprintf(buf, "%d\n%s", dev->max_tgt_dev_commands,
(dev->max_tgt_dev_commands != dev->handler->max_tgt_dev_commands) ?
SCST_SYSFS_KEY_MARK "\n" : "");
TRACE_EXIT_RES(pos);
return pos;
}
static ssize_t scst_dev_sysfs_max_tgt_dev_commands_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int res;
struct scst_device *dev;
long newtn;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
res = kstrtol(buf, 0, &newtn);
#else
res = strict_strtol(buf, 0, &newtn);
#endif
if (res != 0) {
PRINT_ERROR("strtol() for %s failed: %d ", buf, res);
goto out;
}
if (newtn < 0) {
PRINT_ERROR("Illegal max tgt dev value %ld", newtn);
res = -EINVAL;
goto out;
}
if (dev->max_tgt_dev_commands != newtn) {
PRINT_INFO("Setting new queue depth %ld for device %s (old %d)",
newtn, dev->virt_name, dev->max_tgt_dev_commands);
dev->max_tgt_dev_commands = newtn;
}
out:
if (res == 0)
res = count;
TRACE_EXIT_RES(res);
return res;
}
static struct kobj_attribute dev_max_tgt_dev_commands_attr =
__ATTR(max_tgt_dev_commands, S_IRUGO | S_IWUSR,
scst_dev_sysfs_max_tgt_dev_commands_show,
scst_dev_sysfs_max_tgt_dev_commands_store);
static ssize_t scst_dev_block_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -3604,6 +3667,7 @@ static struct kobj_attribute dev_block_attr =
static struct attribute *scst_dev_attrs[] = {
&dev_type_attr.attr,
&dev_max_tgt_dev_commands_attr.attr,
&dev_block_attr.attr,
NULL,
};

View File

@@ -5073,7 +5073,7 @@ static int __scst_init_cmd(struct scst_cmd *cmd)
cmd->state = SCST_CMD_STATE_PARSE;
cnt = atomic_inc_return(&cmd->tgt_dev->tgt_dev_cmd_count);
if (unlikely(cnt > SCST_MAX_TGT_DEV_COMMANDS)) {
if (unlikely(cnt > cmd->dev->max_tgt_dev_commands)) {
TRACE(TRACE_FLOW_CONTROL,
"Too many pending commands (%d) in "
"session, returning BUSY to initiator \"%s\"",