Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d7a7435 authored by Nicholas Bellinger's avatar Nicholas Bellinger
Browse files

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: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent af980e46
Loading
Loading
Loading
Loading
+68 −26
Original line number Diff line number Diff line
@@ -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 @@ static int __init tcmu_module_init(void)
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);