diff options
| author | Nicholas Bellinger <nab@linux-iscsi.org> | 2017-03-18 18:04:13 -0400 |
|---|---|---|
| committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2017-03-18 19:32:30 -0400 |
| commit | 7d7a743543905a8297dce53b36e793e5307da5d7 (patch) | |
| tree | 56a0de5d2a19e47f7787d0cff4d754f9bc99821f /drivers/target/target_core_user.c | |
| parent | af980e46a26ac8805685bb70c8572dbc47abb126 (diff) | |
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>
Diffstat (limited to 'drivers/target/target_core_user.c')
| -rw-r--r-- | drivers/target/target_core_user.c | 94 |
1 files changed, 68 insertions, 26 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 10cc15f0b1fa..c6874c38a10b 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/stringify.h> | 28 | #include <linux/stringify.h> |
| 29 | #include <linux/bitops.h> | 29 | #include <linux/bitops.h> |
| 30 | #include <linux/highmem.h> | 30 | #include <linux/highmem.h> |
| 31 | #include <linux/configfs.h> | ||
| 31 | #include <net/genetlink.h> | 32 | #include <net/genetlink.h> |
| 32 | #include <scsi/scsi_common.h> | 33 | #include <scsi/scsi_common.h> |
| 33 | #include <scsi/scsi_proto.h> | 34 | #include <scsi/scsi_proto.h> |
| @@ -1046,7 +1047,7 @@ static void tcmu_free_device(struct se_device *dev) | |||
| 1046 | 1047 | ||
| 1047 | enum { | 1048 | enum { |
| 1048 | Opt_dev_config, Opt_dev_size, Opt_hw_block_size, Opt_hw_max_sectors, | 1049 | Opt_dev_config, Opt_dev_size, Opt_hw_block_size, Opt_hw_max_sectors, |
| 1049 | Opt_cmd_time_out, Opt_err, | 1050 | Opt_err, |
| 1050 | }; | 1051 | }; |
| 1051 | 1052 | ||
| 1052 | static match_table_t tokens = { | 1053 | static match_table_t tokens = { |
| @@ -1054,7 +1055,6 @@ static match_table_t tokens = { | |||
| 1054 | {Opt_dev_size, "dev_size=%u"}, | 1055 | {Opt_dev_size, "dev_size=%u"}, |
| 1055 | {Opt_hw_block_size, "hw_block_size=%u"}, | 1056 | {Opt_hw_block_size, "hw_block_size=%u"}, |
| 1056 | {Opt_hw_max_sectors, "hw_max_sectors=%u"}, | 1057 | {Opt_hw_max_sectors, "hw_max_sectors=%u"}, |
| 1057 | {Opt_cmd_time_out, "cmd_time_out=%u"}, | ||
| 1058 | {Opt_err, NULL} | 1058 | {Opt_err, NULL} |
| 1059 | }; | 1059 | }; |
| 1060 | 1060 | ||
| @@ -1121,23 +1121,6 @@ static ssize_t tcmu_set_configfs_dev_params(struct se_device *dev, | |||
| 1121 | if (ret < 0) | 1121 | if (ret < 0) |
| 1122 | pr_err("kstrtoul() failed for dev_size=\n"); | 1122 | pr_err("kstrtoul() failed for dev_size=\n"); |
| 1123 | break; | 1123 | break; |
| 1124 | case Opt_cmd_time_out: | ||
| 1125 | if (tcmu_dev_configured(udev)) { | ||
| 1126 | pr_err("Can not update cmd_time_out after device has been configured.\n"); | ||
| 1127 | ret = -EINVAL; | ||
| 1128 | break; | ||
| 1129 | } | ||
| 1130 | arg_p = match_strdup(&args[0]); | ||
| 1131 | if (!arg_p) { | ||
| 1132 | ret = -ENOMEM; | ||
| 1133 | break; | ||
| 1134 | } | ||
| 1135 | ret = kstrtouint(arg_p, 0, &udev->cmd_time_out); | ||
| 1136 | kfree(arg_p); | ||
| 1137 | if (ret < 0) | ||
| 1138 | pr_err("kstrtouint() failed for cmd_time_out=\n"); | ||
| 1139 | udev->cmd_time_out *= MSEC_PER_SEC; | ||
| 1140 | break; | ||
| 1141 | case Opt_hw_block_size: | 1124 | case Opt_hw_block_size: |
| 1142 | ret = tcmu_set_dev_attrib(&args[0], | 1125 | ret = tcmu_set_dev_attrib(&args[0], |
| 1143 | &(dev->dev_attrib.hw_block_size)); | 1126 | &(dev->dev_attrib.hw_block_size)); |
| @@ -1165,9 +1148,7 @@ static ssize_t tcmu_show_configfs_dev_params(struct se_device *dev, char *b) | |||
| 1165 | 1148 | ||
| 1166 | bl = sprintf(b + bl, "Config: %s ", | 1149 | bl = sprintf(b + bl, "Config: %s ", |
| 1167 | udev->dev_config[0] ? udev->dev_config : "NULL"); | 1150 | udev->dev_config[0] ? udev->dev_config : "NULL"); |
| 1168 | bl += sprintf(b + bl, "Size: %zu ", udev->dev_size); | 1151 | bl += sprintf(b + bl, "Size: %zu\n", udev->dev_size); |
| 1169 | bl += sprintf(b + bl, "Cmd Time Out: %lu\n", | ||
| 1170 | udev->cmd_time_out / MSEC_PER_SEC); | ||
| 1171 | 1152 | ||
| 1172 | return bl; | 1153 | return bl; |
| 1173 | } | 1154 | } |
| @@ -1186,7 +1167,48 @@ tcmu_parse_cdb(struct se_cmd *cmd) | |||
| 1186 | return passthrough_parse_cdb(cmd, tcmu_queue_cmd); | 1167 | return passthrough_parse_cdb(cmd, tcmu_queue_cmd); |
| 1187 | } | 1168 | } |
| 1188 | 1169 | ||
| 1189 | static const struct target_backend_ops tcmu_ops = { | 1170 | static ssize_t tcmu_cmd_time_out_show(struct config_item *item, char *page) |
| 1171 | { | ||
| 1172 | struct se_dev_attrib *da = container_of(to_config_group(item), | ||
| 1173 | struct se_dev_attrib, da_group); | ||
| 1174 | struct tcmu_dev *udev = container_of(da->da_dev, | ||
| 1175 | struct tcmu_dev, se_dev); | ||
| 1176 | |||
| 1177 | return snprintf(page, PAGE_SIZE, "%lu\n", udev->cmd_time_out / MSEC_PER_SEC); | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | static ssize_t tcmu_cmd_time_out_store(struct config_item *item, const char *page, | ||
| 1181 | size_t count) | ||
| 1182 | { | ||
| 1183 | struct se_dev_attrib *da = container_of(to_config_group(item), | ||
| 1184 | struct se_dev_attrib, da_group); | ||
| 1185 | struct tcmu_dev *udev = container_of(da->da_dev, | ||
| 1186 | struct tcmu_dev, se_dev); | ||
| 1187 | u32 val; | ||
| 1188 | int ret; | ||
| 1189 | |||
| 1190 | if (da->da_dev->export_count) { | ||
| 1191 | pr_err("Unable to set tcmu cmd_time_out while exports exist\n"); | ||
| 1192 | return -EINVAL; | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | ret = kstrtou32(page, 0, &val); | ||
| 1196 | if (ret < 0) | ||
| 1197 | return ret; | ||
| 1198 | |||
| 1199 | if (!val) { | ||
| 1200 | pr_err("Illegal value for cmd_time_out\n"); | ||
| 1201 | return -EINVAL; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | udev->cmd_time_out = val * MSEC_PER_SEC; | ||
| 1205 | return count; | ||
| 1206 | } | ||
| 1207 | CONFIGFS_ATTR(tcmu_, cmd_time_out); | ||
| 1208 | |||
| 1209 | static struct configfs_attribute **tcmu_attrs; | ||
| 1210 | |||
| 1211 | static struct target_backend_ops tcmu_ops = { | ||
| 1190 | .name = "user", | 1212 | .name = "user", |
| 1191 | .owner = THIS_MODULE, | 1213 | .owner = THIS_MODULE, |
| 1192 | .transport_flags = TRANSPORT_FLAG_PASSTHROUGH, | 1214 | .transport_flags = TRANSPORT_FLAG_PASSTHROUGH, |
| @@ -1200,12 +1222,12 @@ static const struct target_backend_ops tcmu_ops = { | |||
| 1200 | .show_configfs_dev_params = tcmu_show_configfs_dev_params, | 1222 | .show_configfs_dev_params = tcmu_show_configfs_dev_params, |
| 1201 | .get_device_type = sbc_get_device_type, | 1223 | .get_device_type = sbc_get_device_type, |
| 1202 | .get_blocks = tcmu_get_blocks, | 1224 | .get_blocks = tcmu_get_blocks, |
| 1203 | .tb_dev_attrib_attrs = passthrough_attrib_attrs, | 1225 | .tb_dev_attrib_attrs = NULL, |
| 1204 | }; | 1226 | }; |
| 1205 | 1227 | ||
| 1206 | static int __init tcmu_module_init(void) | 1228 | static int __init tcmu_module_init(void) |
| 1207 | { | 1229 | { |
| 1208 | int ret; | 1230 | int ret, i, len = 0; |
| 1209 | 1231 | ||
| 1210 | BUILD_BUG_ON((sizeof(struct tcmu_cmd_entry) % TCMU_OP_ALIGN_SIZE) != 0); | 1232 | BUILD_BUG_ON((sizeof(struct tcmu_cmd_entry) % TCMU_OP_ALIGN_SIZE) != 0); |
| 1211 | 1233 | ||
| @@ -1227,12 +1249,31 @@ static int __init tcmu_module_init(void) | |||
| 1227 | goto out_unreg_device; | 1249 | goto out_unreg_device; |
| 1228 | } | 1250 | } |
| 1229 | 1251 | ||
| 1252 | for (i = 0; passthrough_attrib_attrs[i] != NULL; i++) { | ||
| 1253 | len += sizeof(struct configfs_attribute *); | ||
| 1254 | } | ||
| 1255 | len += sizeof(struct configfs_attribute *) * 2; | ||
| 1256 | |||
| 1257 | tcmu_attrs = kzalloc(len, GFP_KERNEL); | ||
| 1258 | if (!tcmu_attrs) { | ||
| 1259 | ret = -ENOMEM; | ||
| 1260 | goto out_unreg_genl; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | for (i = 0; passthrough_attrib_attrs[i] != NULL; i++) { | ||
| 1264 | tcmu_attrs[i] = passthrough_attrib_attrs[i]; | ||
| 1265 | } | ||
| 1266 | tcmu_attrs[i] = &tcmu_attr_cmd_time_out; | ||
| 1267 | tcmu_ops.tb_dev_attrib_attrs = tcmu_attrs; | ||
| 1268 | |||
| 1230 | ret = transport_backend_register(&tcmu_ops); | 1269 | ret = transport_backend_register(&tcmu_ops); |
| 1231 | if (ret) | 1270 | if (ret) |
| 1232 | goto out_unreg_genl; | 1271 | goto out_attrs; |
| 1233 | 1272 | ||
| 1234 | return 0; | 1273 | return 0; |
| 1235 | 1274 | ||
| 1275 | out_attrs: | ||
| 1276 | kfree(tcmu_attrs); | ||
| 1236 | out_unreg_genl: | 1277 | out_unreg_genl: |
| 1237 | genl_unregister_family(&tcmu_genl_family); | 1278 | genl_unregister_family(&tcmu_genl_family); |
| 1238 | out_unreg_device: | 1279 | out_unreg_device: |
| @@ -1246,6 +1287,7 @@ out_free_cache: | |||
| 1246 | static void __exit tcmu_module_exit(void) | 1287 | static void __exit tcmu_module_exit(void) |
| 1247 | { | 1288 | { |
| 1248 | target_backend_unregister(&tcmu_ops); | 1289 | target_backend_unregister(&tcmu_ops); |
| 1290 | kfree(tcmu_attrs); | ||
| 1249 | genl_unregister_family(&tcmu_genl_family); | 1291 | genl_unregister_family(&tcmu_genl_family); |
| 1250 | root_device_unregister(tcmu_root_device); | 1292 | root_device_unregister(tcmu_root_device); |
| 1251 | kmem_cache_destroy(tcmu_cmd_cache); | 1293 | kmem_cache_destroy(tcmu_cmd_cache); |
