mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-26 00:10:19 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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\"",
|
||||
|
||||
Reference in New Issue
Block a user