tcmu: Convert cmd_time_out into backend device attribute

Instead of putting cmd_time_out under ../target/core/user_0/foo/control,
which has historically been used by parameters needed for initial
backend device configuration, go ahead and move cmd_time_out into
a backend device attribute.

In order to do this, tcmu_module_init() has been updated to create
a local struct configfs_attribute **tcmu_attrs, that is based upon
the existing passthrough_attrib_attrs along with the new cmd_time_out
attribute.  Once **tcm_attrs has been setup, go ahead and point
it at tcmu_ops->tb_dev_attrib_attrs so it's picked up by target-core.

Also following MNC's previous change, ->cmd_time_out is stored in
milliseconds but exposed via configfs in seconds.  Also, note this
patch restricts the modification of ->cmd_time_out to before +
after the TCMU device has been configured, but not while it has
active fabric exports.

Cc: Mike Christie <mchristi@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
Nicholas Bellinger 2017-03-18 15:04:13 -07:00
parent af980e46a2
commit 7d7a743543

View File

@ -28,6 +28,7 @@
#include <linux/stringify.h>
#include <linux/bitops.h>
#include <linux/highmem.h>
#include <linux/configfs.h>
#include <net/genetlink.h>
#include <scsi/scsi_common.h>
#include <scsi/scsi_proto.h>
@ -1046,7 +1047,7 @@ static void tcmu_free_device(struct se_device *dev)
enum {
Opt_dev_config, Opt_dev_size, Opt_hw_block_size, Opt_hw_max_sectors,
Opt_cmd_time_out, Opt_err,
Opt_err,
};
static match_table_t tokens = {
@ -1054,7 +1055,6 @@ static match_table_t tokens = {
{Opt_dev_size, "dev_size=%u"},
{Opt_hw_block_size, "hw_block_size=%u"},
{Opt_hw_max_sectors, "hw_max_sectors=%u"},
{Opt_cmd_time_out, "cmd_time_out=%u"},
{Opt_err, NULL}
};
@ -1121,23 +1121,6 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev,
if (ret < 0)
pr_err("kstrtoul() failed for dev_size=\n");
break;
case Opt_cmd_time_out:
if (tcmu_dev_configured(udev)) {
pr_err("Can not update cmd_time_out after device has been configured.\n");
ret = -EINVAL;
break;
}
arg_p = match_strdup(&args[0]);
if (!arg_p) {
ret = -ENOMEM;
break;
}
ret = kstrtouint(arg_p, 0, &udev->cmd_time_out);
kfree(arg_p);
if (ret < 0)
pr_err("kstrtouint() failed for cmd_time_out=\n");
udev->cmd_time_out *= MSEC_PER_SEC;
break;
case Opt_hw_block_size:
ret = tcmu_set_dev_attrib(&args[0],
&(dev->dev_attrib.hw_block_size));
@ -1165,9 +1148,7 @@ static ssize_t tcmu_show_configfs_dev_params(struct se_device *dev, char *b)
bl = sprintf(b + bl, "Config: %s ",
udev->dev_config[0] ? udev->dev_config : "NULL");
bl += sprintf(b + bl, "Size: %zu ", udev->dev_size);
bl += sprintf(b + bl, "Cmd Time Out: %lu\n",
udev->cmd_time_out / MSEC_PER_SEC);
bl += sprintf(b + bl, "Size: %zu\n", udev->dev_size);
return bl;
}
@ -1186,7 +1167,48 @@ tcmu_parse_cdb(struct se_cmd *cmd)
return passthrough_parse_cdb(cmd, tcmu_queue_cmd);
}
static const struct target_backend_ops tcmu_ops = {
static ssize_t tcmu_cmd_time_out_show(struct config_item *item, char *page)
{
struct se_dev_attrib *da = container_of(to_config_group(item),
struct se_dev_attrib, da_group);
struct tcmu_dev *udev = container_of(da->da_dev,
struct tcmu_dev, se_dev);
return snprintf(page, PAGE_SIZE, "%lu\n", udev->cmd_time_out / MSEC_PER_SEC);
}
static ssize_t tcmu_cmd_time_out_store(struct config_item *item, const char *page,
size_t count)
{
struct se_dev_attrib *da = container_of(to_config_group(item),
struct se_dev_attrib, da_group);
struct tcmu_dev *udev = container_of(da->da_dev,
struct tcmu_dev, se_dev);
u32 val;
int ret;
if (da->da_dev->export_count) {
pr_err("Unable to set tcmu cmd_time_out while exports exist\n");
return -EINVAL;
}
ret = kstrtou32(page, 0, &val);
if (ret < 0)
return ret;
if (!val) {
pr_err("Illegal value for cmd_time_out\n");
return -EINVAL;
}
udev->cmd_time_out = val * MSEC_PER_SEC;
return count;
}
CONFIGFS_ATTR(tcmu_, cmd_time_out);
static struct configfs_attribute **tcmu_attrs;
static struct target_backend_ops tcmu_ops = {
.name = "user",
.owner = THIS_MODULE,
.transport_flags = TRANSPORT_FLAG_PASSTHROUGH,
@ -1200,12 +1222,12 @@ static const struct target_backend_ops tcmu_ops = {
.show_configfs_dev_params = tcmu_show_configfs_dev_params,
.get_device_type = sbc_get_device_type,
.get_blocks = tcmu_get_blocks,
.tb_dev_attrib_attrs = passthrough_attrib_attrs,
.tb_dev_attrib_attrs = NULL,
};
static int __init tcmu_module_init(void)
{
int ret;
int ret, i, len = 0;
BUILD_BUG_ON((sizeof(struct tcmu_cmd_entry) % TCMU_OP_ALIGN_SIZE) != 0);
@ -1227,12 +1249,31 @@ static int __init tcmu_module_init(void)
goto out_unreg_device;
}
for (i = 0; passthrough_attrib_attrs[i] != NULL; i++) {
len += sizeof(struct configfs_attribute *);
}
len += sizeof(struct configfs_attribute *) * 2;
tcmu_attrs = kzalloc(len, GFP_KERNEL);
if (!tcmu_attrs) {
ret = -ENOMEM;
goto out_unreg_genl;
}
for (i = 0; passthrough_attrib_attrs[i] != NULL; i++) {
tcmu_attrs[i] = passthrough_attrib_attrs[i];
}
tcmu_attrs[i] = &tcmu_attr_cmd_time_out;
tcmu_ops.tb_dev_attrib_attrs = tcmu_attrs;
ret = transport_backend_register(&tcmu_ops);
if (ret)
goto out_unreg_genl;
goto out_attrs;
return 0;
out_attrs:
kfree(tcmu_attrs);
out_unreg_genl:
genl_unregister_family(&tcmu_genl_family);
out_unreg_device:
@ -1246,6 +1287,7 @@ out_free_cache:
static void __exit tcmu_module_exit(void)
{
target_backend_unregister(&tcmu_ops);
kfree(tcmu_attrs);
genl_unregister_family(&tcmu_genl_family);
root_device_unregister(tcmu_root_device);
kmem_cache_destroy(tcmu_cmd_cache);